1
1
mirror of https://github.com/n8n-io/n8n.git synced 2024-08-16 16:40:30 +03:00

refactor(editor): Upgrade frontend typing (no-changelog) (#9915)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-07-03 14:19:24 +02:00 committed by GitHub
parent b2f8ea7918
commit 7f8857f69b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 172 additions and 99 deletions

View File

@ -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' });

View File

@ -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'],

View File

@ -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(

View File

@ -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',

View File

@ -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>"
`; `;

View File

@ -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>

View File

@ -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]);

View File

@ -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 } },

View File

@ -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);

View File

@ -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;

View File

@ -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>

View File

@ -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(() => {

View File

@ -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

View File

@ -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}`,
})); }));

View File

@ -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>
`, `,

View File

@ -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();

View File

@ -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();

View File

@ -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',

View File

@ -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,

View File

@ -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 {

View File

@ -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();

View File

@ -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();

View File

@ -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';

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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);
}; };

View File

@ -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),

View File

@ -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<{

View File

@ -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"
> >

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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>

View File

@ -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;

View File

@ -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,
}, },
}, }),
}, },
}); });

View File

@ -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

View File

@ -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'));