diff --git a/cypress/e2e/4-http-request-node.cy.ts b/cypress/e2e/4-http-request-node.cy.ts new file mode 100644 index 0000000000000..51a50fab45c08 --- /dev/null +++ b/cypress/e2e/4-http-request-node.cy.ts @@ -0,0 +1,24 @@ +import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows'; +import { WorkflowPage as WorkflowPageClass } from '../pages/workflow'; + +const WorkflowsPage = new WorkflowsPageClass(); +const WorkflowPage = new WorkflowPageClass(); + +describe('HTTP Request node', () => { + beforeEach(() => { + cy.task('db:reset'); + cy.skipSetup(); + }); + + it('should make a request with a URL and receive a response', () => { + WorkflowsPage.actions.createWorkflowFromCard(); + WorkflowPage.actions.addInitialNodeToCanvas('Manual Trigger'); + WorkflowPage.actions.addNodeToCanvas('HTTP Request'); + WorkflowPage.actions.openNodeNdv('HTTP Request'); + WorkflowPage.actions.typeIntoParameterInput('url', 'https://google.com'); + + WorkflowPage.actions.executeNodeFromNdv(); + + WorkflowPage.getters.ndvOutputPanel().contains(''); + }); +}); diff --git a/cypress/e2e/4-node-creator.cy.ts b/cypress/e2e/4-node-creator.cy.ts new file mode 100644 index 0000000000000..516bfafa6b92d --- /dev/null +++ b/cypress/e2e/4-node-creator.cy.ts @@ -0,0 +1,168 @@ +import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from "../constants"; +import { randFirstName, randLastName } from "@ngneat/falso"; +import { NodeCreator } from '../pages/features/node-creator'; +import { INodeTypeDescription } from '../../packages/workflow'; +import CustomNodeFixture from '../fixtures/Custom_node.json'; + +const username = DEFAULT_USER_EMAIL; +const password = DEFAULT_USER_PASSWORD; +const firstName = randFirstName(); +const lastName = randLastName(); +const nodeCreatorFeature = new NodeCreator(); + +describe('Node Creator', () => { + beforeEach(() => { + cy.intercept('GET', '/types/nodes.json', (req) => { + // Delete caching headers so that we can intercept the request + ['etag', 'if-none-match', 'if-modified-since'].forEach(header => {delete req.headers[header]}); + + + req.continue((res) => { + const nodes = res.body as INodeTypeDescription[]; + + nodes.push(CustomNodeFixture as INodeTypeDescription); + res.send(nodes) + }) + }).as('nodesIntercept') + + cy.signup(username, firstName, lastName, password); + + cy.on('uncaught:exception', (err, runnable) => { + expect(err.message).to.include('Not logged in'); + + return false; + }) + + cy.signin(username, password); + cy.visit(nodeCreatorFeature.url); + }); + + it('should open node creator on trigger tab if no trigger is on canvas', () => { + nodeCreatorFeature.getters.canvasAddButton().click(); + + nodeCreatorFeature.getters.nodeCreator().contains('When should this workflow run?').should('be.visible'); + + nodeCreatorFeature.getters.nodeCreatorTabs().should('not.exist'); + }) + + it('should see all tabs when opening via plus button', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.nodeCreatorTabs().should('exist'); + nodeCreatorFeature.getters.selectedTab().should('have.text', 'Trigger'); + }); + + it('should navigate subcategory', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.getCreatorItem('On App Event').click(); + nodeCreatorFeature.getters.activeSubcategory().should('have.text', 'On App Event'); + // Go back + nodeCreatorFeature.getters.activeSubcategory().find('button').click() + nodeCreatorFeature.getters.activeSubcategory().should('not.exist'); + }) + + it('should search for nodes', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.selectedTab().should('have.text', 'Trigger'); + + nodeCreatorFeature.getters.searchBar().find('input').type('manual'); + nodeCreatorFeature.getters.creatorItem().should('have.length', 1); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('manual123'); + nodeCreatorFeature.getters.creatorItem().should('have.length', 0); + nodeCreatorFeature.getters.noResults() + .should('exist') + .should('contain.text', 'We didn\'t make that... yet'); + + nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image'); + nodeCreatorFeature.getters.creatorItem().should('have.length', 0); + nodeCreatorFeature.getters.noResults() + .should('exist') + .should('contain.text', 'To see results, click here'); + + nodeCreatorFeature.getters.noResults().contains('click here').click(); + nodeCreatorFeature.getters.nodeCreatorTabs().should('exist'); + nodeCreatorFeature.getters.getCreatorItem('Edit Image').should('exist'); + nodeCreatorFeature.getters.selectedTab().should('have.text', 'All'); + nodeCreatorFeature.getters.searchBar().find('button').click(); + nodeCreatorFeature.getters.searchBar().find('input').should('be.empty') + }) + + it('should add manual trigger node', () => { + nodeCreatorFeature.getters.canvasAddButton().click(); + nodeCreatorFeature.getters.getCreatorItem('Manually').click(); + + // TODO: Replace once we have canvas feature utils + cy.get('span').contains('Back to canvas').click(); + + nodeCreatorFeature.getters.canvasAddButton().should('not.be.visible'); + nodeCreatorFeature.getters.nodeCreator().should('not.exist'); + + // TODO: Replace once we have canvas feature utils + cy.get('div').contains("On clicking 'execute'").should('exist'); + }) + + it('check if non-core nodes are rendered all nodes', () => { + cy.wait('@nodesIntercept').then((interception) => { + const nodes = interception.response?.body as INodeTypeDescription[]; + + const categorizedNodes = nodeCreatorFeature.actions.categorizeNodes(nodes); + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.actions.selectTab('All'); + + const categories = Object.keys(categorizedNodes); + categories.forEach((category: string) => { + // Core Nodes contains subcategories which we'll test separately + if(category === 'Core Nodes') return; + + nodeCreatorFeature.actions.toggleCategory(category) + + // Check if all nodes are present + categorizedNodes[category].forEach((node: INodeTypeDescription) => { + if(node.hidden) return; + nodeCreatorFeature.getters.categorizedItems().contains(node.displayName).should('exist'); + }) + + nodeCreatorFeature.actions.toggleCategory(category) + }) + }) + }) + + it.only('should render and select community node', () => { + cy.wait('@nodesIntercept').then(() => { + const customCategory = 'customCategory'; + const customNode = 'E2E Node'; + const customNodeDescription = 'Demonstrate rendering of node'; + + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.actions.selectTab('All'); + + nodeCreatorFeature.getters.getCreatorItem(customCategory).should('exist'); + + nodeCreatorFeature.actions.toggleCategory(customCategory); + nodeCreatorFeature.getters.getCreatorItem(customNode).findChildByTestId('node-item-community-tooltip').should('exist'); + nodeCreatorFeature.getters.getCreatorItem(customNode).contains(customNodeDescription).should('exist'); + nodeCreatorFeature.actions.selectNode(customNode); + + // TODO: Replace once we have canvas feature utils + cy.get('.data-display .node-name').contains(customNode).should('exist'); + + const nodeParameters = () => cy.getByTestId('node-parameters') + const firstParameter = () => nodeParameters().find('.parameter-item').eq(0); + const secondParameter = () => nodeParameters().find('.parameter-item').eq(1); + + // Check correct fields are rendered + nodeParameters().should('exist') + // Test property text input + firstParameter().contains('Test property').should('exist'); + firstParameter().find('input.el-input__inner').should('have.value', 'Some default'); + // Resource select input + secondParameter().find('label').contains('Resource').should('exist'); + secondParameter().find('input.el-input__inner').should('have.value', 'option2'); + secondParameter().find('.el-select').click(); + secondParameter().find('.el-select-dropdown__list').should('exist') + // Check if all options are rendered and select the fourth one + secondParameter().find('.el-select-dropdown__list').children().should('have.length', 4); + secondParameter().find('.el-select-dropdown__list').children().eq(3).contains('option4').should('exist').click(); + secondParameter().find('input.el-input__inner').should('have.value', 'option4'); + }) + }) +}); diff --git a/cypress/fixtures/Custom_node.json b/cypress/fixtures/Custom_node.json new file mode 100644 index 0000000000000..bbd661d261dc4 --- /dev/null +++ b/cypress/fixtures/Custom_node.json @@ -0,0 +1,55 @@ +{ + "properties": [{ + "displayName": "Test property", + "name": "testProp", + "type": "string", + "required": true, + "noDataExpression": false, + "default": "Some default" + }, + { + "displayName": "Resource", + "name": "resource", + "type": "options", + "noDataExpression": true, + "options": [{ + "name": "option1", + "value": "option1" + }, + { + "name": "option2", + "value": "option2" + }, + { + "name": "option3", + "value": "option3" + }, + { + "name": "option4", + "value": "option4" + } + ], + "default": "option2" + } + ], + "displayName": "E2E Node", + "name": "@e2e/n8n-nodes-e2e", + "group": [ + "transform" + ], + "codex": { + "categories": ["CustomCategory"] + }, + "version": 1, + "description": "Demonstrate rendering of node", + "defaults": { + "name": "E2E Node " + }, + "inputs": [ + "main" + ], + "outputs": [ + "main" + ], + "icon": "fa:network-wired" +} diff --git a/cypress/pages/features/node-creator.ts b/cypress/pages/features/node-creator.ts new file mode 100644 index 0000000000000..129277a753168 --- /dev/null +++ b/cypress/pages/features/node-creator.ts @@ -0,0 +1,55 @@ +import { BasePage } from "../base"; +import { INodeTypeDescription } from '../../packages/workflow'; + +export class NodeCreator extends BasePage { + url = '/workflow/new'; + getters = { + plusButton: () => cy.getByTestId('node-creator-plus-button'), + canvasAddButton: () => cy.getByTestId('canvas-add-button'), + searchBar: () => cy.getByTestId('search-bar'), + getCreatorItem: (label: string) => this.getters.creatorItem().contains(label).parents('[data-test-id="item-iterator-item"]'), + getNthCreatorItem: (n: number) => this.getters.creatorItem().eq(n), + nodeCreator: () => cy.getByTestId('node-creator'), + nodeCreatorTabs: () => cy.getByTestId('node-creator-type-selector'), + selectedTab: () => this.getters.nodeCreatorTabs().find('.is-active'), + categorizedItems: () => cy.getByTestId('categorized-items'), + creatorItem: () => cy.getByTestId('item-iterator-item'), + communityNodeTooltip: () => cy.getByTestId('node-item-community-tooltip'), + noResults: () => cy.getByTestId('categorized-no-results'), + activeSubcategory: () => cy.getByTestId('categorized-items-subcategory'), + expandedCategories: () => this.getters.creatorItem().find('>div').filter('.active').invoke('text'), + }; + actions = { + openNodeCreator: () => { + this.getters.plusButton().click(); + this.getters.nodeCreator().should('be.visible') + }, + selectNode: (displayName: string) => { + this.getters.getCreatorItem(displayName).click(); + }, + selectTab: (tab: string) => { + this.getters.nodeCreatorTabs().contains(tab).click(); + }, + toggleCategory: (category: string) => { + this.getters.getCreatorItem(category).click() + }, + categorizeNodes: (nodes: INodeTypeDescription[]) => { + const categorizedNodes = nodes.reduce((acc, node) => { + const categories = (node?.codex?.categories || []).map((category: string) => category.trim()); + + categories.forEach((category: {[key: string]: INodeTypeDescription[]}) => { + // Node creator should show only the latest version of a node + const newerVersion = nodes.find((n: INodeTypeDescription) => n.name === node.nameĀ && (n.version > node.version || Array.isArray(n.version))); + + if (acc[category] === undefined) { + acc[category] = []; + } + acc[category].push(newerVersion ?? node); + }); + return acc; + }, {}) + + return categorizedNodes; + } + }; +} diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index a5d44ddb29f40..fd9a51de97503 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -1,19 +1,52 @@ -import { BasePage } from "./base"; +import { BasePage } from './base'; export class WorkflowPage extends BasePage { url = '/workflow/new'; getters = { - // workflowNameInput: () => cy.getByTestId('workflow-name-input', { timeout: 5000 }).then($el => cy.wrap($el.find('input'))), + workflowNameInput: () => cy.getByTestId('workflow-name-input'), workflowImportInput: () => cy.getByTestId('workflow-import-input'), workflowTags: () => cy.getByTestId('workflow-tags'), - saveButton: () => cy.getByTestId('wf-save-button').children().first(), + saveButton: () => cy.getByTestId('save-button'), + + nodeCreatorSearchBar: () => cy.getByTestId('node-creator-search-bar'), + nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'), + canvasPlusButton: () => cy.getByTestId('canvas-plus-button'), + canvasNodeBox: (nodeDisplayName: string) => { + return cy + .getByTestId('canvas-node-box-title') + .contains(nodeDisplayName) + .parents('[data-test-id="canvas-node-box"]'); + }, + + ndvParameterInput: (parameterName: string) => + cy.getByTestId(`parameter-input-${parameterName}`), + ndvOutputPanel: () => cy.getByTestId('output-panel'), activatorSwitch: () => cy.getByTestId('wf-activate-switch'), workflowMenu: () => cy.getByTestId('workflow-menu'), firstStepButton: () => cy.getByTestId('canvas-add-button'), triggerNodeItem: (name: string) => cy.getByTestId(name), - workflowNameInput: () => cy.getByTestId('workflow-name-input'), }; + actions = { + addInitialNodeToCanvas: (nodeDisplayName: string) => { + this.getters.canvasPlusButton().click(); + this.getters.nodeCreatorSearchBar().type(nodeDisplayName); + this.getters.nodeCreatorSearchBar().type('{enter}{esc}'); + }, + addNodeToCanvas: (nodeDisplayName: string) => { + this.getters.nodeCreatorPlusButton().click(); + this.getters.nodeCreatorSearchBar().type(nodeDisplayName); + this.getters.nodeCreatorSearchBar().type('{enter}{esc}'); + }, + openNodeNdv: (nodeTypeName: string) => { + this.getters.canvasNodeBox(nodeTypeName).dblclick(); + }, + typeIntoParameterInput: (parameterName: string, content: string) => { + this.getters.ndvParameterInput(parameterName).type(content); + }, + executeNodeFromNdv: () => { + cy.contains('Execute node').click(); + }, visit: () => { cy.visit(this.url); cy.get('[data-test-id=node-view-loader]', { timeout: 5000 }).should('not.exist'); diff --git a/cypress/pages/workflows.ts b/cypress/pages/workflows.ts index 7e1ce4600725e..783d45bd22f34 100644 --- a/cypress/pages/workflows.ts +++ b/cypress/pages/workflows.ts @@ -24,4 +24,10 @@ export class WorkflowsPage extends BasePage { // myWorkflows: () => cy.getByTestId('my-workflows'), // allWorkflows: () => cy.getByTestId('all-workflows'), }; + + actions = { + createWorkflowFromCard: () => { + this.getters.newWorkflowButtonCard().click(); + }, + } } diff --git a/packages/cli/src/databases/entities/WorkflowEntity.ts b/packages/cli/src/databases/entities/WorkflowEntity.ts index 4bb7168b82f30..06d47e40d1776 100644 --- a/packages/cli/src/databases/entities/WorkflowEntity.ts +++ b/packages/cli/src/databases/entities/WorkflowEntity.ts @@ -101,6 +101,9 @@ export class WorkflowEntity extends AbstractEntity implements IWorkflowDb { setHash(): void { const { name, active, nodes, connections, settings, staticData, pinData } = this; + // Workflow listing page does not request the `connections` column, so we can use this for `undefined` to avoid generating hashes for all the workflows. + if (!connections) return; + const state = JSON.stringify({ name, active, diff --git a/packages/cli/src/workflows/workflows.controller.ee.ts b/packages/cli/src/workflows/workflows.controller.ee.ts index 292e1092ec082..5403c81445cde 100644 --- a/packages/cli/src/workflows/workflows.controller.ee.ts +++ b/packages/cli/src/workflows/workflows.controller.ee.ts @@ -97,10 +97,9 @@ EEWorkflowController.get( ); } - return EEWorkflows.addCredentialsToWorkflow( - EEWorkflows.addOwnerAndSharings(workflow), - req.user, - ); + EEWorkflows.addOwnerAndSharings(workflow); + await EEWorkflows.addCredentialsToWorkflow(workflow, req.user); + return workflow; }), ); @@ -200,9 +199,12 @@ EEWorkflowController.get( )) as unknown as WorkflowEntity[]; return Promise.all( - workflows.map(async (workflow) => - EEWorkflows.addCredentialsToWorkflow(EEWorkflows.addOwnerAndSharings(workflow), req.user), - ), + workflows.map(async (workflow) => { + EEWorkflows.addOwnerAndSharings(workflow); + await EEWorkflows.addCredentialsToWorkflow(workflow, req.user); + workflow.nodes = []; + return workflow; + }), ); }), ); diff --git a/packages/cli/src/workflows/workflows.services.ee.ts b/packages/cli/src/workflows/workflows.services.ee.ts index 21ce1cfbd1d3c..fdc68db4da33d 100644 --- a/packages/cli/src/workflows/workflows.services.ee.ts +++ b/packages/cli/src/workflows/workflows.services.ee.ts @@ -85,9 +85,7 @@ export class EEWorkflowsService extends WorkflowsService { return transaction.save(newSharedWorkflows); } - static addOwnerAndSharings( - workflow: WorkflowWithSharingsAndCredentials, - ): WorkflowWithSharingsAndCredentials { + static addOwnerAndSharings(workflow: WorkflowWithSharingsAndCredentials): void { workflow.ownedBy = null; workflow.sharedWith = []; workflow.usedCredentials = []; @@ -104,14 +102,12 @@ export class EEWorkflowsService extends WorkflowsService { }); delete workflow.shared; - - return workflow; } static async addCredentialsToWorkflow( workflow: WorkflowWithSharingsAndCredentials, currentUser: User, - ): Promise { + ): Promise { workflow.usedCredentials = []; const userCredentials = await EECredentials.getAll(currentUser); const credentialIdsUsedByWorkflow = new Set(); @@ -155,8 +151,6 @@ export class EEWorkflowsService extends WorkflowsService { }); workflow.usedCredentials?.push(workflowCredential); }); - - return workflow; } static validateCredentialPermissionsToUser( diff --git a/packages/cli/src/workflows/workflows.services.ts b/packages/cli/src/workflows/workflows.services.ts index 9b4df6e17d9ff..27dfc2ed62840 100644 --- a/packages/cli/src/workflows/workflows.services.ts +++ b/packages/cli/src/workflows/workflows.services.ts @@ -140,26 +140,27 @@ export class WorkflowsService { } const fields: Array = ['id', 'name', 'active', 'createdAt', 'updatedAt']; + const relations: string[] = []; - const query: FindManyOptions = { - select: config.get('enterprise.features.sharing') ? [...fields, 'nodes'] : fields, - relations: config.get('enterprise.features.sharing') - ? ['tags', 'shared', 'shared.user', 'shared.role'] - : ['tags'], - }; + if (!config.getEnv('workflowTagsDisabled')) { + relations.push('tags'); + } - if (config.getEnv('workflowTagsDisabled')) { - delete query.relations; + const isSharingEnabled = config.getEnv('enterprise.features.sharing'); + if (isSharingEnabled) { + relations.push('shared', 'shared.user', 'shared.role'); } - const workflows = await Db.collections.Workflow.find( - Object.assign(query, { - where: { - id: In(sharedWorkflowIds), - ...filter, - }, - }), - ); + const query: FindManyOptions = { + select: isSharingEnabled ? [...fields, 'nodes'] : fields, + relations, + where: { + id: In(sharedWorkflowIds), + ...filter, + }, + }; + + const workflows = await Db.collections.Workflow.find(query); return workflows.map((workflow) => { const { id, ...rest } = workflow; diff --git a/packages/design-system/.storybook/main.js b/packages/design-system/.storybook/main.js index f11d0b2cd90f0..3e512d7a6d1ee 100644 --- a/packages/design-system/.storybook/main.js +++ b/packages/design-system/.storybook/main.js @@ -4,7 +4,7 @@ const path = require('path'); * @type {import('@storybook/core-common').StorybookConfig} */ module.exports = { - stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.ts'], + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.{ts,js}'], addons: [ '@storybook/addon-links', '@storybook/addon-essentials', diff --git a/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.ts b/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.ts index 176121f3b1b20..f3f3c03a516e3 100644 --- a/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.ts +++ b/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.ts @@ -1,5 +1,6 @@ import N8nActionToggle from './ActionToggle.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/ActionToggle', @@ -23,7 +24,7 @@ const methods = { onAction: action('action'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nActionToggle, diff --git a/packages/design-system/src/components/N8nAvatar/Avatar.stories.ts b/packages/design-system/src/components/N8nAvatar/Avatar.stories.ts index a1d22012758e2..b690009016421 100644 --- a/packages/design-system/src/components/N8nAvatar/Avatar.stories.ts +++ b/packages/design-system/src/components/N8nAvatar/Avatar.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nAvatar from './Avatar.vue'; export default { @@ -11,7 +12,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nAvatar, diff --git a/packages/design-system/src/components/N8nBadge/Badge.stories.ts b/packages/design-system/src/components/N8nBadge/Badge.stories.ts index 6d0a65a556688..ac4d178eda5da 100644 --- a/packages/design-system/src/components/N8nBadge/Badge.stories.ts +++ b/packages/design-system/src/components/N8nBadge/Badge.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nBadge from './Badge.vue'; export default { @@ -15,7 +16,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nBadge, diff --git a/packages/design-system/src/components/N8nBlockUi/BlockUi.stories.ts b/packages/design-system/src/components/N8nBlockUi/BlockUi.stories.ts index f9a8f8a842382..bbcc750712199 100644 --- a/packages/design-system/src/components/N8nBlockUi/BlockUi.stories.ts +++ b/packages/design-system/src/components/N8nBlockUi/BlockUi.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nBlockUi from './BlockUi.vue'; export default { @@ -5,7 +6,7 @@ export default { component: N8nBlockUi, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nBlockUi, diff --git a/packages/design-system/src/components/N8nFormBox/FormBox.stories.ts b/packages/design-system/src/components/N8nFormBox/FormBox.stories.ts index a073bd5c9147f..44a45077bdcd1 100644 --- a/packages/design-system/src/components/N8nFormBox/FormBox.stories.ts +++ b/packages/design-system/src/components/N8nFormBox/FormBox.stories.ts @@ -1,5 +1,6 @@ import N8nFormBox from './FormBox.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Modules/FormBox', @@ -15,7 +16,7 @@ const methods = { onInput: action('input'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nFormBox, diff --git a/packages/design-system/src/components/N8nFormInput/FormInput.stories.ts b/packages/design-system/src/components/N8nFormInput/FormInput.stories.ts index e524d60b5ffbb..1542944794c1f 100644 --- a/packages/design-system/src/components/N8nFormInput/FormInput.stories.ts +++ b/packages/design-system/src/components/N8nFormInput/FormInput.stories.ts @@ -1,5 +1,6 @@ import N8nFormInput from './FormInput.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Modules/FormInput', @@ -13,7 +14,7 @@ const methods = { onChange: action('change'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nFormInput, diff --git a/packages/design-system/src/components/N8nFormInputs/FormInputs.stories.ts b/packages/design-system/src/components/N8nFormInputs/FormInputs.stories.ts index c073577a4c6c5..09f59bf2b78e0 100644 --- a/packages/design-system/src/components/N8nFormInputs/FormInputs.stories.ts +++ b/packages/design-system/src/components/N8nFormInputs/FormInputs.stories.ts @@ -1,5 +1,6 @@ import N8nFormInputs from './FormInputs.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Modules/FormInputs', @@ -15,7 +16,7 @@ const methods = { onSubmit: action('submit'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nFormInputs, diff --git a/packages/design-system/src/components/N8nHeading/Heading.stories.ts b/packages/design-system/src/components/N8nHeading/Heading.stories.ts index 055a48c37021a..c581f3c7901b8 100644 --- a/packages/design-system/src/components/N8nHeading/Heading.stories.ts +++ b/packages/design-system/src/components/N8nHeading/Heading.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nHeading from './Heading.vue'; export default { @@ -19,7 +20,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nHeading, diff --git a/packages/design-system/src/components/N8nIcon/Icon.stories.ts b/packages/design-system/src/components/N8nIcon/Icon.stories.ts index 6d8c5c2754e22..6d71ea5a00c2d 100644 --- a/packages/design-system/src/components/N8nIcon/Icon.stories.ts +++ b/packages/design-system/src/components/N8nIcon/Icon.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nIcon from './Icon.vue'; export default { @@ -21,7 +22,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nIcon, diff --git a/packages/design-system/src/components/N8nInputLabel/InputLabel.stories.ts b/packages/design-system/src/components/N8nInputLabel/InputLabel.stories.ts index 828d22b1136a1..8eb6539865391 100644 --- a/packages/design-system/src/components/N8nInputLabel/InputLabel.stories.ts +++ b/packages/design-system/src/components/N8nInputLabel/InputLabel.stories.ts @@ -1,5 +1,6 @@ import N8nInputLabel from './InputLabel.vue'; import N8nInput from '../N8nInput'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/Input Label', @@ -10,7 +11,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nInputLabel, diff --git a/packages/design-system/src/components/N8nInputNumber/InputNumber.stories.ts b/packages/design-system/src/components/N8nInputNumber/InputNumber.stories.ts index fae34a57835a8..78ce48e77d9f5 100644 --- a/packages/design-system/src/components/N8nInputNumber/InputNumber.stories.ts +++ b/packages/design-system/src/components/N8nInputNumber/InputNumber.stories.ts @@ -1,5 +1,6 @@ import N8nInputNumber from './InputNumber.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/Input Number', @@ -51,7 +52,7 @@ const methods = { onInput: action('input'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nInputNumber, @@ -71,7 +72,7 @@ Input.args = { controls: false, }; -const ManyTemplate = (args, { argTypes }) => ({ +const ManyTemplate: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nInputNumber, diff --git a/packages/design-system/src/components/N8nLink/Link.stories.ts b/packages/design-system/src/components/N8nLink/Link.stories.ts index 2224190d1f1c0..6daeb93d64ac4 100644 --- a/packages/design-system/src/components/N8nLink/Link.stories.ts +++ b/packages/design-system/src/components/N8nLink/Link.stories.ts @@ -1,5 +1,6 @@ import N8nLink from './Link.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/Link', @@ -18,7 +19,7 @@ const methods = { onClick: action('click'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nLink, diff --git a/packages/design-system/src/components/N8nLoading/Loading.stories.ts b/packages/design-system/src/components/N8nLoading/Loading.stories.ts index 2d08e3a409d1f..86f0bd1461104 100644 --- a/packages/design-system/src/components/N8nLoading/Loading.stories.ts +++ b/packages/design-system/src/components/N8nLoading/Loading.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nLoading from './Loading.vue'; export default { @@ -29,7 +30,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nLoading, diff --git a/packages/design-system/src/components/N8nMarkdown/Markdown.stories.ts b/packages/design-system/src/components/N8nMarkdown/Markdown.stories.ts index 93259c5b34337..b185505b6c21c 100644 --- a/packages/design-system/src/components/N8nMarkdown/Markdown.stories.ts +++ b/packages/design-system/src/components/N8nMarkdown/Markdown.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nMarkdown from './Markdown.vue'; export default { @@ -29,7 +30,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nMarkdown, diff --git a/packages/design-system/src/components/N8nPopover/Popover.stories.ts b/packages/design-system/src/components/N8nPopover/Popover.stories.ts index f2709a2429d73..36bd7179c78f1 100644 --- a/packages/design-system/src/components/N8nPopover/Popover.stories.ts +++ b/packages/design-system/src/components/N8nPopover/Popover.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nPopover from './Popover.vue'; export default { @@ -34,7 +35,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nPopover, diff --git a/packages/design-system/src/components/N8nRadioButtons/RadioButtons.stories.ts b/packages/design-system/src/components/N8nRadioButtons/RadioButtons.stories.ts index 27efc67487b64..c711b0ce85a2b 100644 --- a/packages/design-system/src/components/N8nRadioButtons/RadioButtons.stories.ts +++ b/packages/design-system/src/components/N8nRadioButtons/RadioButtons.stories.ts @@ -1,6 +1,7 @@ import N8nRadioButtons from './RadioButtons.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/RadioButtons', @@ -20,7 +21,7 @@ const methods = { onInput: action('input'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nRadioButtons, diff --git a/packages/design-system/src/components/N8nResizeWrapper/ResizeWrapper.stories.ts b/packages/design-system/src/components/N8nResizeWrapper/ResizeWrapper.stories.js similarity index 100% rename from packages/design-system/src/components/N8nResizeWrapper/ResizeWrapper.stories.ts rename to packages/design-system/src/components/N8nResizeWrapper/ResizeWrapper.stories.js diff --git a/packages/design-system/src/components/N8nSpinner/Spinner.stories.ts b/packages/design-system/src/components/N8nSpinner/Spinner.stories.ts index 7e3acff6152b7..0a51e8ec4ce14 100644 --- a/packages/design-system/src/components/N8nSpinner/Spinner.stories.ts +++ b/packages/design-system/src/components/N8nSpinner/Spinner.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nSpinner from './Spinner.vue'; export default { @@ -19,7 +20,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nSpinner, diff --git a/packages/design-system/src/components/N8nSticky/Sticky.stories.ts b/packages/design-system/src/components/N8nSticky/Sticky.stories.ts index c41339456af9d..d453e5e6a8dfd 100644 --- a/packages/design-system/src/components/N8nSticky/Sticky.stories.ts +++ b/packages/design-system/src/components/N8nSticky/Sticky.stories.ts @@ -1,4 +1,5 @@ import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; import N8nSticky from './Sticky.vue'; export default { @@ -45,7 +46,7 @@ const methods = { onResizeStart: action('resizestart'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nSticky, diff --git a/packages/design-system/src/components/N8nTabs/Tabs.stories.ts b/packages/design-system/src/components/N8nTabs/Tabs.stories.ts index b8cc4f0f2bdd1..2cb7a55e4f128 100644 --- a/packages/design-system/src/components/N8nTabs/Tabs.stories.ts +++ b/packages/design-system/src/components/N8nTabs/Tabs.stories.ts @@ -1,6 +1,7 @@ import N8nTabs from './Tabs.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Atoms/Tabs', @@ -15,7 +16,7 @@ const methods = { onInput: action('input'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nTabs, diff --git a/packages/design-system/src/components/N8nTag/Tag.stories.ts b/packages/design-system/src/components/N8nTag/Tag.stories.ts index 3f3c9490ce4d5..3ce2fe65a8596 100644 --- a/packages/design-system/src/components/N8nTag/Tag.stories.ts +++ b/packages/design-system/src/components/N8nTag/Tag.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nTag from './Tag.vue'; export default { @@ -12,7 +13,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nTag, diff --git a/packages/design-system/src/components/N8nTags/Tags.stories.ts b/packages/design-system/src/components/N8nTags/Tags.stories.ts index 0fa9b3af45328..a4d751cf45bd5 100644 --- a/packages/design-system/src/components/N8nTags/Tags.stories.ts +++ b/packages/design-system/src/components/N8nTags/Tags.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nTags from './Tags.vue'; export default { @@ -6,7 +7,7 @@ export default { argTypes: {}, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nTags, diff --git a/packages/design-system/src/components/N8nText/Text.stories.ts b/packages/design-system/src/components/N8nText/Text.stories.ts index 49d12dd7074cc..dd0313f3b1bc8 100644 --- a/packages/design-system/src/components/N8nText/Text.stories.ts +++ b/packages/design-system/src/components/N8nText/Text.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nText from './Text.vue'; export default { @@ -27,7 +28,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nText, diff --git a/packages/design-system/src/components/N8nTooltip/Tooltip.stories.ts b/packages/design-system/src/components/N8nTooltip/Tooltip.stories.ts index 60c2a410e4d0e..337d50ebb1e36 100644 --- a/packages/design-system/src/components/N8nTooltip/Tooltip.stories.ts +++ b/packages/design-system/src/components/N8nTooltip/Tooltip.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nTooltip from './Tooltip.vue'; export default { @@ -34,7 +35,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nTooltip, diff --git a/packages/design-system/src/components/N8nUserInfo/UserInfo.stories.ts b/packages/design-system/src/components/N8nUserInfo/UserInfo.stories.ts index dd521b000a2e1..29247db8f0a37 100644 --- a/packages/design-system/src/components/N8nUserInfo/UserInfo.stories.ts +++ b/packages/design-system/src/components/N8nUserInfo/UserInfo.stories.ts @@ -1,3 +1,4 @@ +import type { StoryFn } from '@storybook/vue'; import N8nUserInfo from './UserInfo.vue'; export default { @@ -8,7 +9,7 @@ export default { }, }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nUserInfo, diff --git a/packages/design-system/src/components/N8nUserSelect/UserSelect.stories.ts b/packages/design-system/src/components/N8nUserSelect/UserSelect.stories.ts index 875fe2df42fc0..dfc574dcabacd 100644 --- a/packages/design-system/src/components/N8nUserSelect/UserSelect.stories.ts +++ b/packages/design-system/src/components/N8nUserSelect/UserSelect.stories.ts @@ -1,5 +1,6 @@ import N8nUserSelect from './UserSelect.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Modules/UserSelect', @@ -16,7 +17,7 @@ const methods = { onFocus: action('focus'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nUserSelect, diff --git a/packages/design-system/src/components/N8nUsersList/UsersList.stories.ts b/packages/design-system/src/components/N8nUsersList/UsersList.stories.ts index 63a9415275b07..f3e9e65d751b2 100644 --- a/packages/design-system/src/components/N8nUsersList/UsersList.stories.ts +++ b/packages/design-system/src/components/N8nUsersList/UsersList.stories.ts @@ -1,5 +1,6 @@ import N8nUsersList from './UsersList.vue'; import { action } from '@storybook/addon-actions'; +import type { StoryFn } from '@storybook/vue'; export default { title: 'Modules/UsersList', @@ -15,7 +16,7 @@ const methods = { onDelete: action('delete'), }; -const Template = (args, { argTypes }) => ({ +const Template: StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { N8nUsersList, diff --git a/packages/editor-ui/src/components/Node.vue b/packages/editor-ui/src/components/Node.vue index 845c5acca1e2e..a8758ebf3ce76 100644 --- a/packages/editor-ui/src/components/Node.vue +++ b/packages/editor-ui/src/components/Node.vue @@ -1,5 +1,5 @@