first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*storybook.log
storybook-static
@@ -0,0 +1,33 @@
import type { StorybookConfig } from '@storybook/vue3-vite';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value: string): any {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));
}
const config: StorybookConfig = {
stories: [
'../../design-system/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
'../../chat/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
'../../../editor-ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
getAbsolutePath('@chromatic-com/storybook'),
getAbsolutePath('@storybook/addon-vitest'),
getAbsolutePath('@storybook/addon-a11y'),
getAbsolutePath('@storybook/addon-docs'),
getAbsolutePath('@storybook/addon-themes'),
],
framework: getAbsolutePath('@storybook/vue3-vite'),
staticDirs: ['../../design-system/assets'],
core: {
disableTelemetry: true,
},
};
export default config;
@@ -0,0 +1,8 @@
export const allModes = {
dark: {
theme: 'dark',
},
light: {
theme: 'light',
},
} as const;
@@ -0,0 +1,113 @@
import { withThemeByDataAttribute } from '@storybook/addon-themes';
import { setup } from '@storybook/vue3';
import ElementPlus from 'element-plus';
// @ts-expect-error no types
import lang from 'element-plus/dist/locale/en.mjs';
import { createPinia } from 'pinia';
import { createMemoryHistory, createRouter } from 'vue-router';
import { N8nPlugin } from '@n8n/design-system';
import { i18nInstance } from '@n8n/i18n';
import './storybook.scss';
import { allModes } from './modes';
// import '../src/css/tailwind/index.css';
setup((app) => {
const pinia = createPinia();
app.use(pinia);
app.use(i18nInstance);
const router = createRouter({
history: createMemoryHistory(),
routes: [{ path: '/:catchAll(.*)', component: { template: '' } }],
});
app.use(router);
app.use(ElementPlus, {
locale: lang,
});
app.use(N8nPlugin, {});
});
export const parameters = {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
backgrounds: {
default: '--color--background--light-3',
values: [
{
name: '--color--background--shade-2',
value: 'var(--color--background--shade-2)',
},
{
name: '--color--background',
value: 'var(--color--background)',
},
{
name: '--color--background--light-2',
value: 'var(--color--background--light-2)',
},
{
name: '--color--background--light-3',
value: 'var(--color--background--light-3)',
},
],
},
themes: {
default: 'light',
list: [
{
name: 'light',
class: 'theme-light',
color: '#fff',
},
{
name: 'dark',
class: 'theme-dark-beta',
color: '#000',
},
],
},
options: {
storySort: {
order: [
'Docs',
'Styleguide',
['Colors Primitives', 'Colors Tokens', 'Font', 'Spacing', 'Border'],
'Core',
'Assistant',
'Chat',
'Tables',
'Utilities',
'Experimental',
],
},
},
chromatic: {
modes: {
light: allModes['light'],
dark: allModes['dark'],
},
disableSnapshot: false,
},
};
export const decorators = [
withThemeByDataAttribute({
themes: {
light: 'light',
dark: 'dark',
},
defaultTheme: 'light',
attributeName: 'data-theme',
parentSelector: 'body',
}),
];
export const tags = ['autodocs'];
@@ -0,0 +1,22 @@
@use '../../design-system/src/css/base.scss';
@use '../../design-system/src/css/reset.scss';
@use '../../design-system/src/css/index.scss';
.multi-container > * {
margin-bottom: 10px;
}
#storybook-root > div:not([class]) > *,
#storybook-root > * {
margin: var(--spacing--5xs);
}
body {
padding: 0 !important;
}
.story {
padding: 2rem;
display: flex;
gap: 1rem;
}
@@ -0,0 +1,3 @@
# @n8n/storybook
This package contains the Storybook setup for n8n components. Storybook is a tool for developing UI components in isolation, which helps in building, testing, and documenting components effectively.
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>n8n - Storybook</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
@@ -0,0 +1,51 @@
{
"name": "@n8n/storybook",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "storybook dev -p 6006",
"build": "storybook build",
"typecheck": "vue-tsc --noEmit -p tsconfig.app.json"
},
"dependencies": {
"@n8n/chat": "workspace:*",
"@n8n/composables": "workspace:*",
"@n8n/design-system": "workspace:*",
"@n8n/i18n": "workspace:*",
"@n8n/stores": "workspace:*",
"@n8n/utils": "workspace:*",
"pinia": "catalog:frontend",
"vue": "catalog:frontend",
"vue-router": "catalog:frontend",
"vue-tsc": "catalog:frontend"
},
"devDependencies": {
"@chromatic-com/storybook": "catalog:storybook",
"@n8n/typescript-config": "workspace:*",
"@storybook/addon-a11y": "catalog:storybook",
"@storybook/addon-docs": "catalog:storybook",
"@storybook/addon-themes": "catalog:storybook",
"@storybook/addon-vitest": "catalog:storybook",
"@storybook/vue3-vite": "catalog:storybook",
"@types/node": "^24.10.1",
"@vitejs/plugin-vue": "catalog:frontend",
"@vitest/browser-playwright": "^4.0.16",
"@vitest/coverage-v8": "catalog:",
"@vue/tsconfig": "catalog:frontend",
"eslint-plugin-storybook": "catalog:storybook",
"playwright": "catalog:e2e",
"storybook": "catalog:storybook",
"typescript": "catalog:",
"unplugin-icons": "catalog:frontend",
"vite": "catalog:",
"vite-svg-loader": "catalog:frontend",
"vitest": "catalog:",
"vue-tsc": "catalog:frontend"
},
"eslintConfig": {
"extends": [
"plugin:storybook/recommended"
]
}
}
@@ -0,0 +1,34 @@
{
"extends": "@n8n/typescript-config/tsconfig.frontend.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"rootDirs": [".", "../composables/src"],
"outDir": "dist",
"moduleResolution": "bundler",
"types": [
"vite/client",
"vitest/globals",
"unplugin-icons/types/vue",
"../design-system/src/shims-modules.d.ts"
],
"paths": {
"@n8n/chat*": ["../chat/src*"],
"@n8n/design-system*": ["../design-system/src*"],
"@n8n/composables*": ["../composables/src*"],
"@n8n/i18n*": ["../i18n/src*"],
"@n8n/stores*": ["../stores/src*"],
"@n8n/utils*": ["../../../@n8n/utils/src*"],
"@/*": ["../../editor-ui/src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"../chat/src/**/*.stories.ts",
"../design-system/src/**/*.stories.ts",
"../../editor-ui/src/**/*.stories.ts"
]
}
@@ -0,0 +1,4 @@
{
"files": [],
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
}
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
@@ -0,0 +1,17 @@
{
"extends": ["//"],
"tasks": {
"build": {
"extends": false
},
"test": {
"extends": false
},
"test:unit": {
"extends": false
},
"test:integration": {
"extends": false
}
}
}
@@ -0,0 +1,88 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import icons from 'unplugin-icons/vite';
import svgLoader from 'vite-svg-loader';
import path from 'path';
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
icons({
compiler: 'vue3',
autoInstall: true,
}),
svgLoader({
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
cleanupIds: false,
removeViewBox: false,
},
},
},
],
},
}),
],
resolve: {
alias: [
{
find: /^@n8n\/design-system$/,
replacement: path.resolve(__dirname, '../design-system/src/index.ts'),
},
{
find: /^@n8n\/design-system\/(.*)$/,
replacement: path.resolve(__dirname, '../design-system/src/$1'),
},
{
find: /^@n8n\/chat$/,
replacement: path.resolve(__dirname, '../chat/src/index.ts'),
},
{
find: /^@n8n\/chat\/(.*)$/,
replacement: path.resolve(__dirname, '../chat/src/$1'),
},
// Editor-UI aliases
{
find: /^@\/(.*)$/,
replacement: path.resolve(__dirname, '../../editor-ui/src/$1'),
},
{
find: /^@n8n\/i18n$/,
replacement: path.resolve(__dirname, '../i18n/src/index.ts'),
},
{
find: /^@n8n\/i18n\/(.*)$/,
replacement: path.resolve(__dirname, '../i18n/src/$1'),
},
{
find: /^@n8n\/stores$/,
replacement: path.resolve(__dirname, '../stores/src/index.ts'),
},
{
find: /^@n8n\/stores\/(.*)$/,
replacement: path.resolve(__dirname, '../stores/src/$1'),
},
{
find: /^@n8n\/composables$/,
replacement: path.resolve(__dirname, '../composables/src/index.ts'),
},
{
find: /^@n8n\/composables\/(.*)$/,
replacement: path.resolve(__dirname, '../composables/src/$1'),
},
{
find: /^@n8n\/utils$/,
replacement: path.resolve(__dirname, '../../../@n8n/utils/src/index.ts'),
},
{
find: /^@n8n\/utils\/(.*)$/,
replacement: path.resolve(__dirname, '../../../@n8n/utils/src/$1'),
},
],
},
});