mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
refactor(editor): Upgrade frontend typing (no-changelog) (#9915)
This commit is contained in:
parent
b2f8ea7918
commit
7f8857f69b
|
@ -48,9 +48,9 @@ interface ActionBoxProps {
|
||||||
buttonText: string;
|
buttonText: string;
|
||||||
buttonType: ButtonType;
|
buttonType: ButtonType;
|
||||||
description: string;
|
description: string;
|
||||||
calloutText: string;
|
calloutText?: string;
|
||||||
calloutTheme: CalloutTheme;
|
calloutTheme?: CalloutTheme;
|
||||||
calloutIcon: string;
|
calloutIcon?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({ name: 'N8nActionBox' });
|
defineOptions({ name: 'N8nActionBox' });
|
||||||
|
|
|
@ -10,6 +10,7 @@ describe('N8NActionBox', () => {
|
||||||
description:
|
description:
|
||||||
'Long description that you should know something is the way it is because of how it is. ',
|
'Long description that you should know something is the way it is because of how it is. ',
|
||||||
buttonText: 'Do something',
|
buttonText: 'Do something',
|
||||||
|
buttonType: 'primary',
|
||||||
},
|
},
|
||||||
global: {
|
global: {
|
||||||
stubs: ['n8n-heading', 'n8n-text', 'n8n-button', 'n8n-callout'],
|
stubs: ['n8n-heading', 'n8n-text', 'n8n-button', 'n8n-callout'],
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:placement="placement"
|
:placement="placement"
|
||||||
:trigger="trigger"
|
:trigger="trigger"
|
||||||
:popper-class="popperClass"
|
:popper-class="popperClass"
|
||||||
|
:teleported="teleported"
|
||||||
@command="onSelect"
|
@command="onSelect"
|
||||||
@visible-change="onVisibleChange"
|
@visible-change="onVisibleChange"
|
||||||
>
|
>
|
||||||
|
@ -74,6 +75,7 @@ interface ActionDropdownProps {
|
||||||
iconSize?: IconSize;
|
iconSize?: IconSize;
|
||||||
trigger?: (typeof TRIGGER)[number];
|
trigger?: (typeof TRIGGER)[number];
|
||||||
hideArrow?: boolean;
|
hideArrow?: boolean;
|
||||||
|
teleported?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<ActionDropdownProps>(), {
|
const props = withDefaults(defineProps<ActionDropdownProps>(), {
|
||||||
|
@ -83,6 +85,7 @@ const props = withDefaults(defineProps<ActionDropdownProps>(), {
|
||||||
iconSize: 'medium',
|
iconSize: 'medium',
|
||||||
trigger: 'click',
|
trigger: 'click',
|
||||||
hideArrow: false,
|
hideArrow: false,
|
||||||
|
teleported: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const $attrs = useAttrs();
|
const $attrs = useAttrs();
|
||||||
|
@ -98,7 +101,10 @@ const getItemClasses = (item: ActionDropdownItem): Record<string, boolean> => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const $emit = defineEmits(['select', 'visibleChange']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'select', action: string): void;
|
||||||
|
(event: 'visibleChange', open: boolean): void;
|
||||||
|
}>();
|
||||||
const elementDropdown = ref<InstanceType<typeof ElDropdown>>();
|
const elementDropdown = ref<InstanceType<typeof ElDropdown>>();
|
||||||
|
|
||||||
const popperClass = computed(
|
const popperClass = computed(
|
||||||
|
|
|
@ -6,7 +6,6 @@ describe('components', () => {
|
||||||
it('should render default styling correctly', () => {
|
it('should render default styling correctly', () => {
|
||||||
const wrapper = render(N8nActionDropdown, {
|
const wrapper = render(N8nActionDropdown, {
|
||||||
props: {
|
props: {
|
||||||
teleported: false,
|
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
id: 'item1',
|
id: 'item1',
|
||||||
|
|
|
@ -7,7 +7,7 @@ exports[`components > N8nActionDropdown > should render custom styling correctly
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components > N8nActionDropdown > should render default styling correctly 1`] = `
|
exports[`components > N8nActionDropdown > should render default styling correctly 1`] = `
|
||||||
"<div class="action-dropdown-container actionDropdownContainer" teleported="false">
|
"<div class="action-dropdown-container actionDropdownContainer">
|
||||||
<el-dropdown-stub trigger="click" effect="light" placement="bottom" popperoptions="[object Object]" size="" splitbutton="false" hideonclick="true" loop="true" showtimeout="150" hidetimeout="150" tabindex="0" maxheight="" popperclass="shadow" disabled="false" role="menu" teleported="true"></el-dropdown-stub>
|
<el-dropdown-stub trigger="click" effect="light" placement="bottom" popperoptions="[object Object]" size="" splitbutton="false" hideonclick="true" loop="true" showtimeout="150" hidetimeout="150" tabindex="0" maxheight="" popperclass="shadow" disabled="false" role="menu" teleported="true"></el-dropdown-stub>
|
||||||
</div>"
|
</div>"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -68,7 +68,10 @@ withDefaults(defineProps<ActionToggleProps>(), {
|
||||||
iconOrientation: 'vertical',
|
iconOrientation: 'vertical',
|
||||||
});
|
});
|
||||||
|
|
||||||
const $emit = defineEmits(['action', 'visible-change']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'action', value: string): void;
|
||||||
|
(event: 'visible-change', value: boolean): void;
|
||||||
|
}>();
|
||||||
const onCommand = (value: string) => $emit('action', value);
|
const onCommand = (value: string) => $emit('action', value);
|
||||||
const onVisibleChange = (value: boolean) => $emit('visible-change', value);
|
const onVisibleChange = (value: boolean) => $emit('visible-change', value);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -84,7 +84,10 @@ const props = withDefaults(defineProps<DatatableProps>(), {
|
||||||
rowsPerPage: 10,
|
rowsPerPage: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
const $emit = defineEmits(['update:currentPage', 'update:rowsPerPage']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'update:currentPage', value: number): void;
|
||||||
|
(event: 'update:rowsPerPage', value: number): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const rowsPerPageOptions = ref([10, 25, 50, 100]);
|
const rowsPerPageOptions = ref([10, 25, 50, 100]);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { defineComponent, h } from 'vue';
|
import { defineComponent, h } from 'vue';
|
||||||
import type { DatatableRow } from '../../../types';
|
import type { DatatableColumn, DatatableRow } from '../../../types';
|
||||||
import N8nButton from '../../N8nButton';
|
import N8nButton from '../../N8nButton';
|
||||||
|
|
||||||
export const ActionComponent = defineComponent({
|
export const ActionComponent = defineComponent({
|
||||||
|
@ -15,7 +15,7 @@ export const ActionComponent = defineComponent({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const columns = [
|
export const columns: DatatableColumn[] = [
|
||||||
{ id: 'id', path: 'id', label: 'ID' },
|
{ id: 'id', path: 'id', label: 'ID' },
|
||||||
{ id: 'name', path: 'name', label: 'Name' },
|
{ id: 'name', path: 'name', label: 'Name' },
|
||||||
{ id: 'age', path: 'meta.age', label: 'Age' },
|
{ id: 'age', path: 'meta.age', label: 'Age' },
|
||||||
|
@ -23,10 +23,11 @@ export const columns = [
|
||||||
id: 'action',
|
id: 'action',
|
||||||
label: 'Action',
|
label: 'Action',
|
||||||
render: ActionComponent,
|
render: ActionComponent,
|
||||||
|
path: 'action',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const rows = [
|
export const rows: DatatableRow[] = [
|
||||||
{ id: 1, name: 'Richard Hendricks', meta: { age: 29 } },
|
{ id: 1, name: 'Richard Hendricks', meta: { age: 29 } },
|
||||||
{ id: 2, name: 'Bertram Gilfoyle', meta: { age: 44 } },
|
{ id: 2, name: 'Bertram Gilfoyle', meta: { age: 44 } },
|
||||||
{ id: 3, name: 'Dinesh Chugtai', meta: { age: 31 } },
|
{ id: 3, name: 'Dinesh Chugtai', meta: { age: 31 } },
|
||||||
|
|
|
@ -68,7 +68,11 @@ withDefaults(defineProps<FormBoxProps>(), {
|
||||||
});
|
});
|
||||||
|
|
||||||
const formBus = createEventBus();
|
const formBus = createEventBus();
|
||||||
const $emit = defineEmits(['submit', 'update', 'secondaryClick']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'submit', value: { [key: string]: Value }): void;
|
||||||
|
(event: 'update', value: { name: string; value: Value }): void;
|
||||||
|
(event: 'secondaryClick', value: Event): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const onUpdateModelValue = (e: { name: string; value: Value }) => $emit('update', e);
|
const onUpdateModelValue = (e: { name: string; value: Value }) => $emit('update', e);
|
||||||
const onSubmit = (e: { [key: string]: Value }) => $emit('submit', e);
|
const onSubmit = (e: { [key: string]: Value }) => $emit('submit', e);
|
||||||
|
|
|
@ -159,7 +159,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
|
|
||||||
const $emit = defineEmits<{
|
const $emit = defineEmits<{
|
||||||
(event: 'validate', shouldValidate: boolean): void;
|
(event: 'validate', shouldValidate: boolean): void;
|
||||||
(event: 'update:modelValue', value: unknown): void;
|
(event: 'update:modelValue', value: Validatable): void;
|
||||||
(event: 'focus'): void;
|
(event: 'focus'): void;
|
||||||
(event: 'blur'): void;
|
(event: 'blur'): void;
|
||||||
(event: 'enter'): void;
|
(event: 'enter'): void;
|
||||||
|
|
|
@ -26,12 +26,12 @@ const props = withDefaults(defineProps<FormInputsProps>(), {
|
||||||
tagSize: 'small',
|
tagSize: 'small',
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits({
|
const emit = defineEmits<{
|
||||||
update: (_: { name: string; value: Value }) => true,
|
(name: 'update', _: { name: string; value: Value }): boolean;
|
||||||
'update:modelValue': (_: Record<string, Value>) => true,
|
(name: 'update:modelValue', value: Record<string, Value>): boolean;
|
||||||
submit: (_: Record<string, Value>) => true,
|
(name: 'submit', value: Record<string, Value>): boolean;
|
||||||
ready: (_: boolean) => true,
|
(name: 'ready', value: boolean): boolean;
|
||||||
});
|
}>();
|
||||||
|
|
||||||
const showValidationWarnings = ref(false);
|
const showValidationWarnings = ref(false);
|
||||||
const values = reactive<Record<string, Value>>({});
|
const values = reactive<Record<string, Value>>({});
|
||||||
|
@ -123,8 +123,8 @@ onMounted(() => {
|
||||||
:show-validation-warnings="showValidationWarnings"
|
:show-validation-warnings="showValidationWarnings"
|
||||||
:teleported="teleported"
|
:teleported="teleported"
|
||||||
:tag-size="tagSize"
|
:tag-size="tagSize"
|
||||||
@update:model-value="(value) => onUpdateModelValue(input.name, value as Value)"
|
@update:model-value="(value: Value) => onUpdateModelValue(input.name, value)"
|
||||||
@validate="(value) => onValidate(input.name, value)"
|
@validate="(value: boolean) => onValidate(input.name, value)"
|
||||||
@enter="onSubmit"
|
@enter="onSubmit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -68,7 +68,10 @@ const props = withDefaults(defineProps<InfoAccordionProps>(), {
|
||||||
initiallyExpanded: false,
|
initiallyExpanded: false,
|
||||||
eventBus: () => createEventBus(),
|
eventBus: () => createEventBus(),
|
||||||
});
|
});
|
||||||
const $emit = defineEmits(['click:body', 'tooltipClick']);
|
const $emit = defineEmits<{
|
||||||
|
(name: 'click:body', e: MouseEvent): void;
|
||||||
|
(name: 'tooltipClick', item: string, e: MouseEvent): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const expanded = ref(false);
|
const expanded = ref(false);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -155,7 +155,11 @@ const htmlContent = computed(() => {
|
||||||
return safeHtml;
|
return safeHtml;
|
||||||
});
|
});
|
||||||
|
|
||||||
const $emit = defineEmits(['markdown-click', 'update-content']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'markdown-click', link: string, e: MouseEvent): void;
|
||||||
|
(event: 'update-content', content: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const onClick = (event: MouseEvent) => {
|
const onClick = (event: MouseEvent) => {
|
||||||
let clickedLink: HTMLAnchorElement | null = null;
|
let clickedLink: HTMLAnchorElement | null = null;
|
||||||
|
|
||||||
|
@ -169,7 +173,9 @@ const onClick = (event: MouseEvent) => {
|
||||||
clickedLink = parentLink;
|
clickedLink = parentLink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$emit('markdown-click', clickedLink, event);
|
if (clickedLink) {
|
||||||
|
$emit('markdown-click', clickedLink?.href, event);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle checkbox changes
|
// Handle checkbox changes
|
||||||
|
|
|
@ -4,7 +4,7 @@ import N8nRecycleScroller from '../RecycleScroller.vue';
|
||||||
const itemSize = 100;
|
const itemSize = 100;
|
||||||
const itemKey = 'id';
|
const itemKey = 'id';
|
||||||
const items = [...(new Array(100) as number[])].map((_, index) => ({
|
const items = [...(new Array(100) as number[])].map((_, index) => ({
|
||||||
id: index,
|
id: String(index),
|
||||||
name: `Item ${index}`,
|
name: `Item ${index}`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ describe('components', () => {
|
||||||
|
|
||||||
it('should select an option', async () => {
|
it('should select an option', async () => {
|
||||||
const n8nSelectTestComponent = defineComponent({
|
const n8nSelectTestComponent = defineComponent({
|
||||||
|
props: {
|
||||||
|
teleported: Boolean,
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const options = ref(['1', '2', '3']);
|
const options = ref(['1', '2', '3']);
|
||||||
const selected = ref('');
|
const selected = ref('');
|
||||||
|
@ -36,7 +39,7 @@ describe('components', () => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<n8n-select v-model="selected">
|
<n8n-select v-model="selected" :teleported="teleported">
|
||||||
<n8n-option v-for="o in options" :key="o" :value="o" :label="o" />
|
<n8n-option v-for="o in options" :key="o" :value="o" :label="o" />
|
||||||
</n8n-select>
|
</n8n-select>
|
||||||
`,
|
`,
|
||||||
|
|
|
@ -42,7 +42,10 @@ const props = withDefaults(defineProps<TagsProp>(), {
|
||||||
truncateAt: 3,
|
truncateAt: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
const $emit = defineEmits(['expand', 'click:tag']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'expand', value: boolean): void;
|
||||||
|
(event: 'click:tag', tagId: string, e: MouseEvent): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,10 @@ const props = withDefaults(defineProps<UserSelectProps>(), {
|
||||||
currentUserId: '',
|
currentUserId: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const $emit = defineEmits(['blur', 'focus']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'blur'): void;
|
||||||
|
(event: 'focus'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Side',
|
lastName: 'Side',
|
||||||
fullName: 'Sunny Side',
|
fullName: 'Sunny Side',
|
||||||
email: 'hello@n8n.io',
|
email: 'hello@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
signInType: 'email',
|
signInType: 'email',
|
||||||
|
@ -27,7 +26,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Dog',
|
lastName: 'Dog',
|
||||||
fullName: 'Kobi Dog',
|
fullName: 'Kobi Dog',
|
||||||
email: 'kobi@n8n.io',
|
email: 'kobi@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
signInType: 'ldap',
|
signInType: 'ldap',
|
||||||
|
@ -59,7 +57,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Side',
|
lastName: 'Side',
|
||||||
fullName: 'Sunny Side',
|
fullName: 'Sunny Side',
|
||||||
email: 'hello@n8n.io',
|
email: 'hello@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
signInType: 'email',
|
signInType: 'email',
|
||||||
|
@ -71,7 +68,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Dog',
|
lastName: 'Dog',
|
||||||
fullName: 'Kobi Dog',
|
fullName: 'Kobi Dog',
|
||||||
email: 'kobi@n8n.io',
|
email: 'kobi@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
signInType: 'ldap',
|
signInType: 'ldap',
|
||||||
|
@ -83,7 +79,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
fullName: 'John Doe',
|
fullName: 'John Doe',
|
||||||
email: 'john@n8n.io',
|
email: 'john@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
signInType: 'email',
|
signInType: 'email',
|
||||||
|
@ -95,7 +90,6 @@ describe('UserStack', () => {
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
fullName: 'Jane Doe',
|
fullName: 'Jane Doe',
|
||||||
email: 'jane@n8n.io',
|
email: 'jane@n8n.io',
|
||||||
isDefaultUser: false,
|
|
||||||
isPendingUser: false,
|
isPendingUser: false,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
signInType: 'ldap',
|
signInType: 'ldap',
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:actions="getActions(user)"
|
:actions="getActions(user)"
|
||||||
theme="dark"
|
theme="dark"
|
||||||
@action="(action) => onUserAction(user, action)"
|
@action="(action: string) => onUserAction(user, action)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,7 +105,9 @@ const getActions = (user: IUser): UserAction[] => {
|
||||||
return props.actions.filter((action) => (action.guard ?? defaultGuard)(user));
|
return props.actions.filter((action) => (action.guard ?? defaultGuard)(user));
|
||||||
};
|
};
|
||||||
|
|
||||||
const $emit = defineEmits(['action']);
|
const $emit = defineEmits<{
|
||||||
|
(event: 'action', _: { action: string; userId: string }): void;
|
||||||
|
}>();
|
||||||
const onUserAction = (user: IUser, action: string) =>
|
const onUserAction = (user: IUser, action: string) =>
|
||||||
$emit('action', {
|
$emit('action', {
|
||||||
action,
|
action,
|
||||||
|
|
|
@ -4,8 +4,7 @@ export type DatatableRowDataType = string | number | boolean | null | undefined;
|
||||||
|
|
||||||
export interface DatatableRow {
|
export interface DatatableRow {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
|
[key: string]: DatatableRowDataType | Record<string, DatatableRowDataType>;
|
||||||
[key: string]: DatatableRowDataType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatatableColumn {
|
export interface DatatableColumn {
|
||||||
|
|
|
@ -13,11 +13,11 @@ const props = defineProps<{
|
||||||
selectedCredentialId: string | null;
|
selectedCredentialId: string | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const $emit = defineEmits({
|
const $emit = defineEmits<{
|
||||||
credentialSelected: (_credentialId: string) => true,
|
(event: 'credentialSelected', credentialId: string): void;
|
||||||
credentialDeselected: () => true,
|
(event: 'credentialDeselected'): void;
|
||||||
credentialModalOpened: () => true,
|
(event: 'credentialModalOpened'): void;
|
||||||
});
|
}>();
|
||||||
|
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const credentialsStore = useCredentialsStore();
|
const credentialsStore = useCredentialsStore();
|
||||||
|
|
|
@ -12,10 +12,10 @@ const props = defineProps<{
|
||||||
selectedCredentialId: string | null;
|
selectedCredentialId: string | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const $emit = defineEmits({
|
const $emit = defineEmits<{
|
||||||
credentialSelected: (_credentialId: string) => true,
|
(event: 'credentialSelected', credentialId: string): void;
|
||||||
newCredential: () => true,
|
(event: 'newCredential'): void;
|
||||||
});
|
}>();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, defineProps, defineEmits } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import ExpandableInputEdit from '@/components/ExpandableInput/ExpandableInputEdit.vue';
|
import ExpandableInputEdit from '@/components/ExpandableInput/ExpandableInputEdit.vue';
|
||||||
import ExpandableInputPreview from '@/components/ExpandableInput/ExpandableInputPreview.vue';
|
import ExpandableInputPreview from '@/components/ExpandableInput/ExpandableInputPreview.vue';
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
|
|
|
@ -28,9 +28,11 @@ withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits<{
|
||||||
|
(key: 'update:modelValue', tab: MAIN_HEADER_TABS, event: MouseEvent): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
function onUpdateModelValue(tab: string, event: MouseEvent): void {
|
function onUpdateModelValue(tab: MAIN_HEADER_TABS, event: MouseEvent): void {
|
||||||
emit('update:modelValue', tab, event);
|
emit('update:modelValue', tab, event);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
data-test-id="floating-node"
|
data-test-id="floating-node"
|
||||||
:data-node-name="node.name"
|
:data-node-name="node.name"
|
||||||
:data-node-placement="connectionGroup"
|
:data-node-placement="connectionGroup"
|
||||||
@click="$emit('switchSelectedNode', node.name)"
|
@click="emit('switchSelectedNode', node.name)"
|
||||||
>
|
>
|
||||||
<NodeIcon
|
<NodeIcon
|
||||||
:node-type="nodeType"
|
:node-type="nodeType"
|
||||||
|
@ -56,7 +56,9 @@ const props = defineProps<Props>();
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
const workflow = workflowsStore.getCurrentWorkflow();
|
const workflow = workflowsStore.getCurrentWorkflow();
|
||||||
const emit = defineEmits(['switchSelectedNode']);
|
const emit = defineEmits<{
|
||||||
|
(key: 'switchSelectedNode', nodeName: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
interface NodeConfig {
|
interface NodeConfig {
|
||||||
node: INodeUi;
|
node: INodeUi;
|
||||||
|
|
|
@ -139,7 +139,10 @@ const workflowsStore = useWorkflowsStore();
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
const { debounce } = useDebounce();
|
const { debounce } = useDebounce();
|
||||||
const emit = defineEmits(['switchSelectedNode', 'openConnectionNodeCreator']);
|
const emit = defineEmits<{
|
||||||
|
(event: 'switchSelectedNode', nodeName: string): void;
|
||||||
|
(event: 'openConnectionNodeCreator', nodeName: string, connectionType: ConnectionTypes): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
interface NodeConfig {
|
interface NodeConfig {
|
||||||
node: INodeUi;
|
node: INodeUi;
|
||||||
|
|
|
@ -29,9 +29,9 @@ import CategorizedItemsRenderer from '../Renderers/CategorizedItemsRenderer.vue'
|
||||||
import type { IDataObject } from 'n8n-workflow';
|
import type { IDataObject } from 'n8n-workflow';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
|
||||||
const emit = defineEmits({
|
const emit = defineEmits<{
|
||||||
nodeTypeSelected: (_nodeTypes: string[]) => true,
|
(event: 'nodeTypeSelected', _: [actionKey: string, nodeName: string] | [nodeName: string]): void;
|
||||||
});
|
}>();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
|
||||||
const { userActivated } = useUsersStore();
|
const { userActivated } = useUsersStore();
|
||||||
|
|
|
@ -31,9 +31,9 @@ export interface Props {
|
||||||
rootView: 'trigger' | 'action';
|
rootView: 'trigger' | 'action';
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits({
|
const emit = defineEmits<{
|
||||||
nodeTypeSelected: (_nodeTypes: string[]) => true,
|
(event: 'nodeTypeSelected', nodeTypes: string[]): void;
|
||||||
});
|
}>();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
|
|
@ -141,7 +141,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue';
|
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue';
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
import type { IRunData, ConnectionTypes, Workflow } from 'n8n-workflow';
|
import type { IRunData, Workflow } from 'n8n-workflow';
|
||||||
import { jsonParse, NodeHelpers, NodeConnectionType } from 'n8n-workflow';
|
import { jsonParse, NodeHelpers, NodeConnectionType } from 'n8n-workflow';
|
||||||
import type { IUpdateInformation, TargetItem } from '@/Interface';
|
import type { IUpdateInformation, TargetItem } from '@/Interface';
|
||||||
|
|
||||||
|
@ -175,14 +175,18 @@ import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits<{
|
||||||
'saveKeyboardShortcut',
|
(value: 'saveKeyboardShortcut', event: KeyboardEvent): void;
|
||||||
'valueChanged',
|
(value: 'valueChanged', parameterData: IUpdateInformation): void;
|
||||||
'switchSelectedNode',
|
(value: 'switchSelectedNode', nodeTypeName: string): void;
|
||||||
'openConnectionNodeCreator',
|
(
|
||||||
'redrawNode',
|
value: 'openConnectionNodeCreator',
|
||||||
'stopExecution',
|
nodeTypeName: string,
|
||||||
]);
|
connectionType: NodeConnectionType,
|
||||||
|
): void;
|
||||||
|
(value: 'redrawNode', nodeName: string): void;
|
||||||
|
(value: 'stopExecution'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -597,7 +601,7 @@ const onSwitchSelectedNode = (nodeTypeName: string) => {
|
||||||
emit('switchSelectedNode', nodeTypeName);
|
emit('switchSelectedNode', nodeTypeName);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOpenConnectionNodeCreator = (nodeTypeName: string, connectionType: ConnectionTypes) => {
|
const onOpenConnectionNodeCreator = (nodeTypeName: string, connectionType: NodeConnectionType) => {
|
||||||
emit('openConnectionNodeCreator', nodeTypeName, connectionType);
|
emit('openConnectionNodeCreator', nodeTypeName, connectionType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,9 @@ const { getSchemaForExecutionData, filterSchema } = useDataSchema();
|
||||||
const { getNodeInputData } = useNodeHelpers();
|
const { getNodeInputData } = useNodeHelpers();
|
||||||
const { debounce } = useDebounce();
|
const { debounce } = useDebounce();
|
||||||
|
|
||||||
const emit = defineEmits<{ (event: 'clear:search'): void }>();
|
const emit = defineEmits<{
|
||||||
|
(event: 'clear:search'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const nodeSchema = computed(() =>
|
const nodeSchema = computed(() =>
|
||||||
filterSchema(getSchemaForExecutionData(props.data ?? []), props.search),
|
filterSchema(getSchemaForExecutionData(props.data ?? []), props.search),
|
||||||
|
|
|
@ -17,7 +17,12 @@ const { showMessage } = useToast();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
|
|
||||||
const emit = defineEmits(['save', 'cancel', 'edit', 'delete']);
|
const emit = defineEmits<{
|
||||||
|
(event: 'save', data: IResource): void;
|
||||||
|
(event: 'cancel', data: IResource): void;
|
||||||
|
(event: 'edit', data: IResource): void;
|
||||||
|
(event: 'delete', data: IResource): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
<i18n-t
|
<i18n-t
|
||||||
:keypath="
|
:keypath="
|
||||||
uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description
|
uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description
|
||||||
|
.tooltip
|
||||||
"
|
"
|
||||||
tag="span"
|
tag="span"
|
||||||
>
|
>
|
||||||
|
|
|
@ -18,7 +18,9 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
dismissible: true,
|
dismissible: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['close']);
|
const emit = defineEmits<{
|
||||||
|
(event: 'close'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const hasTrailingContent = computed(() => {
|
const hasTrailingContent = computed(() => {
|
||||||
return !!slots.trailingContent;
|
return !!slots.trailingContent;
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { computed } from 'vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
|
||||||
defineEmits(['click']);
|
defineEmits<{
|
||||||
|
(key: 'click', event: MouseEvent): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const locale = useI18n();
|
const locale = useI18n();
|
||||||
|
|
|
@ -25,7 +25,10 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(['closeModal', 'execution:stop', 'update:autoRefresh', 'update:filters']);
|
const emit = defineEmits<{
|
||||||
|
(event: 'update:filters', value: ExecutionFilterType): void;
|
||||||
|
(event: 'execution:stop'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
|
|
@ -9,7 +9,13 @@ import { i18n as locale } from '@/plugins/i18n';
|
||||||
import ExecutionsTime from '@/components/executions/ExecutionsTime.vue';
|
import ExecutionsTime from '@/components/executions/ExecutionsTime.vue';
|
||||||
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
|
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
|
||||||
|
|
||||||
const emit = defineEmits(['stop', 'select', 'retrySaved', 'retryOriginal', 'delete']);
|
type Command = 'retrySaved' | 'retryOriginal' | 'delete';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: 'stop', data: ExecutionSummary): void;
|
||||||
|
(event: 'select', data: ExecutionSummary): void;
|
||||||
|
(event: Command, data: ExecutionSummary): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -141,7 +147,7 @@ function onSelect() {
|
||||||
emit('select', props.execution);
|
emit('select', props.execution);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleActionItemClick(commandData: 'retrySaved' | 'retryOriginal' | 'delete') {
|
async function handleActionItemClick(commandData: Command) {
|
||||||
emit(commandData, props.execution);
|
emit(commandData, props.execution);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -165,6 +165,7 @@ export type IResource = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
key?: string;
|
||||||
updatedAt?: string;
|
updatedAt?: string;
|
||||||
createdAt?: string;
|
createdAt?: string;
|
||||||
homeProject?: ProjectSharingData;
|
homeProject?: ProjectSharingData;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event';
|
||||||
import { useHistoryHelper } from '../useHistoryHelper';
|
import { useHistoryHelper } from '../useHistoryHelper';
|
||||||
import { defineComponent, type PropType } from 'vue';
|
import { defineComponent, type PropType } from 'vue';
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
||||||
|
import { mock } from 'vitest-mock-extended';
|
||||||
|
|
||||||
const undoMock = vi.fn();
|
const undoMock = vi.fn();
|
||||||
const redoMock = vi.fn();
|
const redoMock = vi.fn();
|
||||||
|
@ -58,12 +59,12 @@ describe('useHistoryHelper', () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
render(TestComponent, {
|
render(TestComponent, {
|
||||||
props: {
|
props: {
|
||||||
route: {
|
route: mock<RouteLocationNormalizedLoaded>({
|
||||||
name: MAIN_HEADER_TABS.WORKFLOW,
|
name: MAIN_HEADER_TABS.WORKFLOW,
|
||||||
meta: {
|
meta: {
|
||||||
nodeView: true,
|
nodeView: true,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -76,12 +77,12 @@ describe('useHistoryHelper', () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
render(TestComponent, {
|
render(TestComponent, {
|
||||||
props: {
|
props: {
|
||||||
route: {
|
route: mock<RouteLocationNormalizedLoaded>({
|
||||||
name: MAIN_HEADER_TABS.WORKFLOW,
|
name: MAIN_HEADER_TABS.WORKFLOW,
|
||||||
meta: {
|
meta: {
|
||||||
nodeView: true,
|
nodeView: true,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,11 @@ const i18 = useI18n();
|
||||||
// #region Emit
|
// #region Emit
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const emit = defineEmits(['onFormChanged', 'onBackClick', 'submit']);
|
const emit = defineEmits<{
|
||||||
|
(event: 'onFormChanged', formField: string): void;
|
||||||
|
(event: 'onBackClick', formField: string): void;
|
||||||
|
(event: 'submit', form: { token: string; recoveryCode: string }): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
|
|
@ -118,13 +118,17 @@ function resetNewVariablesList() {
|
||||||
newlyAddedVariableIds.value = [];
|
newlyAddedVariableIds.value = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourceToEnvironmentVariable = (data: IResource): EnvironmentVariable => {
|
const resourceToEnvironmentVariable = (data: IResource): EnvironmentVariable => ({
|
||||||
return {
|
id: data.id,
|
||||||
id: data.id,
|
key: data.name,
|
||||||
key: data.name,
|
value: 'value' in data ? data.value : '',
|
||||||
value: 'value' in data ? data.value : '',
|
});
|
||||||
};
|
|
||||||
};
|
const environmentVariableToResource = (data: EnvironmentVariable): IResource => ({
|
||||||
|
id: data.id,
|
||||||
|
name: data.key,
|
||||||
|
value: 'value' in data ? data.value : '',
|
||||||
|
});
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
if (!isFeatureEnabled.value) return;
|
if (!isFeatureEnabled.value) return;
|
||||||
|
@ -159,35 +163,33 @@ function addTemporaryVariable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveVariable(data: IResource) {
|
async function saveVariable(data: IResource) {
|
||||||
let updatedVariable: EnvironmentVariable;
|
|
||||||
const variable = resourceToEnvironmentVariable(data);
|
const variable = resourceToEnvironmentVariable(data);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof data.id === 'string' && data.id.startsWith(TEMPORARY_VARIABLE_UID_BASE)) {
|
if (typeof variable.id === 'string' && variable.id.startsWith(TEMPORARY_VARIABLE_UID_BASE)) {
|
||||||
const { id, ...rest } = variable;
|
const { id, ...rest } = variable;
|
||||||
updatedVariable = await environmentsStore.createVariable(rest);
|
const updatedVariable = await environmentsStore.createVariable(rest);
|
||||||
allVariables.value.unshift(updatedVariable);
|
allVariables.value.unshift(updatedVariable);
|
||||||
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
||||||
newlyAddedVariableIds.value.unshift(updatedVariable.id);
|
newlyAddedVariableIds.value.unshift(updatedVariable.id);
|
||||||
} else {
|
} else {
|
||||||
updatedVariable = await environmentsStore.updateVariable(variable);
|
const updatedVariable = await environmentsStore.updateVariable(variable);
|
||||||
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
||||||
allVariables.value.push(updatedVariable);
|
allVariables.value.push(updatedVariable);
|
||||||
toggleEditing(updatedVariable);
|
toggleEditing(environmentVariableToResource(updatedVariable));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error, i18n.baseText('variables.errors.save'));
|
showError(error, i18n.baseText('variables.errors.save'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleEditing(data: EnvironmentVariable) {
|
function toggleEditing(data: IResource) {
|
||||||
editMode.value = {
|
editMode.value = {
|
||||||
...editMode.value,
|
...editMode.value,
|
||||||
[data.id]: !editMode.value[data.id],
|
[data.id]: !editMode.value[data.id],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelEditing(data: EnvironmentVariable) {
|
function cancelEditing(data: IResource) {
|
||||||
if (typeof data.id === 'string' && data.id.startsWith(TEMPORARY_VARIABLE_UID_BASE)) {
|
if (typeof data.id === 'string' && data.id.startsWith(TEMPORARY_VARIABLE_UID_BASE)) {
|
||||||
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -195,10 +197,13 @@ function cancelEditing(data: EnvironmentVariable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteVariable(data: EnvironmentVariable) {
|
async function deleteVariable(data: IResource) {
|
||||||
|
const variable = resourceToEnvironmentVariable(data);
|
||||||
try {
|
try {
|
||||||
const confirmed = await message.confirm(
|
const confirmed = await message.confirm(
|
||||||
i18n.baseText('variables.modals.deleteConfirm.message', { interpolate: { name: data.key } }),
|
i18n.baseText('variables.modals.deleteConfirm.message', {
|
||||||
|
interpolate: { name: variable.key },
|
||||||
|
}),
|
||||||
i18n.baseText('variables.modals.deleteConfirm.title'),
|
i18n.baseText('variables.modals.deleteConfirm.title'),
|
||||||
{
|
{
|
||||||
confirmButtonText: i18n.baseText('variables.modals.deleteConfirm.confirmButton'),
|
confirmButtonText: i18n.baseText('variables.modals.deleteConfirm.confirmButton'),
|
||||||
|
@ -210,7 +215,7 @@ async function deleteVariable(data: EnvironmentVariable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await environmentsStore.deleteVariable(data);
|
await environmentsStore.deleteVariable(variable);
|
||||||
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
allVariables.value = allVariables.value.filter((variable) => variable.id !== data.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error, i18n.baseText('variables.errors.delete'));
|
showError(error, i18n.baseText('variables.errors.delete'));
|
||||||
|
|
Loading…
Reference in a new issue