diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index f4237c8adc..c5d939f6b6 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -260,6 +260,57 @@ Cypress.Commands.add('resetDatabase', () => { }); }); +Cypress.Commands.add('clearIndexedDB', (dbName: string, storeName?: string) => { + cy.window().then((win) => { + return new Promise((resolve, reject) => { + if (!win.indexedDB) { + resolve(); + return; + } + + // If storeName is provided, clear specific store; otherwise delete entire database + if (storeName) { + const openRequest = win.indexedDB.open(dbName); + + openRequest.onsuccess = () => { + const db = openRequest.result; + + if (!db.objectStoreNames.contains(storeName)) { + db.close(); + resolve(); + return; + } + + const transaction = db.transaction([storeName], 'readwrite'); + const store = transaction.objectStore(storeName); + const clearRequest = store.clear(); + + clearRequest.onsuccess = () => { + db.close(); + resolve(); + }; + + clearRequest.onerror = () => { + db.close(); + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors + reject(clearRequest.error); + }; + }; + + openRequest.onerror = () => { + resolve(); // Database doesn't exist, nothing to clear + }; + } else { + const deleteRequest = win.indexedDB.deleteDatabase(dbName); + + deleteRequest.onsuccess = () => resolve(); + deleteRequest.onerror = () => resolve(); // Ignore errors if DB doesn't exist + deleteRequest.onblocked = () => resolve(); // Ignore if blocked + } + }); + }); +}); + Cypress.Commands.add('interceptNewTab', () => { cy.window().then((win) => { cy.stub(win, 'open').as('windowOpen'); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index 784e8b6001..0c428851d0 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -90,6 +90,7 @@ declare global { } >; resetDatabase(): void; + clearIndexedDB(dbName: string, storeName?: string): Chainable; setAppDate(targetDate: number | Date): void; interceptNewTab(): Chainable; visitInterceptedTab(): Chainable; diff --git a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.scss b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.scss index 42d0de7341..e83cac774e 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.scss +++ b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.scss @@ -145,6 +145,33 @@ --button-loading-background-color: var(--color-button-secondary-loading-background); } +@mixin n8n-button-highlight { + --button-font-color: var(--color-button-highlight-font); + --button-border-color: var(--color-button-highlight-border); + --button-background-color: var(--color-button-highlight-background); + + --button-hover-font-color: var(--color-button-highlight-hover-active-focus-font); + --button-hover-border-color: var(--color-button-highlight-hover-active-focus-border); + --button-hover-background-color: var(--color-button-highlight-hover-background); + + --button-active-font-color: var(--color-button-highlight-hover-active-focus-font); + --button-active-border-color: var(--color-button-highlight-hover-active-focus-border); + --button-active-background-color: var(--color-button-highlight-active-focus-background); + + --button-focus-font-color: var(--color-button-highlight-hover-active-focus-font); + --button-focus-border-color: var(--color-button-highlight-hover-active-focus-border); + --button-focus-background-color: var(--color-button-highlight-active-focus-background); + --button-focus-outline-color: var(--color-button-highlight-focus-outline); + + --button-disabled-font-color: var(--color-button-highlight-disabled-font); + --button-disabled-border-color: var(--color-button-highlight-disabled-border); + --button-disabled-background-color: var(--color-button-highlight-disabled-background); + + --button-loading-font-color: var(--color-button-highlight-loading-font); + --button-loading-border-color: var(--color-button-highlight-loading-border); + --button-loading-background-color: var(--color-button-highlight-loading-background); +} + @mixin n8n-button-success { --button-font-color: var(--color-button-success-font); --button-border-color: var(--color-success); diff --git a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.stories.ts b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.stories.ts index 922116b225..bea19f4592 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.stories.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.stories.ts @@ -9,7 +9,7 @@ export default { argTypes: { type: { control: 'select', - options: ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger'], + options: ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'highlight'], }, size: { control: { @@ -78,6 +78,7 @@ const AllColorsAndSizesTemplate: StoryFn = (args, { argTypes }) => ({ +

@@ -86,6 +87,7 @@ const AllColorsAndSizesTemplate: StoryFn = (args, { argTypes }) => ({ +

@@ -94,6 +96,7 @@ const AllColorsAndSizesTemplate: StoryFn = (args, { argTypes }) => ({ + `, methods, }); @@ -152,6 +155,12 @@ WithIcon.args = { icon: 'circle-plus', }; +export const Highlight = AllSizesTemplate.bind({}); +Highlight.args = { + type: 'highlight', + label: 'Button', +}; + export const Square = AllColorsAndSizesTemplate.bind({}); Square.args = { label: '48', diff --git a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.test.ts b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.test.ts index 80df349f79..6007f8cb2b 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.test.ts +++ b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.test.ts @@ -64,6 +64,23 @@ describe('components', () => { expect(wrapper.html()).toMatchSnapshot(); }); }); + + describe('type', () => { + it('should render highlight button', () => { + const wrapper = render(N8nButton, { + props: { + type: 'highlight', + }, + slots, + global: { + stubs, + }, + }); + const button = wrapper.container.querySelector('button'); + expect(button?.className).toContain('highlight'); + expect(wrapper.html()).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.vue b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.vue index 73f094aa88..4f6176d16b 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.vue +++ b/packages/frontend/@n8n/design-system/src/components/N8nButton/Button.vue @@ -120,6 +120,10 @@ $loading-overlay-background-color: rgba(255, 255, 255, 0); @include Button.n8n-button-secondary; } +.highlight { + @include Button.n8n-button-highlight; +} + .tertiary { @include Button.n8n-button-secondary; } diff --git a/packages/frontend/@n8n/design-system/src/components/N8nButton/__snapshots__/Button.test.ts.snap b/packages/frontend/@n8n/design-system/src/components/N8nButton/__snapshots__/Button.test.ts.snap index 5c2f13a3d9..1c0b76ffd8 100644 --- a/packages/frontend/@n8n/design-system/src/components/N8nButton/__snapshots__/Button.test.ts.snap +++ b/packages/frontend/@n8n/design-system/src/components/N8nButton/__snapshots__/Button.test.ts.snap @@ -10,6 +10,12 @@ exports[`components > N8nButton > props > square > should render square button 1 " `; +exports[`components > N8nButton > props > type > should render highlight button 1`] = ` +"" +`; + exports[`components > N8nButton > should render correctly 1`] = ` "