feat(editor): Update icons to Lucide icons (#16231)
Co-authored-by: Mutasem Aldmour <mutasem@n8n.io>
@@ -92,7 +92,7 @@ export function getNodeByName(name: string) {
|
||||
export function getNodesWithSpinner() {
|
||||
return cy
|
||||
.getByTestId('canvas-node')
|
||||
.filter((_, el) => Cypress.$(el).find('[data-icon=sync-alt]').length > 0);
|
||||
.filter((_, el) => Cypress.$(el).find('[data-icon=refresh-cw]').length > 0);
|
||||
}
|
||||
|
||||
export function getWaitingNodes() {
|
||||
|
||||
@@ -41,33 +41,33 @@ describe('Execution', () => {
|
||||
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Manual')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-sync-alt'))
|
||||
.within(() => cy.get('svg[data-icon=refresh-cw]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
|
||||
cy.wait(2000);
|
||||
|
||||
// Check canvas nodes after 2nd step (waiting node finished its execution and the http request node is about to start)
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Manual')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
|
||||
successToast().should('be.visible');
|
||||
@@ -101,18 +101,18 @@ describe('Execution', () => {
|
||||
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Manual')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-sync-alt'))
|
||||
.within(() => cy.get('svg[data-icon=refresh-cw]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
|
||||
successToast().should('be.visible');
|
||||
clearNotifications();
|
||||
@@ -123,16 +123,16 @@ describe('Execution', () => {
|
||||
// Check canvas nodes after workflow stopped
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Manual')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-sync-alt').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=refresh-cw]').should('not.exist'));
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
|
||||
successToast().should('be.visible');
|
||||
|
||||
@@ -181,29 +181,29 @@ describe('Execution', () => {
|
||||
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Webhook')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Wait')
|
||||
.within(() => cy.get('.fa-sync-alt'))
|
||||
.within(() => cy.get('svg[data-icon=refresh-cw]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check').should('not.exist'));
|
||||
.within(() => cy.get('svg[data-icon=check]').should('not.exist'));
|
||||
|
||||
cy.wait(2000);
|
||||
|
||||
// Check canvas nodes after 2nd step (waiting node finished its execution and the http request node is about to start)
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Webhook')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Set')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
|
||||
successToast().should('be.visible');
|
||||
@@ -578,11 +578,11 @@ describe('Execution', () => {
|
||||
// Check that the previous nodes executed successfully
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('DebugHelper')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Filter')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
|
||||
errorToast().should('contain', 'Problem in node ‘Telegram‘');
|
||||
@@ -596,7 +596,7 @@ describe('Execution', () => {
|
||||
|
||||
workflowPage.getters
|
||||
.canvasNodeByName('Edit Fields')
|
||||
.within(() => cy.get('.fa-check'))
|
||||
.within(() => cy.get('svg[data-icon=check]'))
|
||||
.should('exist');
|
||||
|
||||
workflowPage.getters.canvasNodeByName('Edit Fields').dblclick();
|
||||
|
||||
@@ -342,14 +342,14 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||
});
|
||||
|
||||
it('should set and update project icon', () => {
|
||||
const DEFAULT_ICON = 'fa-layer-group';
|
||||
const DEFAULT_ICON = 'layers';
|
||||
const NEW_PROJECT_NAME = 'Test Project';
|
||||
|
||||
cy.signinAsAdmin();
|
||||
cy.visit(workflowsPage.url);
|
||||
projects.createProject(NEW_PROJECT_NAME);
|
||||
// New project should have default icon
|
||||
projects.getIconPickerButton().find('svg').should('have.class', DEFAULT_ICON);
|
||||
projects.getIconPickerButton().find('svg').should('have.attr', 'data-icon', DEFAULT_ICON);
|
||||
// Choose another icon
|
||||
projects.getIconPickerButton().click();
|
||||
projects.getIconPickerTab('Emojis').click();
|
||||
|
||||
@@ -36,7 +36,7 @@ watch(
|
||||
class="empty-container"
|
||||
>
|
||||
<div class="empty" data-test-id="chat-messages-empty">
|
||||
<N8nIcon icon="comment" size="large" class="emptyIcon" />
|
||||
<N8nIcon icon="message-circle" size="large" class="emptyIcon" />
|
||||
<N8nText tag="p" size="medium" color="text-base">
|
||||
{{ emptyText }}
|
||||
</N8nText>
|
||||
|
||||
7
packages/frontend/@n8n/chat/src/env.d.ts
vendored
@@ -15,3 +15,10 @@ declare module 'markdown-it-task-lists' {
|
||||
|
||||
export = markdownItTaskLists;
|
||||
}
|
||||
|
||||
declare module '~icons/*' {
|
||||
import type { FunctionalComponent, SVGAttributes } from 'vue';
|
||||
|
||||
const component: FunctionalComponent<SVGAttributes>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"postcss": "^8.4.38",
|
||||
"sass": "^1.64.1",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"unplugin-icons": "^0.19.0",
|
||||
"unplugin-vue-components": "^0.27.2",
|
||||
"unplugin-icons": "catalog:frontend",
|
||||
"unplugin-vue-components": "catalog:frontend",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:",
|
||||
|
||||
@@ -294,7 +294,7 @@ function onSubmitFeedback(feedback: string) {
|
||||
/>
|
||||
<N8nIconButton
|
||||
:class="{ [$style.sendButton]: true }"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
:text="true"
|
||||
size="large"
|
||||
data-test-id="send-message-button"
|
||||
|
||||
@@ -69,7 +69,6 @@ exports[`AskAssistantChat > does not render retry button if no error is present
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -181,7 +180,7 @@ exports[`AskAssistantChat > does not render retry button if no error is present
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -263,7 +262,6 @@ exports[`AskAssistantChat > renders chat with messages correctly 1`] = `
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -614,7 +612,7 @@ exports[`AskAssistantChat > renders chat with messages correctly 1`] = `
|
||||
data-test-id="replace-code-button"
|
||||
disabled="false"
|
||||
element="button"
|
||||
icon="refresh"
|
||||
icon="refresh-cw"
|
||||
label=""
|
||||
loading="false"
|
||||
outline="false"
|
||||
@@ -918,7 +916,7 @@ Testing more code
|
||||
data-test-id="replace-code-button"
|
||||
disabled="false"
|
||||
element="button"
|
||||
icon="refresh"
|
||||
icon="refresh-cw"
|
||||
label=""
|
||||
loading="false"
|
||||
outline="false"
|
||||
@@ -999,7 +997,7 @@ Testing more code
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -1081,7 +1079,6 @@ exports[`AskAssistantChat > renders default placeholder chat correctly 1`] = `
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -1186,7 +1183,7 @@ exports[`AskAssistantChat > renders default placeholder chat correctly 1`] = `
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -1268,7 +1265,6 @@ exports[`AskAssistantChat > renders end of session chat correctly 1`] = `
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -1457,7 +1453,7 @@ exports[`AskAssistantChat > renders end of session chat correctly 1`] = `
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -1539,7 +1535,6 @@ exports[`AskAssistantChat > renders error message correctly with retry button 1`
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -1615,7 +1610,7 @@ exports[`AskAssistantChat > renders error message correctly with retry button 1`
|
||||
>
|
||||
<n8n-icon-stub
|
||||
class="errorIcon"
|
||||
icon="exclamation-triangle"
|
||||
icon="triangle-alert"
|
||||
size="small"
|
||||
spin="false"
|
||||
/>
|
||||
@@ -1663,7 +1658,7 @@ exports[`AskAssistantChat > renders error message correctly with retry button 1`
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -1745,7 +1740,6 @@ exports[`AskAssistantChat > renders message with code snippet 1`] = `
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -1927,7 +1921,7 @@ catch(e) {
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
@@ -2009,7 +2003,6 @@ exports[`AskAssistantChat > renders streaming chat correctly 1`] = `
|
||||
<n8n-icon-stub
|
||||
color="text-base"
|
||||
icon="arrow-right"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
</div>
|
||||
@@ -2124,7 +2117,7 @@ exports[`AskAssistantChat > renders streaming chat correctly 1`] = `
|
||||
class="sendButton"
|
||||
data-test-id="send-message-button"
|
||||
disabled="true"
|
||||
icon="paper-plane"
|
||||
icon="send"
|
||||
loading="false"
|
||||
outline="false"
|
||||
size="large"
|
||||
|
||||
@@ -22,7 +22,7 @@ const { t } = useI18n();
|
||||
<BaseMessage :message="message" :is-first-of-role="isFirstOfRole" :user="user">
|
||||
<div :class="$style.error" data-test-id="chat-message-system">
|
||||
<p :class="$style.errorText">
|
||||
<N8nIcon icon="exclamation-triangle" size="small" :class="$style.errorIcon" />
|
||||
<N8nIcon icon="triangle-alert" size="small" :class="$style.errorIcon" />
|
||||
{{ message.content }}
|
||||
</p>
|
||||
<N8nButton
|
||||
|
||||
@@ -109,14 +109,14 @@ const diffs = computed(() => {
|
||||
</div>
|
||||
<div :class="$style.actions">
|
||||
<div v-if="error">
|
||||
<N8nIcon icon="exclamation-triangle" color="danger" class="mr-5xs" />
|
||||
<N8nIcon icon="triangle-alert" color="danger" class="mr-5xs" />
|
||||
<span :class="$style.infoText">{{ t('codeDiff.couldNotReplace') }}</span>
|
||||
</div>
|
||||
<div v-else-if="replaced">
|
||||
<N8nButton
|
||||
type="secondary"
|
||||
size="mini"
|
||||
icon="undo"
|
||||
icon="undo-2"
|
||||
data-test-id="undo-replace-button"
|
||||
@click="() => emit('undo')"
|
||||
>
|
||||
@@ -131,7 +131,7 @@ const diffs = computed(() => {
|
||||
v-else
|
||||
:type="replacing ? 'secondary' : 'primary'"
|
||||
size="mini"
|
||||
icon="refresh"
|
||||
icon="refresh-cw"
|
||||
data-test-id="replace-code-button"
|
||||
:disabled="!content || streaming"
|
||||
:loading="replacing"
|
||||
|
||||
@@ -276,7 +276,7 @@ exports[`CodeDiff > renders code diff correctly 1`] = `
|
||||
data-test-id="replace-code-button"
|
||||
disabled="false"
|
||||
element="button"
|
||||
icon="refresh"
|
||||
icon="refresh-cw"
|
||||
label=""
|
||||
loading="false"
|
||||
outline="false"
|
||||
@@ -543,8 +543,7 @@ exports[`CodeDiff > renders error state correctly 1`] = `
|
||||
<n8n-icon-stub
|
||||
class="mr-5xs"
|
||||
color="danger"
|
||||
icon="exclamation-triangle"
|
||||
size="medium"
|
||||
icon="triangle-alert"
|
||||
spin="false"
|
||||
/>
|
||||
<span
|
||||
@@ -814,7 +813,7 @@ exports[`CodeDiff > renders replaced code diff correctly 1`] = `
|
||||
data-test-id="undo-replace-button"
|
||||
disabled="false"
|
||||
element="button"
|
||||
icon="undo"
|
||||
icon="undo-2"
|
||||
label=""
|
||||
loading="false"
|
||||
outline="false"
|
||||
@@ -827,7 +826,6 @@ exports[`CodeDiff > renders replaced code diff correctly 1`] = `
|
||||
class="ml-xs"
|
||||
color="success"
|
||||
icon="check"
|
||||
size="medium"
|
||||
spin="false"
|
||||
/>
|
||||
<span
|
||||
@@ -1097,7 +1095,7 @@ exports[`CodeDiff > renders replacing code diff correctly 1`] = `
|
||||
data-test-id="replace-code-button"
|
||||
disabled="false"
|
||||
element="button"
|
||||
icon="refresh"
|
||||
icon="refresh-cw"
|
||||
label=""
|
||||
loading="true"
|
||||
outline="false"
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { ButtonType } from '@n8n/design-system/types/button';
|
||||
import N8nButton from '../N8nButton';
|
||||
import N8nCallout, { type CalloutTheme } from '../N8nCallout';
|
||||
import N8nHeading from '../N8nHeading';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
import N8nText from '../N8nText';
|
||||
|
||||
interface ActionBoxProps {
|
||||
@@ -13,11 +14,11 @@ interface ActionBoxProps {
|
||||
buttonText?: string;
|
||||
buttonType?: ButtonType;
|
||||
buttonDisabled?: boolean;
|
||||
buttonIcon?: string;
|
||||
buttonIcon?: IconName;
|
||||
description?: string;
|
||||
calloutText?: string;
|
||||
calloutTheme?: CalloutTheme;
|
||||
calloutIcon?: string;
|
||||
calloutIcon?: IconName;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'N8nActionBox' });
|
||||
|
||||
@@ -51,7 +51,7 @@ defaultActionDropdown.args = {
|
||||
|
||||
export const customStyling = template.bind({});
|
||||
customStyling.args = {
|
||||
activatorIcon: 'bars',
|
||||
activatorIcon: 'menu',
|
||||
items: [
|
||||
{
|
||||
id: 'item1',
|
||||
@@ -67,7 +67,7 @@ customStyling.args = {
|
||||
{
|
||||
id: 'item3',
|
||||
label: 'Action 3',
|
||||
icon: 'heart',
|
||||
icon: 'home',
|
||||
divided: true,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('components', () => {
|
||||
{
|
||||
id: 'item3',
|
||||
label: 'Action 3',
|
||||
icon: 'heart',
|
||||
icon: 'house',
|
||||
divided: true,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { ActionDropdownItem, IconSize, ButtonSize } from '@n8n/design-syste
|
||||
|
||||
import N8nBadge from '../N8nBadge';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
import N8nIconButton from '../N8nIconButton';
|
||||
import { N8nKeyboardShortcut } from '../N8nKeyboardShortcut';
|
||||
|
||||
@@ -20,7 +21,7 @@ const TRIGGER = ['click', 'hover'] as const;
|
||||
interface ActionDropdownProps {
|
||||
items: ActionDropdownItem[];
|
||||
placement?: Placement;
|
||||
activatorIcon?: string;
|
||||
activatorIcon?: IconName;
|
||||
activatorSize?: ButtonSize;
|
||||
iconSize?: IconSize;
|
||||
trigger?: (typeof TRIGGER)[number];
|
||||
@@ -31,7 +32,7 @@ interface ActionDropdownProps {
|
||||
|
||||
const props = withDefaults(defineProps<ActionDropdownProps>(), {
|
||||
placement: 'bottom',
|
||||
activatorIcon: 'ellipsis-h',
|
||||
activatorIcon: 'ellipsis',
|
||||
activatorSize: 'medium',
|
||||
iconSize: 'medium',
|
||||
trigger: 'click',
|
||||
|
||||
@@ -89,7 +89,7 @@ defineExpose({
|
||||
<slot>
|
||||
<span :class="{ [$style.button]: true, [$style[theme]]: !!theme }">
|
||||
<N8nIcon
|
||||
:icon="iconOrientation === 'horizontal' ? 'ellipsis-h' : 'ellipsis-v'"
|
||||
:icon="iconOrientation === 'horizontal' ? 'ellipsis' : 'ellipsis-vertical'"
|
||||
:size="iconSize"
|
||||
/>
|
||||
</span>
|
||||
@@ -120,7 +120,7 @@ defineExpose({
|
||||
<div :class="$style.iconContainer">
|
||||
<N8nIcon
|
||||
v-if="action.type === 'external-link'"
|
||||
icon="external-link-alt"
|
||||
icon="external-link"
|
||||
size="xsmall"
|
||||
color="text-base"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { render, screen } from '@testing-library/vue';
|
||||
|
||||
import N8nAlert from './Alert.vue';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
|
||||
describe('components', () => {
|
||||
describe('N8nAlert', () => {
|
||||
@@ -21,11 +20,14 @@ describe('components', () => {
|
||||
title: 'Title',
|
||||
default: 'Message',
|
||||
aside: '<button>Click me</button>',
|
||||
icon: '<n8n-icon icon="plus-circle" />',
|
||||
icon: '<n8n-icon icon="circle-plus" />',
|
||||
},
|
||||
global: {
|
||||
components: {
|
||||
'n8n-icon': N8nIcon,
|
||||
'n8n-icon': {
|
||||
template: '<span class="n8n-icon" />',
|
||||
props: ['icon'],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -23,13 +23,13 @@ const props = withDefaults(defineProps<AlertProps>(), {
|
||||
const icon = computed(() => {
|
||||
switch (props.type) {
|
||||
case 'success':
|
||||
return 'check-circle';
|
||||
return 'circle-check';
|
||||
case 'warning':
|
||||
return 'exclamation-triangle';
|
||||
return 'triangle-alert';
|
||||
case 'error':
|
||||
return 'times-circle';
|
||||
return 'circle-x';
|
||||
default:
|
||||
return 'info-circle';
|
||||
return 'info';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ const withSlotsTemplate: StoryFn = (args, { argTypes }) => ({
|
||||
template: `<Breadcrumbs v-bind="args">
|
||||
<template #prepend>
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<n8n-icon icon="layer-group"/>
|
||||
<n8n-icon icon="layers"/>
|
||||
<n8n-text>My Project</n8n-text>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -149,7 +149,7 @@ Text.args = {
|
||||
export const WithIcon = AllSizesTemplate.bind({});
|
||||
WithIcon.args = {
|
||||
label: 'Button',
|
||||
icon: 'plus-circle',
|
||||
icon: 'circle-plus',
|
||||
};
|
||||
|
||||
export const Square = AllColorsAndSizesTemplate.bind({});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('components', () => {
|
||||
it('should render icon button', () => {
|
||||
const wrapper = render(N8nButton, {
|
||||
props: {
|
||||
icon: 'plus-circle',
|
||||
icon: 'circle-plus',
|
||||
},
|
||||
slots,
|
||||
global: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`components > N8nButton > props > icon > should render icon button 1`] = `"<button class="button button primary medium withIcon" aria-live="polite"><span class="icon"><n8n-icon-stub icon="plus-circle" size="medium" spin="false"></n8n-icon-stub></span>Button</button>"`;
|
||||
exports[`components > N8nButton > props > icon > should render icon button 1`] = `"<button class="button button primary medium withIcon" aria-live="polite"><span class="icon"><n8n-icon-stub icon="circle-plus" size="medium" spin="false"></n8n-icon-stub></span>Button</button>"`;
|
||||
|
||||
exports[`components > N8nButton > props > loading > should render loading spinner 1`] = `"<button class="button button primary medium loading withIcon" disabled="" aria-busy="true" aria-live="polite"><span class="icon"><n8n-spinner-stub size="medium" type="dots"></n8n-spinner-stub></span>Button</button>"`;
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ defaultCallout.args = {
|
||||
export const customCallout = template.bind({});
|
||||
customCallout.args = {
|
||||
theme: 'custom',
|
||||
icon: 'code-branch',
|
||||
icon: 'git-branch',
|
||||
default: `
|
||||
This is a custom callout.
|
||||
`,
|
||||
@@ -87,7 +87,7 @@ customCallout.args = {
|
||||
export const secondaryCallout = template.bind({});
|
||||
secondaryCallout.args = {
|
||||
theme: 'secondary',
|
||||
icon: 'thumbtack',
|
||||
icon: 'pin',
|
||||
default: `
|
||||
This data is pinned.
|
||||
`,
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('components', () => {
|
||||
const wrapper = render(N8nCallout, {
|
||||
props: {
|
||||
theme: 'custom',
|
||||
icon: 'code-branch',
|
||||
icon: 'git-branch',
|
||||
},
|
||||
global: {
|
||||
stubs: ['n8n-icon', 'n8n-text'],
|
||||
@@ -93,7 +93,7 @@ describe('components', () => {
|
||||
const wrapper = render(N8nCallout, {
|
||||
props: {
|
||||
theme: 'custom',
|
||||
icon: 'code-branch',
|
||||
icon: 'git-branch',
|
||||
},
|
||||
global: {
|
||||
stubs: ['n8n-icon', 'n8n-text', 'n8n-link'],
|
||||
|
||||
@@ -4,18 +4,19 @@ import { computed, useCssModule } from 'vue';
|
||||
import type { IconSize, CalloutTheme } from '@n8n/design-system/types';
|
||||
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
import N8nText from '../N8nText';
|
||||
|
||||
const CALLOUT_DEFAULT_ICONS: Record<string, string> = {
|
||||
info: 'info-circle',
|
||||
success: 'check-circle',
|
||||
warning: 'exclamation-triangle',
|
||||
danger: 'exclamation-triangle',
|
||||
const CALLOUT_DEFAULT_ICONS: Record<string, IconName> = {
|
||||
info: 'info',
|
||||
success: 'circle-check',
|
||||
warning: 'triangle-alert',
|
||||
danger: 'triangle-alert',
|
||||
};
|
||||
|
||||
interface CalloutProps {
|
||||
theme: CalloutTheme;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
iconSize?: IconSize;
|
||||
iconless?: boolean;
|
||||
slim?: boolean;
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`components > N8nCallout > should render additional slots correctly 1`]
|
||||
"<div class="n8n-callout callout custom round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="code-branch" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="git-branch" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub> <n8n-link-stub size="small"></n8n-link-stub>
|
||||
</div>
|
||||
@@ -16,7 +16,7 @@ exports[`components > N8nCallout > should render custom theme correctly 1`] = `
|
||||
"<div class="n8n-callout callout custom round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="code-branch" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="git-branch" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
@@ -27,7 +27,7 @@ exports[`components > N8nCallout > should render danger theme correctly 1`] = `
|
||||
"<div class="n8n-callout callout danger round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="exclamation-triangle" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="triangle-alert" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@ exports[`components > N8nCallout > should render info theme correctly 1`] = `
|
||||
"<div class="n8n-callout callout info round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="info-circle" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="info" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@ exports[`components > N8nCallout > should render secondary theme correctly 1`] =
|
||||
"<div class="n8n-callout callout secondary round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="info-circle" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="info" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@ exports[`components > N8nCallout > should render success theme correctly 1`] = `
|
||||
"<div class="n8n-callout callout success round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="check-circle" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="circle-check" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@ exports[`components > N8nCallout > should render warning theme correctly 1`] = `
|
||||
"<div class="n8n-callout callout warning round" role="alert">
|
||||
<div class="messageSection">
|
||||
<div class="icon">
|
||||
<n8n-icon-stub icon="exclamation-triangle" size="medium" spin="false"></n8n-icon-stub>
|
||||
<n8n-icon-stub icon="triangle-alert" size="medium" spin="false"></n8n-icon-stub>
|
||||
</div>
|
||||
<n8n-text-stub bold="false" size="small" compact="false" tag="span"></n8n-text-stub>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { render } from '@testing-library/vue';
|
||||
|
||||
import Icon from './Icon.vue';
|
||||
import { deprecatedIconSet, type IconName } from './icons';
|
||||
|
||||
describe('Icon', () => {
|
||||
it('should render correctly with default props', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: 'check',
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with a custom size', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: 'check',
|
||||
size: 24,
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with predefined size', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: 'check',
|
||||
size: 'large',
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with spin enabled', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: 'check',
|
||||
spin: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with a custom color', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: 'check',
|
||||
color: 'primary',
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with a deprecated icon', () => {
|
||||
const wrapper = render(Icon, {
|
||||
props: {
|
||||
icon: Object.keys(deprecatedIconSet)[0] as IconName,
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,49 +1,116 @@
|
||||
<script lang="ts" setup>
|
||||
import type { FontAwesomeIconProps } from '@fortawesome/vue-fontawesome';
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { computed, useCssModule } from 'vue';
|
||||
|
||||
import type { IconSize, IconColor } from '@n8n/design-system/types/icon';
|
||||
|
||||
import N8nText from '../N8nText';
|
||||
import type { IconName } from './icons';
|
||||
import { deprecatedIconSet, updatedIconSet } from './icons';
|
||||
|
||||
interface IconProps {
|
||||
icon: FontAwesomeIconProps['icon'];
|
||||
size?: IconSize;
|
||||
spin?: FontAwesomeIconProps['spin'];
|
||||
// component supports both deprecated and updated icon set to support project icons
|
||||
// but only allow new icon names to be used in the future
|
||||
icon: IconName;
|
||||
size?: IconSize | number;
|
||||
spin?: boolean;
|
||||
color?: IconColor;
|
||||
strokeWidth?: number | undefined;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'N8nIcon' });
|
||||
withDefaults(defineProps<IconProps>(), {
|
||||
size: 'medium',
|
||||
|
||||
const props = withDefaults(defineProps<IconProps>(), {
|
||||
spin: false,
|
||||
size: undefined,
|
||||
color: undefined,
|
||||
});
|
||||
|
||||
const $style = useCssModule();
|
||||
const classes = computed(() => {
|
||||
const applied: string[] = [];
|
||||
if (props.spin) {
|
||||
applied.push('spin');
|
||||
}
|
||||
|
||||
if (props.strokeWidth) {
|
||||
applied.push('strokeWidth');
|
||||
}
|
||||
|
||||
return ['n8n-icon', ...applied.map((c) => $style[c])];
|
||||
});
|
||||
|
||||
const sizesInPixels: Record<IconSize, number> = {
|
||||
xsmall: 10,
|
||||
small: 12,
|
||||
medium: 14,
|
||||
large: 16,
|
||||
xlarge: 20,
|
||||
};
|
||||
|
||||
const size = computed((): { height: string; width: string } => {
|
||||
let sizeToApply = '1em';
|
||||
if (props.size) {
|
||||
sizeToApply = `${typeof props.size === 'number' ? props.size : sizesInPixels[props.size]}px`;
|
||||
}
|
||||
|
||||
return {
|
||||
height: sizeToApply,
|
||||
width: sizeToApply,
|
||||
};
|
||||
});
|
||||
|
||||
const styles = computed(() => {
|
||||
const stylesToApply: Record<string, string> = {};
|
||||
|
||||
if (props.color) {
|
||||
stylesToApply.color = `var(--color-${props.color})`;
|
||||
}
|
||||
|
||||
if (props.strokeWidth) {
|
||||
stylesToApply['--n8n-icon-stroke-width'] = `${props.strokeWidth}px`;
|
||||
}
|
||||
|
||||
return stylesToApply;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<N8nText :size="size" :color="color" :compact="true" class="n8n-icon" v-bind="$attrs">
|
||||
<FontAwesomeIcon :icon="icon" :spin="spin" :class="$style[size]" />
|
||||
</N8nText>
|
||||
<Component
|
||||
:is="
|
||||
updatedIconSet[icon as keyof typeof updatedIconSet] ??
|
||||
deprecatedIconSet[icon as keyof typeof deprecatedIconSet]
|
||||
"
|
||||
v-if="
|
||||
updatedIconSet[icon as keyof typeof updatedIconSet] ??
|
||||
deprecatedIconSet[icon as keyof typeof deprecatedIconSet]
|
||||
"
|
||||
:class="classes"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
:height="size.height"
|
||||
:width="size.width"
|
||||
:data-icon="props.icon"
|
||||
:style="styles"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.xlarge {
|
||||
width: var(--font-size-xl) !important;
|
||||
.strokeWidth {
|
||||
path {
|
||||
stroke-width: var(--n8n-icon-stroke-width);
|
||||
}
|
||||
}
|
||||
|
||||
.large {
|
||||
width: var(--font-size-m) !important;
|
||||
.spin {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.medium {
|
||||
width: var(--font-size-s) !important;
|
||||
}
|
||||
|
||||
.small {
|
||||
width: var(--font-size-2xs) !important;
|
||||
}
|
||||
|
||||
.xsmall {
|
||||
width: var(--font-size-3xs) !important;
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Icon > should render correctly with a custom color 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="1em" height="1em" class="n8n-icon" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with a custom size 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="24px" height="24px" class="n8n-icon" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with a deprecated icon 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="1em" height="1em" class="n8n-icon" aria-hidden="true" focusable="false" role="img" data-icon="variable">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 21s-4-3-4-9s4-9 4-9m8 0s4 3 4 9s-4 9-4 9M15 9l-6 6m0-6l6 6"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with all props combined 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="14px" height="14px" class="n8n-icon spin" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with default props 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="1em" height="1em" class="n8n-icon" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with predefined size 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="16px" height="16px" class="n8n-icon" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
|
||||
exports[`Icon > should render correctly with spin enabled 1`] = `
|
||||
"<svg viewBox="0 0 24 24" width="1em" height="1em" class="n8n-icon spin" aria-hidden="true" focusable="false" role="img" data-icon="check">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5"></path>
|
||||
</svg>"
|
||||
`;
|
||||
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M1 0.642857C1 0.287817 1.27473 0 1.61364 0H4.06818C4.40708 0 4.68182 0.287817 4.68182 0.642857V4.5C4.68182 4.85504 4.40708 5.14286 4.06818 5.14286H1.61364C1.27473 5.14286 1 4.85504 1 4.5V0.642857ZM2.22727 1.28571V3.85714H3.45455V1.28571H2.22727ZM6.31818 0.642857C6.31818 0.287817 6.59292 0 6.93182 0H8.15909C8.49799 0 8.77273 0.287817 8.77273 0.642857V3.85714H9.38636C9.72527 3.85714 10 4.14496 10 4.5C10 4.85504 9.72527 5.14286 9.38636 5.14286H6.93182C6.59292 5.14286 6.31818 4.85504 6.31818 4.5C6.31818 4.14496 6.59292 3.85714 6.93182 3.85714H7.54545V1.28571H6.93182C6.59292 1.28571 6.31818 0.997897 6.31818 0.642857ZM1 7.5C1 7.14496 1.27473 6.85714 1.61364 6.85714H2.84091C3.17981 6.85714 3.45455 7.14496 3.45455 7.5V10.7143H4.06818C4.40708 10.7143 4.68182 11.0021 4.68182 11.3571C4.68182 11.7122 4.40708 12 4.06818 12H1.61364C1.27473 12 1 11.7122 1 11.3571C1 11.0021 1.27473 10.7143 1.61364 10.7143H2.22727V8.14286H1.61364C1.27473 8.14286 1 7.85504 1 7.5ZM6.31818 7.5C6.31818 7.14496 6.59292 6.85714 6.93182 6.85714H9.38636C9.72527 6.85714 10 7.14496 10 7.5V11.3571C10 11.7122 9.72527 12 9.38636 12H6.93182C6.59292 12 6.31818 11.7122 6.31818 11.3571V7.5ZM7.54545 8.14286V10.7143H8.77273V8.14286H7.54545Z" /></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 3L9 21" stroke="currentColor" style="stroke-opacity:1;" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15 3L15 21" stroke="currentColor" style="stroke-opacity:1;" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 352 B |
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M13.3333 12.5525V12.4489C14.2278 12.0756 14.8571 11.1925 14.8571 10.1632V3.61924C14.8571 2.96252 14.5962 2.3327 14.1318 1.86832C13.6675 1.40395 13.0376 1.14307 12.3809 1.14307H5.90473C5.38113 1.14296 4.87098 1.30883 4.44756 1.61684C4.02414 1.92485 3.70926 2.35915 3.54816 2.85734H3.39501C2.70016 2.85734 2.10892 3.10191 1.70206 3.5842C1.30739 4.05124 1.14282 4.67372 1.14282 5.33352V12.0002C1.14282 12.8078 1.43463 13.5346 1.98854 14.0573C2.54168 14.5777 3.30892 14.8535 4.19044 14.8535H7.17711L10.2826 14.8573H10.2842C11.0278 14.8611 11.7645 14.7049 12.336 14.3392C12.9303 13.9582 13.3333 13.3525 13.3333 12.5525ZM3.39501 4.0002H3.42854V10.1625C3.42854 10.8192 3.68942 11.449 4.1538 11.9134C4.61817 12.3777 5.248 12.6386 5.90473 12.6386H12.1874C12.163 12.9571 12.003 13.1948 11.7196 13.3761C11.3897 13.588 10.8891 13.7175 10.2887 13.7144H10.2857L7.17558 13.7106H4.19044C3.54816 13.7106 3.07806 13.5125 2.7733 13.2253C2.47006 12.9403 2.28568 12.5259 2.28568 12.0002V5.33352C2.28568 4.84971 2.40758 4.52057 2.5752 4.32096C2.73139 4.13658 2.98054 4.0002 3.39501 4.0002ZM8.01673 3.80972H11.619C11.7706 3.80972 11.9159 3.86992 12.0231 3.97709C12.1302 4.08425 12.1904 4.22959 12.1904 4.38115V7.98418C12.1904 8.13573 12.1302 8.28107 12.0231 8.38823C11.9159 8.4954 11.7706 8.5556 11.619 8.5556C11.4675 8.5556 11.3221 8.4954 11.215 8.38823C11.1078 8.28107 11.0476 8.13573 11.0476 7.98418V5.76019L7.07044 9.73731C7.0177 9.79186 6.95463 9.83536 6.8849 9.86528C6.81517 9.89519 6.74018 9.91092 6.6643 9.91154C6.58843 9.91217 6.51319 9.89767 6.44298 9.86891C6.37277 9.84014 6.30899 9.79768 6.25536 9.74401C6.20173 9.69033 6.15933 9.62651 6.13063 9.55627C6.10193 9.48603 6.08751 9.41078 6.0882 9.3349C6.0889 9.25903 6.1047 9.18406 6.13468 9.11435C6.16466 9.04465 6.20822 8.98162 6.26282 8.92893L10.24 4.95257H8.01673C7.86517 4.95257 7.71983 4.89237 7.61267 4.7852C7.5055 4.67804 7.4453 4.5327 7.4453 4.38115C7.4453 4.22959 7.5055 4.08425 7.61267 3.97709C7.71983 3.86992 7.86517 3.80972 8.01673 3.80972Z" /></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M1.63636 0H8.18182C9.08556 0 9.81818 0.732625 9.81818 1.63636C9.81818 2.5401 9.08556 3.27273 8.18182 3.27273H1.63636C0.732626 3.27273 0 2.5401 0 1.63636C0 0.732625 0.732625 0 1.63636 0ZM1.63636 1.09091C1.33512 1.09091 1.09091 1.33512 1.09091 1.63636C1.09091 1.93761 1.33512 2.18182 1.63636 2.18182H8.18182C8.48306 2.18182 8.72727 1.93761 8.72727 1.63636C8.72727 1.33512 8.48306 1.09091 8.18182 1.09091H1.63636Z M7.09091 4.36353H11.4545C12.3583 4.36353 13.0909 5.09615 13.0909 5.99989C13.0909 6.90363 12.3583 7.63625 11.4545 7.63625H7.09091C6.18717 7.63625 5.45454 6.90363 5.45454 5.99989C5.45454 5.09615 6.18717 4.36353 7.09091 4.36353ZM7.09091 5.45443C6.78966 5.45443 6.54545 5.69864 6.54545 5.99989C6.54545 6.30114 6.78966 6.54534 7.09091 6.54534H11.4545C11.7558 6.54534 12 6.30114 12 5.99989C12 5.69864 11.7558 5.45443 11.4545 5.45443H7.09091Z M7.09091 8.72729H11.4545C12.3583 8.72729 13.0909 9.45992 13.0909 10.3637C13.0909 11.2674 12.3583 12 11.4545 12H7.09091C6.18717 12 5.45454 11.2674 5.45454 10.3637C5.45454 9.45992 6.18717 8.72729 7.09091 8.72729ZM7.09091 9.8182C6.78966 9.8182 6.54545 10.0624 6.54545 10.3637C6.54545 10.6649 6.78966 10.9091 7.09091 10.9091H11.4545C11.7558 10.9091 12 10.6649 12 10.3637C12 10.0624 11.7558 9.8182 11.4545 9.8182H7.09091Z" /></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2V5" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M12 19V22" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M12 2V5" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M12 19V22" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M22.005 11.9951L19.005 11.9951" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M5.005 11.9951L2.005 11.9951" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M19.0796 19.0676L16.9583 16.9463" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M7.05884 7.04688L4.93752 4.92555" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M4.9375 19.0676L7.05882 16.9463" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M16.9583 7.04688L19.0796 4.92556" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 14 7 C 14 10.866 10.866 14 7 14 C 3.134 14 0 10.866 0 7 C 0 3.134 3.134 0 7 0 C 10.866 0 14 3.134 14 7 Z M 11.243 6 L 2.758 6 L 2.758 8 L 11.243 8 L 11.243 6 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 264 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 14 7 C 14 10.866 10.866 14 7 14 C 3.134 14 0 10.866 0 7 C 0 3.134 3.134 0 7 0 C 10.866 0 14 3.134 14 7 Z M 2.575 7.728 L 5.782 10.935 L 11.489 5.228 L 10.075 3.814 L 5.782 8.107 L 3.989 6.314 L 2.575 7.728 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 312 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 4.207 2.793 L 7 5.586 L 9.793 2.793 L 11.207 4.207 L 8.414 7 L 11.207 9.793 L 9.793 11.207 L 7 8.414 L 4.207 11.207 L 2.793 9.793 L 5.586 7 L 2.793 4.207 L 4.207 2.793 Z M 7 0 C 3.134 0 0 3.134 0 7 C 0 10.866 3.134 14 7 14 C 10.866 14 14 10.866 14 7 C 14 3.134 10.866 0 7 0 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 380 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 14 7.006 C 14 8.867 13.162 10.744 11.95 11.956 C 10.738 13.168 8.861 14.006 7 14.006 C 5.139 14.006 3.262 13.168 2.05 11.956 C 0.838 10.744 0 8.867 0 7.006 C 0 5.145 0.838 3.268 2.05 2.056 C 3.262 0.844 5.139 0.006 7 0.006 C 8.861 0.006 10.738 0.844 11.95 2.056 C 13.162 3.268 14 5.145 14 7.006 Z M 10.536 3.47 C 9.576 2.511 8.453 2.006 7 2.006 C 5.547 2.006 4.424 2.511 3.464 3.47 C 2.505 4.43 2 5.553 2 7.006 C 2 8.459 2.505 9.582 3.464 10.542 C 4.424 11.501 5.547 12.006 7 12.006 C 8.453 12.006 9.576 11.501 10.536 10.542 C 11.495 9.582 12 8.459 12 7.006 C 12 5.553 11.495 4.43 10.536 3.47 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 699 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M13.8668 8.36613L11.9048 7.978C11.967 7.66329 12 7.33649 12 7C12 6.66351 11.967 6.3367 11.9048 6.022L13.8668 5.63387C13.9542 6.07571 14 6.5325 14 7C14 7.4675 13.9542 7.92429 13.8668 8.36613ZM12.821 3.11069L11.159 4.22333C10.7934 3.67721 10.3228 3.2066 9.77667 2.84098L10.8893 1.17904C11.6527 1.6901 12.3099 2.34733 12.821 3.11069ZM8.36613 0.133238L7.978 2.09521C7.66329 2.03296 7.33649 2 7 2C6.66351 2 6.3367 2.03296 6.022 2.09521L5.63387 0.133238C6.07571 0.0458286 6.5325 0 7 0C7.4675 0 7.92429 0.0458285 8.36613 0.133238ZM3.11069 1.17904L4.22333 2.84098C3.67721 3.2066 3.2066 3.67721 2.84098 4.22333L1.17904 3.11069C1.6901 2.34733 2.34733 1.6901 3.11069 1.17904ZM0.133238 5.63387C0.0458285 6.07571 0 6.5325 0 7C0 7.4675 0.0458286 7.92429 0.133238 8.36613L2.09521 7.978C2.03296 7.6633 2 7.33649 2 7C2 6.66351 2.03296 6.33671 2.09521 6.022L0.133238 5.63387ZM1.17904 10.8893L2.84098 9.77667C3.2066 10.3228 3.67721 10.7934 4.22333 11.159L3.11069 12.821C2.34733 12.3099 1.6901 11.6527 1.17904 10.8893ZM5.63387 13.8668L6.022 11.9048C6.33671 11.967 6.66351 12 7 12C7.33649 12 7.6633 11.967 7.978 11.9048L8.36613 13.8668C7.92429 13.9542 7.4675 14 7 14C6.5325 14 6.07571 13.9542 5.63387 13.8668ZM10.8893 12.821L9.77667 11.159C10.3228 10.7934 10.7934 10.3228 11.159 9.77667L12.821 10.8893C12.3099 11.6527 11.6527 12.3099 10.8893 12.821Z" /></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14ZM7 12C4.23858 12 2 9.76142 2 7C2 4.23858 4.23858 2 7 2C9.76142 2 12 4.23858 12 7C12 9.76142 9.76142 12 7 12ZM6 3V8H11C11 5.23858 8.76142 3 6 3Z" /></svg>
|
||||
|
After Width: | Height: | Size: 350 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 14 7 C 14 10.866 10.866 14 7 14 C 3.134 14 0 10.866 0 7 C 0 3.134 3.134 0 7 0 C 10.866 0 14 3.134 14 7 Z M 6.5 9 C 6.224 9 6 9.224 6 9.5 L 6 10.5 C 6 10.776 6.224 11 6.5 11 L 7.5 11 C 7.776 11 8 10.776 8 10.5 L 8 9.5 C 8 9.224 7.776 9 7.5 9 L 6.5 9 Z M 6.5 3 C 6.224 3 6 3.224 6 3.5 L 6 7.5 C 6 7.776 6.224 8 6.5 8 L 7.5 8 C 7.776 8 8 7.776 8 7.5 L 8 3.5 C 8 3.224 7.776 3 7.5 3 L 6.5 3 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 493 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M1.78814e-07 0.666667C1.78814e-07 0.298477 0.298477 0 0.666667 0H11.3333C11.7015 0 12 0.298477 12 0.666667C12 1.03486 11.7015 1.33333 11.3333 1.33333H0.666667C0.298477 1.33333 1.78814e-07 1.03486 1.78814e-07 0.666667ZM1.78814e-07 3.62963C1.78814e-07 3.26144 0.298477 2.96296 0.666667 2.96296H11.3333C11.7015 2.96296 12 3.26144 12 3.62963C12 3.99782 11.7015 4.2963 11.3333 4.2963H0.666667C0.298477 4.2963 1.78814e-07 3.99782 1.78814e-07 3.62963ZM0 6.59259C0 6.2244 0.298477 5.92593 0.666667 5.92593H11.3333C11.7015 5.92593 12 6.2244 12 6.59259C12 6.96078 11.7015 7.25926 11.3333 7.25926H0.666667C0.298477 7.25926 0 6.96078 0 6.59259ZM0 9.55556C0 9.18737 0.298477 8.88889 0.666667 8.88889H8.66667C9.03486 8.88889 9.33333 9.18737 9.33333 9.55556C9.33333 9.92375 9.03486 10.2222 8.66667 10.2222H0.666667C0.298477 10.2222 0 9.92375 0 9.55556Z" /></svg>
|
||||
|
After Width: | Height: | Size: 940 B |
@@ -0,0 +1,3 @@
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path style="stroke:currentColor;stroke-opacity: 1;" d="M8 8V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v4m6 12V10a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2ZM8 13v4m8-4v4M2 15h20" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 355 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M214.433 56C232.908 23.9999 279.096 24.0001 297.571 56L477.704 368C496.18 400 473.085 440 436.135 440H75.8685C38.918 440 15.8241 400 34.2993 368L214.433 56ZM256.002 144L131.294 360H380.709L256.002 144Z" /></svg>
|
||||
|
After Width: | Height: | Size: 306 B |
@@ -0,0 +1,10 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="5" height="5" rx="1" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2"/>
|
||||
<rect x="17" y="2" width="5" height="5" rx="1" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2"/>
|
||||
<rect x="17" y="17" width="5" height="5" rx="1" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2"/>
|
||||
<rect x="2" y="17" width="5" height="5" rx="1" stroke="currentColor" style="stroke:currentColor;stroke-opacity:1;" stroke-width="2"/>
|
||||
<rect x="7" y="3" width="10" height="2" fill="currentColor" style="fill:currentColor;fill-opacity:1;"/>
|
||||
<rect x="7" y="19" width="10" height="2" fill="currentColor" style="fill:currentColor;fill-opacity:1;"/>
|
||||
<rect x="3" y="7" width="2" height="10" fill="currentColor" style="fill:currentColor;fill-opacity:1;"/>
|
||||
<rect x="19" y="7" width="2" height="10" fill="currentColor" style="fill:currentColor;fill-opacity:1;"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,576 @@
|
||||
import Binary from './custom/binary.svg';
|
||||
import GripLinesVertical from './custom/grip-lines-vertical.svg';
|
||||
import Json from './custom/json.svg';
|
||||
import PopOut from './custom/pop-out.svg';
|
||||
import Schema from './custom/schema.svg';
|
||||
import Spinner from './custom/spinner.svg';
|
||||
import StatusCanceled from './custom/status-canceled.svg';
|
||||
import StatusCompleted from './custom/status-completed.svg';
|
||||
import StatusError from './custom/status-error.svg';
|
||||
import StatusNew from './custom/status-new.svg';
|
||||
import StatusUnknown from './custom/status-unknown.svg';
|
||||
import StatusWaiting from './custom/status-waiting.svg';
|
||||
import StatusWarning from './custom/status-warning.svg';
|
||||
import Text from './custom/text.svg';
|
||||
import Toolbox from './custom/toolbox.svg';
|
||||
import Triangle from './custom/triangle.svg';
|
||||
import VectorSquare from './custom/vector-square.svg';
|
||||
|
||||
import IconLucideAlignRight from '~icons/lucide/align-right';
|
||||
import IconLucideArchive from '~icons/lucide/archive';
|
||||
import IconLucideArrowDown from '~icons/lucide/arrow-down';
|
||||
import IconLucideArrowLeft from '~icons/lucide/arrow-left';
|
||||
import IconLucideArrowLeftRight from '~icons/lucide/arrow-left-right';
|
||||
import IconLucideArrowRight from '~icons/lucide/arrow-right';
|
||||
import IconLucideArrowUp from '~icons/lucide/arrow-up';
|
||||
import IconLucideAtSign from '~icons/lucide/at-sign';
|
||||
import IconLucideBan from '~icons/lucide/ban';
|
||||
import IconLucideBell from '~icons/lucide/bell';
|
||||
import IconLucideBook from '~icons/lucide/book';
|
||||
import IconLucideBot from '~icons/lucide/bot';
|
||||
import IconLucideBox from '~icons/lucide/box';
|
||||
import IconLucideBrain from '~icons/lucide/brain';
|
||||
import IconLucideBug from '~icons/lucide/bug';
|
||||
import IconLucideCalculator from '~icons/lucide/calculator';
|
||||
import IconLucideCalendar from '~icons/lucide/calendar';
|
||||
import IconLucideCaseUpper from '~icons/lucide/case-upper';
|
||||
import IconLucideChartColumnDecreasing from '~icons/lucide/chart-column-decreasing';
|
||||
import IconLucideCheck from '~icons/lucide/check';
|
||||
import IconLucideCheckCheck from '~icons/lucide/check-check';
|
||||
import IconLucideChevronDown from '~icons/lucide/chevron-down';
|
||||
import IconLucideChevronLeft from '~icons/lucide/chevron-left';
|
||||
import IconLucideChevronRight from '~icons/lucide/chevron-right';
|
||||
import IconLucideChevronUp from '~icons/lucide/chevron-up';
|
||||
import IconLucideChevronsLeft from '~icons/lucide/chevrons-left';
|
||||
import IconLucideChevronsUpDown from '~icons/lucide/chevrons-up-down';
|
||||
import IconLucideCircle from '~icons/lucide/circle';
|
||||
import IconLucideCircleAlert from '~icons/lucide/circle-alert';
|
||||
import IconLucideCircleCheck from '~icons/lucide/circle-check';
|
||||
import IconLucideCircleDot from '~icons/lucide/circle-dot';
|
||||
import IconLucideCircleHelp from '~icons/lucide/circle-help';
|
||||
import IconLucideCircleMinus from '~icons/lucide/circle-minus';
|
||||
import IconLucideCirclePause from '~icons/lucide/circle-pause';
|
||||
import IconLucideCirclePlay from '~icons/lucide/circle-play';
|
||||
import IconLucideCirclePlus from '~icons/lucide/circle-plus';
|
||||
import IconLucideCircleUserRound from '~icons/lucide/circle-user-round';
|
||||
import IconLucideCircleX from '~icons/lucide/circle-x';
|
||||
import IconLucideClipboardList from '~icons/lucide/clipboard-list';
|
||||
import IconLucideClock from '~icons/lucide/clock';
|
||||
import IconLucideCloud from '~icons/lucide/cloud';
|
||||
import IconLucideCloudDownload from '~icons/lucide/cloud-download';
|
||||
import IconLucideCode from '~icons/lucide/code';
|
||||
import IconLucideCog from '~icons/lucide/cog';
|
||||
import IconLucideContrast from '~icons/lucide/contrast';
|
||||
import IconLucideCopy from '~icons/lucide/copy';
|
||||
import IconLucideDatabase from '~icons/lucide/database';
|
||||
import IconLucideEarth from '~icons/lucide/earth';
|
||||
import IconLucideEllipsis from '~icons/lucide/ellipsis';
|
||||
import IconLucideEllipsisVertical from '~icons/lucide/ellipsis-vertical';
|
||||
import IconLucideEqual from '~icons/lucide/equal';
|
||||
import IconLucideExternalLink from '~icons/lucide/external-link';
|
||||
import IconLucideEye from '~icons/lucide/eye';
|
||||
import IconLucideEyeOff from '~icons/lucide/eye-off';
|
||||
import IconLucideFile from '~icons/lucide/file';
|
||||
import IconLucideFileArchive from '~icons/lucide/file-archive';
|
||||
import IconLucideFileCode from '~icons/lucide/file-code';
|
||||
import IconLucideFileDown from '~icons/lucide/file-down';
|
||||
import IconLucideFileInput from '~icons/lucide/file-input';
|
||||
import IconLucideFileOutput from '~icons/lucide/file-output';
|
||||
import IconLucideFileText from '~icons/lucide/file-text';
|
||||
import IconLucideFiles from '~icons/lucide/files';
|
||||
import IconLucideFingerprint from '~icons/lucide/fingerprint';
|
||||
import IconLucideFlaskConical from '~icons/lucide/flask-conical';
|
||||
import IconLucideFolder from '~icons/lucide/folder';
|
||||
import IconLucideFolderOpen from '~icons/lucide/folder-open';
|
||||
import IconLucideFolderPlus from '~icons/lucide/folder-plus';
|
||||
import IconLucideFunnel from '~icons/lucide/funnel';
|
||||
import IconLucideGem from '~icons/lucide/gem';
|
||||
import IconLucideGift from '~icons/lucide/gift';
|
||||
import IconLucideGitBranch from '~icons/lucide/git-branch';
|
||||
import IconLucideGlobe from '~icons/lucide/globe';
|
||||
import IconLucideGraduationCap from '~icons/lucide/graduation-cap';
|
||||
import IconLucideGrid2x2 from '~icons/lucide/grid-2x2';
|
||||
import IconLucideGripVertical from '~icons/lucide/grip-vertical';
|
||||
import IconLucideHandCoins from '~icons/lucide/hand-coins';
|
||||
import IconLucideHandshake from '~icons/lucide/handshake';
|
||||
import IconLucideHardDrive from '~icons/lucide/hard-drive';
|
||||
import IconLucideHardDriveDownload from '~icons/lucide/hard-drive-download';
|
||||
import IconLucideHash from '~icons/lucide/hash';
|
||||
import IconLucideHistory from '~icons/lucide/history';
|
||||
import IconLucideHourglass from '~icons/lucide/hourglass';
|
||||
import IconLucideHouse from '~icons/lucide/house';
|
||||
import IconLucideImage from '~icons/lucide/image';
|
||||
import IconLucideInbox from '~icons/lucide/inbox';
|
||||
import IconLucideInfo from '~icons/lucide/info';
|
||||
import IconLucideKeyRound from '~icons/lucide/key-round';
|
||||
import IconLucideLanguages from '~icons/lucide/languages';
|
||||
import IconLucideLayers from '~icons/lucide/layers';
|
||||
import IconLucideLightbulb from '~icons/lucide/lightbulb';
|
||||
import IconLucideLink from '~icons/lucide/link';
|
||||
import IconLucideList from '~icons/lucide/list';
|
||||
import IconLucideListChecks from '~icons/lucide/list-checks';
|
||||
import IconLucideLock from '~icons/lucide/lock';
|
||||
import IconLucideLogIn from '~icons/lucide/log-in';
|
||||
import IconLucideLogOut from '~icons/lucide/log-out';
|
||||
import IconLucideMail from '~icons/lucide/mail';
|
||||
import IconLucideMaximize from '~icons/lucide/maximize';
|
||||
import IconLucideMaximize2 from '~icons/lucide/maximize-2';
|
||||
import IconLucideMenu from '~icons/lucide/menu';
|
||||
import IconLucideMessageCircle from '~icons/lucide/message-circle';
|
||||
import IconLucideMessagesSquare from '~icons/lucide/messages-square';
|
||||
import IconLucideMilestone from '~icons/lucide/milestone';
|
||||
import IconLucideMinimize2 from '~icons/lucide/minimize-2';
|
||||
import IconLucideMousePointer from '~icons/lucide/mouse-pointer';
|
||||
import IconLucideNetwork from '~icons/lucide/network';
|
||||
import IconLucidePackageOpen from '~icons/lucide/package-open';
|
||||
import IconLucidePalette from '~icons/lucide/palette';
|
||||
import IconLucidePause from '~icons/lucide/pause';
|
||||
import IconLucidePen from '~icons/lucide/pen';
|
||||
import IconLucidePencil from '~icons/lucide/pencil';
|
||||
import IconLucidePin from '~icons/lucide/pin';
|
||||
import IconLucidePlay from '~icons/lucide/play';
|
||||
import IconLucidePlug from '~icons/lucide/plug';
|
||||
import IconLucidePlus from '~icons/lucide/plus';
|
||||
import IconLucidePocketKnife from '~icons/lucide/pocket-knife';
|
||||
import IconLucidePower from '~icons/lucide/power';
|
||||
import IconLucideRedo2 from '~icons/lucide/redo-2';
|
||||
import IconLucideRefreshCw from '~icons/lucide/refresh-cw';
|
||||
import IconLucideRemoveFormatting from '~icons/lucide/remove-formatting';
|
||||
import IconLucideRss from '~icons/lucide/rss';
|
||||
import IconLucideSatelliteDish from '~icons/lucide/satellite-dish';
|
||||
import IconLucideSave from '~icons/lucide/save';
|
||||
import IconLucideScale from '~icons/lucide/scale';
|
||||
import IconLucideScissors from '~icons/lucide/scissors';
|
||||
import IconLucideSearch from '~icons/lucide/search';
|
||||
import IconLucideSend from '~icons/lucide/send';
|
||||
import IconLucideServer from '~icons/lucide/server';
|
||||
import IconLucideShare from '~icons/lucide/share';
|
||||
import IconLucideSlidersHorizontal from '~icons/lucide/sliders-horizontal';
|
||||
import IconLucideSmile from '~icons/lucide/smile';
|
||||
import IconLucideSquare from '~icons/lucide/square';
|
||||
import IconLucideSquareCheck from '~icons/lucide/square-check';
|
||||
import IconLucideSquarePen from '~icons/lucide/square-pen';
|
||||
import IconLucideSquarePlus from '~icons/lucide/square-plus';
|
||||
import IconLucideStickyNote from '~icons/lucide/sticky-note';
|
||||
import IconLucideSun from '~icons/lucide/sun';
|
||||
import IconLucideTable from '~icons/lucide/table';
|
||||
import IconLucideTags from '~icons/lucide/tags';
|
||||
import IconLucideTerminal from '~icons/lucide/terminal';
|
||||
import IconLucideThumbsDown from '~icons/lucide/thumbs-down';
|
||||
import IconLucideThumbsUp from '~icons/lucide/thumbs-up';
|
||||
import IconLucideTrash2 from '~icons/lucide/trash-2';
|
||||
import IconLucideTreePine from '~icons/lucide/tree-pine';
|
||||
import IconLucideTriangleAlert from '~icons/lucide/triangle-alert';
|
||||
import IconLucideUndo2 from '~icons/lucide/undo-2';
|
||||
import IconLucideUnlink from '~icons/lucide/unlink';
|
||||
import IconLucideUser from '~icons/lucide/user';
|
||||
import IconLucideUserCheck from '~icons/lucide/user-check';
|
||||
import IconLucideUserLock from '~icons/lucide/user-lock';
|
||||
import IconLucideUserRound from '~icons/lucide/user-round';
|
||||
import IconLucideUsers from '~icons/lucide/users';
|
||||
import IconLucideVariable from '~icons/lucide/variable';
|
||||
import IconLucideVault from '~icons/lucide/vault';
|
||||
import IconLucideVideo from '~icons/lucide/video';
|
||||
import IconLucideWaypoints from '~icons/lucide/waypoints';
|
||||
import IconLucideWrench from '~icons/lucide/wrench';
|
||||
import IconLucideX from '~icons/lucide/x';
|
||||
import IconLucideZap from '~icons/lucide/zap';
|
||||
import IconLucideZoomIn from '~icons/lucide/zoom-in';
|
||||
import IconLucideZoomOut from '~icons/lucide/zoom-out';
|
||||
|
||||
/**
|
||||
* Need to keep old icon names
|
||||
* To support old project icons
|
||||
* Which used to include all icons in instance
|
||||
*/
|
||||
export const deprecatedIconSet = {
|
||||
// customIcons
|
||||
variable: IconLucideVariable,
|
||||
'pop-out': PopOut,
|
||||
triangle: Triangle,
|
||||
'status-completed': StatusCompleted,
|
||||
'status-waiting': StatusWaiting,
|
||||
'status-error': StatusError,
|
||||
'status-canceled': StatusCanceled,
|
||||
'status-new': StatusNew,
|
||||
'status-unknown': StatusUnknown,
|
||||
'status-warning': StatusWarning,
|
||||
'vector-square': VectorSquare,
|
||||
schema: Schema,
|
||||
json: Json,
|
||||
binary: Binary,
|
||||
text: Text,
|
||||
toolbox: Toolbox,
|
||||
spinner: Spinner,
|
||||
xmark: IconLucideX,
|
||||
|
||||
// fontAwesomeIcons
|
||||
'caret-up': IconLucideChevronUp,
|
||||
'caret-down': IconLucideChevronDown,
|
||||
'caret-right': IconLucideChevronRight,
|
||||
'caret-left': IconLucideChevronLeft,
|
||||
'folder-plus': IconLucideFolderPlus,
|
||||
share: IconLucideShare,
|
||||
'user-check': IconLucideUserCheck,
|
||||
'check-double': IconLucideCheckCheck,
|
||||
'exclamation-circle': IconLucideCircleAlert,
|
||||
circle: IconLucideCircle,
|
||||
'eye-slash': IconLucideEyeOff,
|
||||
folder: IconLucideFolder,
|
||||
'minus-circle': IconLucideCircleMinus,
|
||||
adjust: IconLucideContrast,
|
||||
refresh: IconLucideRefreshCw,
|
||||
vault: IconLucideVault,
|
||||
'angle-double-left': IconLucideChevronsLeft,
|
||||
'angle-down': IconLucideChevronDown,
|
||||
'angle-left': IconLucideChevronLeft,
|
||||
'angle-right': IconLucideChevronRight,
|
||||
'angle-up': IconLucideChevronUp,
|
||||
archive: IconLucideArchive,
|
||||
'arrow-left': IconLucideArrowLeft,
|
||||
'arrow-right': IconLucideArrowRight,
|
||||
'arrow-up': IconLucideArrowUp,
|
||||
'arrow-down': IconLucideArrowDown,
|
||||
at: IconLucideAtSign,
|
||||
ban: IconLucideBan,
|
||||
'balance-scale-left': IconLucideScale,
|
||||
bars: IconLucideMenu,
|
||||
bolt: IconLucideZap,
|
||||
book: IconLucideBook,
|
||||
'box-open': IconLucidePackageOpen,
|
||||
bug: IconLucideBug,
|
||||
brain: IconLucideBrain,
|
||||
calculator: IconLucideCalculator,
|
||||
calendar: IconLucideCalendar,
|
||||
'chart-bar': IconLucideChartColumnDecreasing,
|
||||
check: IconLucideCheck,
|
||||
'check-circle': IconLucideCircleCheck,
|
||||
'check-square': IconLucideSquareCheck,
|
||||
'chevron-left': IconLucideChevronLeft,
|
||||
'chevron-right': IconLucideChevronRight,
|
||||
'chevron-down': IconLucideChevronDown,
|
||||
'chevron-up': IconLucideChevronUp,
|
||||
code: IconLucideCode,
|
||||
'code-branch': IconLucideGitBranch,
|
||||
cog: IconLucideCog,
|
||||
cogs: IconLucideCog,
|
||||
comment: IconLucideMessageCircle,
|
||||
comments: IconLucideMessagesSquare,
|
||||
'clipboard-list': IconLucideClipboardList,
|
||||
clock: IconLucideClock,
|
||||
clone: IconLucideCopy,
|
||||
cloud: IconLucideCloud,
|
||||
'cloud-download-alt': IconLucideCloudDownload,
|
||||
compress: IconLucideChevronsUpDown,
|
||||
copy: IconLucideFiles,
|
||||
cube: IconLucideBox,
|
||||
cut: IconLucideScissors,
|
||||
database: IconLucideDatabase,
|
||||
'dot-circle': IconLucideCircleDot,
|
||||
'grip-lines-vertical': GripLinesVertical,
|
||||
'grip-vertical': IconLucideGripVertical,
|
||||
edit: IconLucideSquarePen,
|
||||
'ellipsis-h': IconLucideEllipsis,
|
||||
'ellipsis-v': IconLucideEllipsisVertical,
|
||||
envelope: IconLucideMail,
|
||||
equals: IconLucideEqual,
|
||||
eye: IconLucideEye,
|
||||
'exclamation-triangle': IconLucideTriangleAlert,
|
||||
expand: IconLucideMaximize,
|
||||
'expand-alt': IconLucideMaximize2,
|
||||
'external-link-alt': IconLucideExternalLink,
|
||||
'exchange-alt': IconLucideArrowLeftRight,
|
||||
file: IconLucideFile,
|
||||
'file-alt': IconLucideFileText,
|
||||
'file-archive': IconLucideFileArchive,
|
||||
'file-code': IconLucideFileCode,
|
||||
'file-download': IconLucideFileDown,
|
||||
'file-export': IconLucideFileOutput,
|
||||
'file-import': IconLucideFileInput,
|
||||
'file-pdf': IconLucideFileText,
|
||||
filter: IconLucideFunnel,
|
||||
fingerprint: IconLucideFingerprint,
|
||||
flask: IconLucideFlaskConical,
|
||||
'folder-open': IconLucideFolderOpen,
|
||||
font: IconLucideCaseUpper,
|
||||
gift: IconLucideGift,
|
||||
globe: IconLucideGlobe,
|
||||
'globe-americas': IconLucideEarth,
|
||||
'graduation-cap': IconLucideGraduationCap,
|
||||
'hand-holding-usd': IconLucideHandCoins,
|
||||
'hand-scissors': IconLucideScissors,
|
||||
handshake: IconLucideHandshake,
|
||||
'hand-point-left': IconLucideArrowLeft,
|
||||
hashtag: IconLucideHash,
|
||||
hdd: IconLucideHardDrive,
|
||||
history: IconLucideHistory,
|
||||
home: IconLucideHouse,
|
||||
hourglass: IconLucideHourglass,
|
||||
image: IconLucideImage,
|
||||
inbox: IconLucideInbox,
|
||||
info: IconLucideInfo,
|
||||
'info-circle': IconLucideInfo,
|
||||
key: IconLucideKeyRound,
|
||||
language: IconLucideLanguages,
|
||||
'layer-group': IconLucideLayers,
|
||||
link: IconLucideLink,
|
||||
list: IconLucideList,
|
||||
lightbulb: IconLucideLightbulb,
|
||||
lock: IconLucideLock,
|
||||
'map-signs': IconLucideMilestone,
|
||||
'mouse-pointer': IconLucideMousePointer,
|
||||
'network-wired': IconLucideNetwork,
|
||||
palette: IconLucidePalette,
|
||||
pause: IconLucidePause,
|
||||
'pause-circle': IconLucideCirclePause,
|
||||
pen: IconLucidePen,
|
||||
'pencil-alt': IconLucidePencil,
|
||||
play: IconLucidePlay,
|
||||
'play-circle': IconLucideCirclePlay,
|
||||
plug: IconLucidePlug,
|
||||
plus: IconLucidePlus,
|
||||
'plus-circle': IconLucideCirclePlus,
|
||||
'plus-square': IconLucideSquarePlus,
|
||||
'project-diagram': IconLucideWaypoints,
|
||||
question: IconLucideCircleHelp,
|
||||
'question-circle': IconLucideCircleHelp,
|
||||
redo: IconLucideRedo2,
|
||||
'remove-format': IconLucideRemoveFormatting,
|
||||
robot: IconLucideBot,
|
||||
rss: IconLucideRss,
|
||||
save: IconLucideSave,
|
||||
'satellite-dish': IconLucideSatelliteDish,
|
||||
search: IconLucideSearch,
|
||||
'search-minus': IconLucideZoomOut,
|
||||
'search-plus': IconLucideZoomIn,
|
||||
server: IconLucideServer,
|
||||
screwdriver: IconLucidePocketKnife,
|
||||
smile: IconLucideSmile,
|
||||
'sign-in-alt': IconLucideLogIn,
|
||||
'sign-out-alt': IconLucideLogOut,
|
||||
'sliders-h': IconLucideSlidersHorizontal,
|
||||
'sticky-note': IconLucideStickyNote,
|
||||
stop: IconLucideSquare,
|
||||
stream: IconLucideAlignRight,
|
||||
sun: IconLucideSun,
|
||||
sync: IconLucideRefreshCw,
|
||||
'sync-alt': IconLucideRefreshCw,
|
||||
table: IconLucideTable,
|
||||
tags: IconLucideTags,
|
||||
tasks: IconLucideListChecks,
|
||||
terminal: IconLucideTerminal,
|
||||
'th-large': IconLucideGrid2x2,
|
||||
thumbtack: IconLucidePin,
|
||||
'thumbs-down': IconLucideThumbsDown,
|
||||
'thumbs-up': IconLucideThumbsUp,
|
||||
times: IconLucideX,
|
||||
'times-circle': IconLucideCircleX,
|
||||
tools: IconLucideWrench,
|
||||
trash: IconLucideTrash2,
|
||||
undo: IconLucideUndo2,
|
||||
unlink: IconLucideUnlink,
|
||||
user: IconLucideUser,
|
||||
'user-circle': IconLucideCircleUserRound,
|
||||
'user-friends': IconLucideUserRound,
|
||||
users: IconLucideUsers,
|
||||
video: IconLucideVideo,
|
||||
tree: IconLucideTreePine,
|
||||
'user-lock': IconLucideUserLock,
|
||||
gem: IconLucideGem,
|
||||
download: IconLucideHardDriveDownload,
|
||||
'power-off': IconLucidePower,
|
||||
'paper-plane': IconLucideSend,
|
||||
bell: IconLucideBell,
|
||||
} as const;
|
||||
|
||||
export const updatedIconSet = {
|
||||
// custom icons
|
||||
'grip-lines-vertical': GripLinesVertical,
|
||||
variable: IconLucideVariable,
|
||||
'pop-out': PopOut,
|
||||
triangle: Triangle,
|
||||
'status-completed': StatusCompleted,
|
||||
'status-waiting': StatusWaiting,
|
||||
'status-error': StatusError,
|
||||
'status-canceled': StatusCanceled,
|
||||
'status-new': StatusNew,
|
||||
'status-unknown': StatusUnknown,
|
||||
'status-warning': StatusWarning,
|
||||
'vector-square': VectorSquare,
|
||||
schema: Schema,
|
||||
json: Json,
|
||||
binary: Binary,
|
||||
text: Text,
|
||||
toolbox: Toolbox,
|
||||
spinner: Spinner,
|
||||
|
||||
// lucide
|
||||
'align-right': IconLucideAlignRight,
|
||||
archive: IconLucideArchive,
|
||||
'arrow-down': IconLucideArrowDown,
|
||||
'arrow-left': IconLucideArrowLeft,
|
||||
'arrow-left-right': IconLucideArrowLeftRight,
|
||||
'arrow-right': IconLucideArrowRight,
|
||||
'arrow-up': IconLucideArrowUp,
|
||||
'at-sign': IconLucideAtSign,
|
||||
ban: IconLucideBan,
|
||||
bell: IconLucideBell,
|
||||
book: IconLucideBook,
|
||||
bot: IconLucideBot,
|
||||
box: IconLucideBox,
|
||||
brain: IconLucideBrain,
|
||||
bug: IconLucideBug,
|
||||
calculator: IconLucideCalculator,
|
||||
calendar: IconLucideCalendar,
|
||||
'case-upper': IconLucideCaseUpper,
|
||||
'chart-column-decreasing': IconLucideChartColumnDecreasing,
|
||||
check: IconLucideCheck,
|
||||
'check-check': IconLucideCheckCheck,
|
||||
'chevron-down': IconLucideChevronDown,
|
||||
'chevron-left': IconLucideChevronLeft,
|
||||
'chevron-right': IconLucideChevronRight,
|
||||
'chevron-up': IconLucideChevronUp,
|
||||
'chevrons-left': IconLucideChevronsLeft,
|
||||
circle: IconLucideCircle,
|
||||
'circle-alert': IconLucideCircleAlert,
|
||||
'circle-check': IconLucideCircleCheck,
|
||||
'circle-dot': IconLucideCircleDot,
|
||||
'circle-help': IconLucideCircleHelp,
|
||||
'circle-minus': IconLucideCircleMinus,
|
||||
'circle-pause': IconLucideCirclePause,
|
||||
'circle-play': IconLucideCirclePlay,
|
||||
'circle-plus': IconLucideCirclePlus,
|
||||
'circle-user-round': IconLucideCircleUserRound,
|
||||
'circle-x': IconLucideCircleX,
|
||||
'clipboard-list': IconLucideClipboardList,
|
||||
clock: IconLucideClock,
|
||||
cloud: IconLucideCloud,
|
||||
'cloud-download': IconLucideCloudDownload,
|
||||
code: IconLucideCode,
|
||||
cog: IconLucideCog,
|
||||
contrast: IconLucideContrast,
|
||||
copy: IconLucideCopy,
|
||||
database: IconLucideDatabase,
|
||||
earth: IconLucideEarth,
|
||||
ellipsis: IconLucideEllipsis,
|
||||
'ellipsis-vertical': IconLucideEllipsisVertical,
|
||||
equal: IconLucideEqual,
|
||||
'external-link': IconLucideExternalLink,
|
||||
eye: IconLucideEye,
|
||||
'eye-off': IconLucideEyeOff,
|
||||
file: IconLucideFile,
|
||||
'file-archive': IconLucideFileArchive,
|
||||
'file-code': IconLucideFileCode,
|
||||
'file-down': IconLucideFileDown,
|
||||
'file-input': IconLucideFileInput,
|
||||
'file-output': IconLucideFileOutput,
|
||||
'file-text': IconLucideFileText,
|
||||
files: IconLucideFiles,
|
||||
fingerprint: IconLucideFingerprint,
|
||||
'flask-conical': IconLucideFlaskConical,
|
||||
folder: IconLucideFolder,
|
||||
'folder-open': IconLucideFolderOpen,
|
||||
'folder-plus': IconLucideFolderPlus,
|
||||
funnel: IconLucideFunnel,
|
||||
gem: IconLucideGem,
|
||||
gift: IconLucideGift,
|
||||
'git-branch': IconLucideGitBranch,
|
||||
globe: IconLucideGlobe,
|
||||
'graduation-cap': IconLucideGraduationCap,
|
||||
'grid-2x2': IconLucideGrid2x2,
|
||||
'grip-vertical': IconLucideGripVertical,
|
||||
'hand-coins': IconLucideHandCoins,
|
||||
handshake: IconLucideHandshake,
|
||||
'hard-drive': IconLucideHardDrive,
|
||||
'hard-drive-download': IconLucideHardDriveDownload,
|
||||
hash: IconLucideHash,
|
||||
history: IconLucideHistory,
|
||||
hourglass: IconLucideHourglass,
|
||||
house: IconLucideHouse,
|
||||
image: IconLucideImage,
|
||||
inbox: IconLucideInbox,
|
||||
info: IconLucideInfo,
|
||||
'key-round': IconLucideKeyRound,
|
||||
languages: IconLucideLanguages,
|
||||
layers: IconLucideLayers,
|
||||
lightbulb: IconLucideLightbulb,
|
||||
link: IconLucideLink,
|
||||
list: IconLucideList,
|
||||
'list-checks': IconLucideListChecks,
|
||||
lock: IconLucideLock,
|
||||
'log-in': IconLucideLogIn,
|
||||
'log-out': IconLucideLogOut,
|
||||
mail: IconLucideMail,
|
||||
'minimize-2': IconLucideMinimize2,
|
||||
maximize: IconLucideMaximize,
|
||||
'maximize-2': IconLucideMaximize2,
|
||||
menu: IconLucideMenu,
|
||||
'message-circle': IconLucideMessageCircle,
|
||||
'messages-square': IconLucideMessagesSquare,
|
||||
milestone: IconLucideMilestone,
|
||||
'mouse-pointer': IconLucideMousePointer,
|
||||
network: IconLucideNetwork,
|
||||
'package-open': IconLucidePackageOpen,
|
||||
palette: IconLucidePalette,
|
||||
pause: IconLucidePause,
|
||||
pen: IconLucidePen,
|
||||
pencil: IconLucidePencil,
|
||||
pin: IconLucidePin,
|
||||
play: IconLucidePlay,
|
||||
plug: IconLucidePlug,
|
||||
plus: IconLucidePlus,
|
||||
'pocket-knife': IconLucidePocketKnife,
|
||||
power: IconLucidePower,
|
||||
'redo-2': IconLucideRedo2,
|
||||
'refresh-cw': IconLucideRefreshCw,
|
||||
'remove-formatting': IconLucideRemoveFormatting,
|
||||
rss: IconLucideRss,
|
||||
'satellite-dish': IconLucideSatelliteDish,
|
||||
save: IconLucideSave,
|
||||
scale: IconLucideScale,
|
||||
scissors: IconLucideScissors,
|
||||
search: IconLucideSearch,
|
||||
send: IconLucideSend,
|
||||
server: IconLucideServer,
|
||||
share: IconLucideShare,
|
||||
'sliders-horizontal': IconLucideSlidersHorizontal,
|
||||
smile: IconLucideSmile,
|
||||
square: IconLucideSquare,
|
||||
'square-check': IconLucideSquareCheck,
|
||||
'square-pen': IconLucideSquarePen,
|
||||
'square-plus': IconLucideSquarePlus,
|
||||
'sticky-note': IconLucideStickyNote,
|
||||
sun: IconLucideSun,
|
||||
table: IconLucideTable,
|
||||
tags: IconLucideTags,
|
||||
terminal: IconLucideTerminal,
|
||||
'thumbs-down': IconLucideThumbsDown,
|
||||
'thumbs-up': IconLucideThumbsUp,
|
||||
'trash-2': IconLucideTrash2,
|
||||
'tree-pine': IconLucideTreePine,
|
||||
'triangle-alert': IconLucideTriangleAlert,
|
||||
'undo-2': IconLucideUndo2,
|
||||
unlink: IconLucideUnlink,
|
||||
user: IconLucideUser,
|
||||
'user-check': IconLucideUserCheck,
|
||||
'user-lock': IconLucideUserLock,
|
||||
'user-round': IconLucideUserRound,
|
||||
users: IconLucideUsers,
|
||||
vault: IconLucideVault,
|
||||
video: IconLucideVideo,
|
||||
waypoints: IconLucideWaypoints,
|
||||
wrench: IconLucideWrench,
|
||||
x: IconLucideX,
|
||||
zap: IconLucideZap,
|
||||
'zoom-in': IconLucideZoomIn,
|
||||
'zoom-out': IconLucideZoomOut,
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof updatedIconSet; // only new icon names should be used moving forward
|
||||
|
||||
export function isSupportedIconName(iconName?: string): iconName is IconName {
|
||||
// support both deprecated and updated icon names
|
||||
return (
|
||||
typeof iconName === 'string' && (iconName in updatedIconSet || iconName in deprecatedIconSet)
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import type { StoryFn } from '@storybook/vue3';
|
||||
|
||||
import { TEST_ICONS } from './constants';
|
||||
import type { Icon } from './IconPicker.vue';
|
||||
import N8nIconPicker from './IconPicker.vue';
|
||||
import { type IconOrEmoji } from './types';
|
||||
|
||||
export default {
|
||||
title: 'Atoms/Icon Picker',
|
||||
@@ -19,7 +18,7 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
function createTemplate(icon: Icon): StoryFn {
|
||||
function createTemplate(icon: IconOrEmoji): StoryFn {
|
||||
return (args, { argTypes }) => ({
|
||||
components: { N8nIconPicker },
|
||||
props: Object.keys(argTypes),
|
||||
@@ -39,13 +38,11 @@ const DefaultTemplate = createTemplate({ type: 'icon', value: 'smile' });
|
||||
export const Default = DefaultTemplate.bind({});
|
||||
Default.args = {
|
||||
buttonTooltip: 'Select an icon',
|
||||
availableIcons: TEST_ICONS,
|
||||
};
|
||||
|
||||
const CustomTooltipTemplate = createTemplate({ type: 'icon', value: 'layer-group' });
|
||||
const CustomTooltipTemplate = createTemplate({ type: 'icon', value: 'layers' });
|
||||
export const WithCustomIconAndTooltip = CustomTooltipTemplate.bind({});
|
||||
WithCustomIconAndTooltip.args = {
|
||||
availableIcons: [...TEST_ICONS],
|
||||
buttonTooltip: 'Select something...',
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { fireEvent, render } from '@testing-library/vue';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
|
||||
import IconPicker from '.';
|
||||
import { TEST_ICONS } from './constants';
|
||||
import { ALL_ICON_PICKER_ICONS } from './constants';
|
||||
|
||||
// Create a proxy handler that returns a mock icon object for any icon name
|
||||
// and mock the entire icon library with the proxy
|
||||
@@ -42,11 +42,6 @@ const components = {
|
||||
template: '<button :data-icon="icon" data-testid="icon-picker-button" />',
|
||||
props: ['icon'],
|
||||
},
|
||||
N8nIcon: {
|
||||
template:
|
||||
'<div class="mock-icon" :data-icon="typeof icon === \'string\' ? icon : icon.iconName" />',
|
||||
props: ['icon'],
|
||||
},
|
||||
};
|
||||
|
||||
describe('IconPicker', () => {
|
||||
@@ -55,12 +50,11 @@ describe('IconPicker', () => {
|
||||
props: {
|
||||
modelValue: { type: 'icon', value: 'smile' },
|
||||
buttonTooltip: 'Select an icon',
|
||||
availableIcons: TEST_ICONS,
|
||||
},
|
||||
global: {
|
||||
plugins: [router],
|
||||
components,
|
||||
stubs: ['N8nButton'],
|
||||
stubs: ['N8nButton', 'N8nIcon'],
|
||||
},
|
||||
});
|
||||
const TEST_EMOJI_COUNT = 1962;
|
||||
@@ -71,7 +65,8 @@ describe('IconPicker', () => {
|
||||
expect(getByTestId('tab-icons').className).toContain('activeTab');
|
||||
expect(getByTestId('icon-picker-popup')).toBeVisible();
|
||||
// All icons should be rendered
|
||||
expect(getAllByTestId('icon-picker-icon')).toHaveLength(TEST_ICONS.length);
|
||||
expect(getAllByTestId('icon-picker-icon')).toHaveLength(ALL_ICON_PICKER_ICONS.length);
|
||||
|
||||
// Click on emojis tab
|
||||
await fireEvent.click(getByTestId('tab-emojis'));
|
||||
// Emojis tab should be active
|
||||
@@ -79,13 +74,13 @@ describe('IconPicker', () => {
|
||||
// All emojis should be rendered
|
||||
expect(getAllByTestId('icon-picker-emoji')).toHaveLength(TEST_EMOJI_COUNT);
|
||||
});
|
||||
|
||||
it('renders icon picker with custom icon and tooltip', async () => {
|
||||
const ICON = 'layer-group';
|
||||
const ICON = 'layers';
|
||||
const TOOLTIP = 'Select something...';
|
||||
const { getByTestId, getByRole } = render(IconPicker, {
|
||||
props: {
|
||||
modelValue: { type: 'icon', value: ICON },
|
||||
availableIcons: [...TEST_ICONS],
|
||||
buttonTooltip: TOOLTIP,
|
||||
},
|
||||
global: {
|
||||
@@ -98,13 +93,13 @@ describe('IconPicker', () => {
|
||||
expect(getByRole('tooltip').textContent).toBe(TOOLTIP);
|
||||
expect(getByTestId('icon-picker-button')).toHaveAttribute('icon', ICON);
|
||||
});
|
||||
|
||||
it('renders emoji as default icon correctly', async () => {
|
||||
const ICON = '🔥';
|
||||
const TOOLTIP = 'Select something...';
|
||||
const { getByTestId, getByRole } = render(IconPicker, {
|
||||
props: {
|
||||
modelValue: { type: 'emoji', value: ICON },
|
||||
availableIcons: [...TEST_ICONS],
|
||||
buttonTooltip: TOOLTIP,
|
||||
},
|
||||
global: {
|
||||
@@ -116,12 +111,12 @@ describe('IconPicker', () => {
|
||||
expect(getByRole('tooltip').textContent).toBe(TOOLTIP);
|
||||
expect(getByTestId('icon-picker-button')).toHaveTextContent(ICON);
|
||||
});
|
||||
|
||||
it('renders icon picker with only emojis', () => {
|
||||
const { queryByTestId } = render(IconPicker, {
|
||||
props: {
|
||||
modelValue: { type: 'icon', value: 'smile' },
|
||||
buttonTooltip: 'Select an emoji',
|
||||
availableIcons: [],
|
||||
},
|
||||
global: {
|
||||
plugins: [router],
|
||||
@@ -131,42 +126,43 @@ describe('IconPicker', () => {
|
||||
});
|
||||
expect(queryByTestId('tab-icons')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('is able to select an icon', async () => {
|
||||
const { getByTestId, getAllByTestId, queryByTestId, emitted } = render(IconPicker, {
|
||||
props: {
|
||||
modelValue: { type: 'icon', value: 'smile' },
|
||||
buttonTooltip: 'Select an icon',
|
||||
availableIcons: TEST_ICONS,
|
||||
},
|
||||
global: {
|
||||
plugins: [router],
|
||||
components,
|
||||
stubs: ['N8nButton'],
|
||||
stubs: ['N8nIcon', 'N8nButton'],
|
||||
},
|
||||
});
|
||||
await fireEvent.click(getByTestId('icon-picker-button'));
|
||||
// Select the first icon
|
||||
await fireEvent.click(getAllByTestId('icon-picker-icon')[0]);
|
||||
// Icon should be selected and popup should be closed
|
||||
expect(getByTestId('icon-picker-button')).toHaveAttribute('icon', TEST_ICONS[0]);
|
||||
expect(getByTestId('icon-picker-button')).toHaveAttribute('icon', ALL_ICON_PICKER_ICONS[0]);
|
||||
expect(queryByTestId('icon-picker-popup')).toBeNull();
|
||||
expect(emitted()).toHaveProperty('update:modelValue');
|
||||
// Should emit the selected icon
|
||||
expect((emitted()['update:modelValue'] as unknown[][])[0][0]).toEqual({
|
||||
type: 'icon',
|
||||
value: TEST_ICONS[0],
|
||||
value: ALL_ICON_PICKER_ICONS[0],
|
||||
});
|
||||
});
|
||||
|
||||
it('is able to select an emoji', async () => {
|
||||
const { getByTestId, getAllByTestId, queryByTestId, emitted } = render(IconPicker, {
|
||||
props: {
|
||||
modelValue: { type: 'emoji', value: '🔥' },
|
||||
buttonTooltip: 'Select an emoji',
|
||||
availableIcons: TEST_ICONS,
|
||||
},
|
||||
global: {
|
||||
plugins: [router],
|
||||
components,
|
||||
stubs: ['N8nIcon'],
|
||||
},
|
||||
});
|
||||
await fireEvent.click(getByTestId('icon-picker-button'));
|
||||
@@ -174,6 +170,7 @@ describe('IconPicker', () => {
|
||||
expect(getByTestId('icon-picker-popup')).toBeVisible();
|
||||
// Select the first emoji
|
||||
await fireEvent.click(getAllByTestId('icon-picker-emoji')[0]);
|
||||
|
||||
// Emoji should be selected and popup should be closed
|
||||
expect(getByTestId('icon-picker-button')).toHaveTextContent('😀');
|
||||
expect(queryByTestId('icon-picker-popup')).toBeNull();
|
||||
|
||||
@@ -5,6 +5,8 @@ import { onClickOutside } from '@vueuse/core';
|
||||
import { isEmojiSupported } from 'is-emoji-supported';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import { ALL_ICON_PICKER_ICONS } from './constants';
|
||||
import type { IconOrEmoji } from './types';
|
||||
import { useI18n } from '../../composables/useI18n';
|
||||
import N8nButton from '../N8nButton';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
@@ -31,27 +33,18 @@ const emojiRanges = [
|
||||
[0x1f400, 0x1f4ff], // Additional pictographs
|
||||
];
|
||||
|
||||
export type Icon = {
|
||||
type: 'icon' | 'emoji';
|
||||
value: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
buttonTooltip: string;
|
||||
availableIcons: string[];
|
||||
buttonSize?: 'small' | 'large';
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
availableIcons: () => [],
|
||||
buttonSize: 'large',
|
||||
});
|
||||
|
||||
const model = defineModel<Icon>({ default: { type: 'icon', value: 'smile' } });
|
||||
|
||||
const hasAvailableIcons = computed(() => props.availableIcons.length > 0);
|
||||
const model = defineModel<IconOrEmoji>({ default: { type: 'icon', value: 'smile' } });
|
||||
|
||||
const emojis = computed(() => {
|
||||
const emojisArray: string[] = [];
|
||||
@@ -67,15 +60,11 @@ const emojis = computed(() => {
|
||||
});
|
||||
|
||||
const popupVisible = ref(false);
|
||||
const tabs = ref<Array<{ value: string; label: string }>>(
|
||||
hasAvailableIcons.value
|
||||
? [
|
||||
{ value: 'icons', label: t('iconPicker.tabs.icons') },
|
||||
{ value: 'emojis', label: t('iconPicker.tabs.emojis') },
|
||||
]
|
||||
: [{ value: 'emojis', label: t('iconPicker.tabs.emojis') }],
|
||||
);
|
||||
const selectedTab = ref<string>(tabs.value[0].value);
|
||||
const tabs: Array<{ value: string; label: string }> = [
|
||||
{ value: 'icons', label: t('iconPicker.tabs.icons') },
|
||||
{ value: 'emojis', label: t('iconPicker.tabs.emojis') },
|
||||
];
|
||||
const selectedTab = ref<string>(tabs[0].value);
|
||||
|
||||
const container = ref<HTMLDivElement>();
|
||||
|
||||
@@ -83,7 +72,7 @@ onClickOutside(container, () => {
|
||||
popupVisible.value = false;
|
||||
});
|
||||
|
||||
const selectIcon = (value: Icon) => {
|
||||
const selectIcon = (value: IconOrEmoji) => {
|
||||
model.value = value;
|
||||
popupVisible.value = false;
|
||||
};
|
||||
@@ -91,7 +80,7 @@ const selectIcon = (value: Icon) => {
|
||||
const togglePopup = () => {
|
||||
popupVisible.value = !popupVisible.value;
|
||||
if (popupVisible.value) {
|
||||
selectedTab.value = tabs.value[0].value;
|
||||
selectedTab.value = tabs[0].value;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -112,7 +101,7 @@ const togglePopup = () => {
|
||||
<N8nIconButton
|
||||
v-if="model.type === 'icon'"
|
||||
:class="$style['icon-button']"
|
||||
:icon="model.value ?? 'smile'"
|
||||
:icon="model.value"
|
||||
:size="buttonSize"
|
||||
:square="true"
|
||||
type="tertiary"
|
||||
@@ -138,11 +127,11 @@ const togglePopup = () => {
|
||||
</div>
|
||||
<div v-if="selectedTab === 'icons'" :class="$style.content">
|
||||
<N8nIcon
|
||||
v-for="icon in availableIcons"
|
||||
v-for="icon in ALL_ICON_PICKER_ICONS"
|
||||
:key="icon"
|
||||
:icon="icon"
|
||||
:class="$style.icon"
|
||||
size="large"
|
||||
:size="24"
|
||||
data-test-id="icon-picker-icon"
|
||||
@click="selectIcon({ type: 'icon', value: icon })"
|
||||
/>
|
||||
|
||||
@@ -1,163 +1,184 @@
|
||||
export const TEST_ICONS = [
|
||||
'angle-double-left',
|
||||
'angle-down',
|
||||
'angle-left',
|
||||
'angle-right',
|
||||
'angle-up',
|
||||
import type { IconName } from '../N8nIcon/icons';
|
||||
|
||||
export const ALL_ICON_PICKER_ICONS: IconName[] = [
|
||||
'folder-plus',
|
||||
'share',
|
||||
'user-check',
|
||||
'check-check',
|
||||
'circle',
|
||||
'eye-off',
|
||||
'folder',
|
||||
'circle-minus',
|
||||
'contrast',
|
||||
'refresh-cw',
|
||||
'vault',
|
||||
'chevrons-left',
|
||||
'archive',
|
||||
'arrow-left',
|
||||
'arrow-right',
|
||||
'arrow-up',
|
||||
'arrow-down',
|
||||
'at',
|
||||
'at-sign',
|
||||
'ban',
|
||||
'balance-scale-left',
|
||||
'bars',
|
||||
'bolt',
|
||||
'scale',
|
||||
'menu',
|
||||
'zap',
|
||||
'book',
|
||||
'box-open',
|
||||
'package-open',
|
||||
'bug',
|
||||
'brain',
|
||||
'calculator',
|
||||
'calendar',
|
||||
'chart-bar',
|
||||
'chart-column-decreasing',
|
||||
'check',
|
||||
'check-circle',
|
||||
'check-square',
|
||||
'circle-check',
|
||||
'square-check',
|
||||
'chevron-left',
|
||||
'chevron-right',
|
||||
'chevron-down',
|
||||
'chevron-up',
|
||||
'code',
|
||||
'code-branch',
|
||||
'git-branch',
|
||||
'cog',
|
||||
'cogs',
|
||||
'comment',
|
||||
'comments',
|
||||
'message-circle',
|
||||
'messages-square',
|
||||
'clipboard-list',
|
||||
'clock',
|
||||
'clone',
|
||||
'cloud',
|
||||
'cloud-download-alt',
|
||||
'copy',
|
||||
'cube',
|
||||
'cut',
|
||||
'cloud',
|
||||
'cloud-download',
|
||||
'files',
|
||||
'box',
|
||||
'scissors',
|
||||
'database',
|
||||
'dot-circle',
|
||||
'circle-dot',
|
||||
'grip-lines-vertical',
|
||||
'grip-vertical',
|
||||
'edit',
|
||||
'ellipsis-h',
|
||||
'ellipsis-v',
|
||||
'envelope',
|
||||
'equals',
|
||||
'square-pen',
|
||||
'ellipsis',
|
||||
'ellipsis-vertical',
|
||||
'mail',
|
||||
'equal',
|
||||
'eye',
|
||||
'exclamation-triangle',
|
||||
'expand',
|
||||
'expand-alt',
|
||||
'external-link-alt',
|
||||
'exchange-alt',
|
||||
'triangle-alert',
|
||||
'maximize',
|
||||
'maximize-2',
|
||||
'external-link',
|
||||
'arrow-left-right',
|
||||
'file',
|
||||
'file-alt',
|
||||
'file-text',
|
||||
'file-archive',
|
||||
'file-code',
|
||||
'file-download',
|
||||
'file-export',
|
||||
'file-import',
|
||||
'file-pdf',
|
||||
'filter',
|
||||
'file-down',
|
||||
'file-output',
|
||||
'file-input',
|
||||
'file-text',
|
||||
'funnel',
|
||||
'fingerprint',
|
||||
'flask',
|
||||
'flask-conical',
|
||||
'folder-open',
|
||||
'font',
|
||||
'case-upper',
|
||||
'gift',
|
||||
'globe',
|
||||
'globe-americas',
|
||||
'earth',
|
||||
'graduation-cap',
|
||||
'hand-holding-usd',
|
||||
'hand-scissors',
|
||||
'hand-coins',
|
||||
'scissors',
|
||||
'handshake',
|
||||
'hand-point-left',
|
||||
'hashtag',
|
||||
'hdd',
|
||||
'arrow-left',
|
||||
'hash',
|
||||
'hard-drive',
|
||||
'history',
|
||||
'home',
|
||||
'house',
|
||||
'hourglass',
|
||||
'image',
|
||||
'inbox',
|
||||
'info',
|
||||
'info-circle',
|
||||
'key',
|
||||
'language',
|
||||
'layer-group',
|
||||
'key-round',
|
||||
'languages',
|
||||
'layers',
|
||||
'link',
|
||||
'list',
|
||||
'lightbulb',
|
||||
'lock',
|
||||
'map-signs',
|
||||
'milestone',
|
||||
'mouse-pointer',
|
||||
'network-wired',
|
||||
'network',
|
||||
'palette',
|
||||
'pause',
|
||||
'pause-circle',
|
||||
'circle-pause',
|
||||
'pen',
|
||||
'pencil-alt',
|
||||
'pencil',
|
||||
'play',
|
||||
'play-circle',
|
||||
'circle-play',
|
||||
'plug',
|
||||
'plus',
|
||||
'plus-circle',
|
||||
'plus-square',
|
||||
'project-diagram',
|
||||
'question',
|
||||
'question-circle',
|
||||
'redo',
|
||||
'remove-format',
|
||||
'robot',
|
||||
'circle-plus',
|
||||
'square-plus',
|
||||
'waypoints',
|
||||
'circle-help',
|
||||
'circle-help',
|
||||
'redo-2',
|
||||
'remove-formatting',
|
||||
'bot',
|
||||
'rss',
|
||||
'save',
|
||||
'satellite-dish',
|
||||
'search',
|
||||
'search-minus',
|
||||
'search-plus',
|
||||
'zoom-out',
|
||||
'zoom-in',
|
||||
'server',
|
||||
'screwdriver',
|
||||
'pocket-knife',
|
||||
'smile',
|
||||
'sign-in-alt',
|
||||
'sign-out-alt',
|
||||
'sliders-h',
|
||||
'spinner',
|
||||
'log-in',
|
||||
'log-out',
|
||||
'sliders-horizontal',
|
||||
'sticky-note',
|
||||
'stop',
|
||||
'stream',
|
||||
'square',
|
||||
'align-right',
|
||||
'sun',
|
||||
'sync',
|
||||
'sync-alt',
|
||||
'refresh-cw',
|
||||
'table',
|
||||
'tags',
|
||||
'tasks',
|
||||
'list-checks',
|
||||
'terminal',
|
||||
'th-large',
|
||||
'thumbtack',
|
||||
'grid-2x2',
|
||||
'pin',
|
||||
'thumbs-down',
|
||||
'thumbs-up',
|
||||
'times',
|
||||
'times-circle',
|
||||
'toolbox',
|
||||
'tools',
|
||||
'trash',
|
||||
'undo',
|
||||
'x',
|
||||
'circle-x',
|
||||
'wrench',
|
||||
'trash-2',
|
||||
'undo-2',
|
||||
'unlink',
|
||||
'user',
|
||||
'user-circle',
|
||||
'user-friends',
|
||||
'circle-user-round',
|
||||
'user-round',
|
||||
'users',
|
||||
'vector-square',
|
||||
'video',
|
||||
'tree',
|
||||
'tree-pine',
|
||||
'user-lock',
|
||||
'gem',
|
||||
'download',
|
||||
'power-off',
|
||||
'paper-plane',
|
||||
'hard-drive-download',
|
||||
'power',
|
||||
'send',
|
||||
'bell',
|
||||
'variable',
|
||||
'pop-out',
|
||||
'triangle',
|
||||
'status-completed',
|
||||
'status-waiting',
|
||||
'status-error',
|
||||
'status-canceled',
|
||||
'status-new',
|
||||
'status-unknown',
|
||||
'status-warning',
|
||||
'vector-square',
|
||||
'schema',
|
||||
'json',
|
||||
'binary',
|
||||
'text',
|
||||
'toolbox',
|
||||
'spinner',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
|
||||
export type IconOrEmoji =
|
||||
| {
|
||||
type: 'icon';
|
||||
value: IconName;
|
||||
}
|
||||
| {
|
||||
type: 'emoji';
|
||||
value: string;
|
||||
};
|
||||
|
||||
export function isIconOrEmoji(icon: unknown): icon is IconOrEmoji {
|
||||
return (
|
||||
typeof icon === 'object' &&
|
||||
icon !== null &&
|
||||
'type' in icon &&
|
||||
(icon.type === 'icon' || icon.type === 'emoji') &&
|
||||
'value' in icon &&
|
||||
typeof icon.value === 'string'
|
||||
);
|
||||
}
|
||||
@@ -5,13 +5,14 @@ import { onMounted, ref } from 'vue';
|
||||
import type { IconColor } from '@n8n/design-system/types/icon';
|
||||
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
import N8nText from '../N8nText';
|
||||
import N8nTooltip from '../N8nTooltip';
|
||||
|
||||
export interface IAccordionItem {
|
||||
id: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
icon: IconName;
|
||||
iconColor?: IconColor;
|
||||
tooltip?: string | null;
|
||||
}
|
||||
@@ -21,7 +22,7 @@ interface InfoAccordionProps {
|
||||
description?: string;
|
||||
items?: IAccordionItem[];
|
||||
initiallyExpanded?: boolean;
|
||||
headerIcon?: { icon: string; color: IconColor };
|
||||
headerIcon?: { icon: IconName; color: IconColor };
|
||||
eventBus?: EventBus;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import N8nInfoTip from './InfoTip.vue';
|
||||
const slots = {
|
||||
default: ['Need help doing something?', '<a href="/docs" target="_blank">Open docs</a>'],
|
||||
};
|
||||
const stubs = ['n8n-tooltip'];
|
||||
const stubs = ['n8n-tooltip', 'n8n-icon'];
|
||||
|
||||
describe('N8nInfoTip', () => {
|
||||
it('should render correctly as note', () => {
|
||||
@@ -30,4 +30,17 @@ describe('N8nInfoTip', () => {
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render correctly with a specific size', () => {
|
||||
const wrapper = render(N8nInfoTip, {
|
||||
slots,
|
||||
props: {
|
||||
size: 'large',
|
||||
},
|
||||
global: {
|
||||
stubs,
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,23 +2,25 @@
|
||||
import type { Placement } from 'element-plus';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import type { IconSize } from '@n8n/design-system/types';
|
||||
import type { IconColor } from '@n8n/design-system/types/icon';
|
||||
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
import N8nTooltip from '../N8nTooltip';
|
||||
|
||||
const THEME = ['info', 'info-light', 'warning', 'warning-light', 'danger', 'success'] as const;
|
||||
const TYPE = ['note', 'tooltip'] as const;
|
||||
|
||||
const ICON_MAP = {
|
||||
info: 'info-circle',
|
||||
const ICON_MAP: { [name: string]: IconName } = {
|
||||
info: 'info',
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'info-light': 'info-circle',
|
||||
warning: 'exclamation-triangle',
|
||||
'info-light': 'info',
|
||||
warning: 'triangle-alert',
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'warning-light': 'triangle', // NOTE: This requires a custom icon
|
||||
danger: 'exclamation-triangle',
|
||||
success: 'check-circle',
|
||||
danger: 'triangle-alert',
|
||||
success: 'circle-check',
|
||||
} as const;
|
||||
|
||||
const COLOR_MAP: Record<keyof IconMap, IconColor> = {
|
||||
@@ -40,6 +42,7 @@ interface InfoTipProps {
|
||||
bold?: boolean;
|
||||
tooltipPlacement?: Placement;
|
||||
enterable?: boolean;
|
||||
size?: IconSize;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'N8nInfoTip' });
|
||||
@@ -49,9 +52,10 @@ const props = withDefaults(defineProps<InfoTipProps>(), {
|
||||
bold: true,
|
||||
tooltipPlacement: 'top',
|
||||
enterable: true,
|
||||
size: undefined,
|
||||
});
|
||||
|
||||
const iconData = computed<{ icon: IconMap[keyof IconMap]; color: IconColor }>(() => {
|
||||
const iconData = computed<{ icon: IconName; color: IconColor }>(() => {
|
||||
return {
|
||||
icon: ICON_MAP[props.theme],
|
||||
color: COLOR_MAP[props.theme],
|
||||
@@ -79,7 +83,7 @@ const iconData = computed<{ icon: IconMap[keyof IconMap]; color: IconColor }>(()
|
||||
:enterable
|
||||
>
|
||||
<span :class="$style.iconText">
|
||||
<N8nIcon :icon="iconData.icon" :color="iconData.color" />
|
||||
<N8nIcon :icon="iconData.icon" :color="iconData.color" :size="size" />
|
||||
</span>
|
||||
<template #content>
|
||||
<span>
|
||||
@@ -88,7 +92,7 @@ const iconData = computed<{ icon: IconMap[keyof IconMap]; color: IconColor }>(()
|
||||
</template>
|
||||
</N8nTooltip>
|
||||
<span v-else :class="$style.iconText">
|
||||
<N8nIcon :icon="iconData.icon" :color="iconData.color" />
|
||||
<N8nIcon :icon="iconData.icon" :color="iconData.color" :size="size" />
|
||||
<span>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
@@ -3,15 +3,22 @@
|
||||
exports[`N8nInfoTip > should render correctly as note 1`] = `
|
||||
"<div class="n8n-info-tip infoTip info note bold">
|
||||
<!-- Note that the branching is required to support displaying
|
||||
the slot either in the tooltip of the icon or following it --><span class="iconText"><span class="n8n-text text-base compact size-medium regular n8n-icon n8n-icon"><!----></span><span>Need help doing something?<a href="/docs" target="_blank">Open docs</a></span></span>
|
||||
the slot either in the tooltip of the icon or following it --><span class="iconText"><n8n-icon-stub icon="info" spin="false" color="text-base"></n8n-icon-stub><span>Need help doing something?<a href="/docs" target="_blank">Open docs</a></span></span>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`N8nInfoTip > should render correctly as tooltip 1`] = `
|
||||
"<div class="n8n-info-tip infoTip info tooltip bold">
|
||||
<!-- Note that the branching is required to support displaying
|
||||
the slot either in the tooltip of the icon or following it --><span class="iconText el-tooltip__trigger el-tooltip__trigger"><span class="n8n-text text-base compact size-medium regular n8n-icon n8n-icon"><!----></span></span>
|
||||
the slot either in the tooltip of the icon or following it --><span class="iconText el-tooltip__trigger el-tooltip__trigger"><n8n-icon-stub icon="info" spin="false" color="text-base"></n8n-icon-stub></span>
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`N8nInfoTip > should render correctly with a specific size 1`] = `
|
||||
"<div class="n8n-info-tip infoTip info note bold">
|
||||
<!-- Note that the branching is required to support displaying
|
||||
the slot either in the tooltip of the icon or following it --><span class="iconText"><n8n-icon-stub icon="info" size="large" spin="false" color="text-base"></n8n-icon-stub><span>Need help doing something?<a href="/docs" target="_blank">Open docs</a></span></span>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
@@ -74,7 +74,7 @@ const addTargetBlank = (html: string) =>
|
||||
:class="[$style.infoIcon, showTooltip ? $style.visible : $style.hidden]"
|
||||
>
|
||||
<N8nTooltip placement="top" :popper-class="$style.tooltipPopper" :show-after="300">
|
||||
<N8nIcon :class="$style.icon" icon="question-circle" size="small" />
|
||||
<N8nIcon :class="$style.icon" icon="circle-help" size="small" />
|
||||
<template #content>
|
||||
<div v-n8n-html="addTargetBlank(tooltipText)" />
|
||||
</template>
|
||||
|
||||
@@ -48,7 +48,7 @@ const templateWithHeaderAndFooter: StoryFn = (args, { argTypes }) => ({
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="p-m hideme">
|
||||
<n8n-icon icon="user-circle" size="xlarge"/>
|
||||
<n8n-icon icon="circle-user-round" size="xlarge"/>
|
||||
<n8n-text>John Smithson</n8n-text>
|
||||
</div>
|
||||
</template>
|
||||
@@ -82,7 +82,7 @@ const templateWithAllSlots: StoryFn = (args, { argTypes }) => ({
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="p-m hideme">
|
||||
<n8n-icon icon="user-circle" size="xlarge"/>
|
||||
<n8n-icon icon="circle-user-round" size="xlarge"/>
|
||||
<n8n-text>John Smithson</n8n-text>
|
||||
</div>
|
||||
</template>
|
||||
@@ -95,7 +95,7 @@ const templateWithAllSlots: StoryFn = (args, { argTypes }) => ({
|
||||
const menuItems = [
|
||||
{
|
||||
id: 'workflows',
|
||||
icon: 'network-wired',
|
||||
icon: 'network',
|
||||
label: 'Workflows',
|
||||
position: 'top',
|
||||
},
|
||||
@@ -107,7 +107,7 @@ const menuItems = [
|
||||
},
|
||||
{
|
||||
id: 'disabled-item',
|
||||
icon: 'times',
|
||||
icon: 'x',
|
||||
label: 'Not Available',
|
||||
available: false,
|
||||
position: 'top',
|
||||
@@ -132,7 +132,7 @@ const menuItems = [
|
||||
{ icon: 'book', label: 'Documentation', id: 'docs' },
|
||||
{
|
||||
id: 'disabled-submenu-item',
|
||||
icon: 'times',
|
||||
icon: 'x',
|
||||
label: 'Not Available',
|
||||
available: false,
|
||||
position: 'top',
|
||||
|
||||
@@ -28,7 +28,7 @@ export const defaultMenuItem = template.bind({});
|
||||
defaultMenuItem.args = {
|
||||
item: {
|
||||
id: 'workflows',
|
||||
icon: 'heart',
|
||||
icon: 'home',
|
||||
label: 'Workflows',
|
||||
},
|
||||
};
|
||||
@@ -37,7 +37,7 @@ export const withSecondaryIcon = template.bind({});
|
||||
withSecondaryIcon.args = {
|
||||
item: {
|
||||
id: 'workflows',
|
||||
icon: 'heart',
|
||||
icon: 'home',
|
||||
label: 'Workflows',
|
||||
secondaryIcon: { name: 'lock', size: 'small' },
|
||||
},
|
||||
@@ -47,7 +47,7 @@ export const withSecondaryIconTooltip = template.bind({});
|
||||
withSecondaryIconTooltip.args = {
|
||||
item: {
|
||||
id: 'workflows',
|
||||
icon: 'heart',
|
||||
icon: 'home',
|
||||
label: 'Workflows',
|
||||
secondaryIcon: {
|
||||
name: 'lock',
|
||||
|
||||
@@ -5,12 +5,13 @@ import type { RouteLocationRaw } from 'vue-router';
|
||||
|
||||
import ConditionalRouterLink from '../ConditionalRouterLink';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import { type IconName } from '../N8nIcon/icons';
|
||||
|
||||
type BaseItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
disabled?: boolean;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
route?: RouteLocationRaw;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { ElTag } from 'element-plus';
|
||||
|
||||
import { useI18n } from '../../composables/useI18n';
|
||||
import type { NodeCreatorTag } from '../../types/node-creator-node';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
|
||||
export interface Props {
|
||||
active?: boolean;
|
||||
@@ -44,10 +44,10 @@ const { t } = useI18n();
|
||||
<ElTag v-if="tag" :class="$style.tag" size="small" round :type="tag.type ?? 'success'">
|
||||
{{ tag.text }}
|
||||
</ElTag>
|
||||
<FontAwesomeIcon
|
||||
<N8nIcon
|
||||
v-if="isTrigger"
|
||||
icon="bolt"
|
||||
size="xs"
|
||||
icon="zap"
|
||||
size="xsmall"
|
||||
:title="t('nodeCreator.nodeItem.triggerIconTitle')"
|
||||
:class="$style.triggerIcon"
|
||||
/>
|
||||
@@ -63,7 +63,7 @@ const { t } = useI18n();
|
||||
</div>
|
||||
<slot name="dragContent" />
|
||||
<button v-if="showActionArrow" :class="$style.panelIcon">
|
||||
<FontAwesomeIcon :class="$style.panelArrow" icon="arrow-right" />
|
||||
<N8nIcon icon="arrow-right" size="large" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -110,10 +110,6 @@ const { t } = useI18n();
|
||||
color: var(--color-text-base);
|
||||
font-size: var(--font-size-2xs);
|
||||
}
|
||||
.panelArrow {
|
||||
font-size: var(--font-size-2xs);
|
||||
width: 12px;
|
||||
}
|
||||
.details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -26,14 +26,14 @@ FileIcon.args = {
|
||||
export const FontIcon = DefaultTemplate.bind({});
|
||||
FontIcon.args = {
|
||||
type: 'icon',
|
||||
name: 'cogs',
|
||||
name: 'cog',
|
||||
size: 200,
|
||||
};
|
||||
|
||||
export const Hoverable = DefaultTemplate.bind({});
|
||||
Hoverable.args = {
|
||||
type: 'icon',
|
||||
name: 'heart',
|
||||
name: 'home',
|
||||
color: 'red',
|
||||
size: 200,
|
||||
nodeTypeName: 'We ❤️ n8n',
|
||||
|
||||
@@ -3,6 +3,9 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import type { Placement } from 'element-plus';
|
||||
import { computed, getCurrentInstance } from 'vue';
|
||||
|
||||
import N8nIcon from '../N8nIcon';
|
||||
import type { IconName } from '../N8nIcon/icons';
|
||||
import { isSupportedIconName } from '../N8nIcon/icons';
|
||||
import N8nTooltip from '../N8nTooltip';
|
||||
|
||||
type IconType = 'file' | 'icon' | 'unknown';
|
||||
@@ -19,6 +22,8 @@ interface NodeIconProps {
|
||||
showTooltip?: boolean;
|
||||
tooltipPosition?: Placement;
|
||||
badge?: { src: string; type: IconType };
|
||||
// temporarily until we roll out FA icons for all nodes
|
||||
useUpdatedIcons?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<NodeIconProps>(), {
|
||||
@@ -72,6 +77,10 @@ const badgeStyleData = computed((): Record<string, string> => {
|
||||
};
|
||||
});
|
||||
|
||||
const updatedIconName = computed((): IconName | undefined => {
|
||||
return props.useUpdatedIcons && isSupportedIconName(props.name) ? props.name : undefined;
|
||||
});
|
||||
|
||||
// Get self component to avoid dependency cycle
|
||||
const N8nNodeIcon = getCurrentInstance()?.type;
|
||||
</script>
|
||||
@@ -88,7 +97,9 @@ const N8nNodeIcon = getCurrentInstance()?.type;
|
||||
>
|
||||
<!-- ElementUI tooltip is prone to memory-leaking so we only render it if we really need it -->
|
||||
<N8nTooltip v-if="showTooltip" :placement="tooltipPosition" :disabled="!showTooltip">
|
||||
<template #content>{{ nodeTypeName }}</template>
|
||||
<template #content>
|
||||
{{ nodeTypeName }}
|
||||
</template>
|
||||
<div v-if="type !== 'unknown'" :class="$style.icon">
|
||||
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
||||
<FontAwesomeIcon v-else :icon="`${name}`" :class="$style.iconFa" :style="fontStyleData" />
|
||||
@@ -100,6 +111,12 @@ const N8nNodeIcon = getCurrentInstance()?.type;
|
||||
<template v-else>
|
||||
<div v-if="type !== 'unknown'" :class="$style.icon">
|
||||
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
||||
<N8nIcon
|
||||
v-else-if="updatedIconName"
|
||||
:icon="updatedIconName"
|
||||
:style="fontStyleData"
|
||||
size="xlarge"
|
||||
/>
|
||||
<FontAwesomeIcon v-else :icon="`${name}`" :style="fontStyleData" />
|
||||
<div v-if="badge" :class="$style.badge" :style="badgeStyleData">
|
||||
<N8nNodeIcon :type="badge.type" :src="badge.src" :size="badgeSize" />
|
||||
|
||||
@@ -19,6 +19,9 @@ describe('N8nSelectableList', () => {
|
||||
modelValue: {},
|
||||
inputs: [{ name: 'propA', initialValue: '' }],
|
||||
},
|
||||
global: {
|
||||
stubs: ['n8n-icon'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.getByTestId('selectable-list-selectable-propA')).toBeInTheDocument();
|
||||
@@ -49,6 +52,9 @@ describe('N8nSelectableList', () => {
|
||||
{ name: 'propA', initialValue: '' },
|
||||
],
|
||||
},
|
||||
global: {
|
||||
stubs: ['n8n-icon'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.queryByTestId('selectable-list-selectable-propA')).not.toBeInTheDocument();
|
||||
@@ -87,6 +93,9 @@ describe('N8nSelectableList', () => {
|
||||
{ name: 'propC', initialValue: '' },
|
||||
],
|
||||
},
|
||||
global: {
|
||||
stubs: ['n8n-icon'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.queryByTestId('selectable-list-selectable-propA')).not.toBeInTheDocument();
|
||||
|
||||
@@ -87,9 +87,10 @@ function itemComparator(a: Item, b: Item) {
|
||||
:data-test-id="`selectable-list-slot-${item.name}`"
|
||||
>
|
||||
<N8nIcon
|
||||
v-if="!disabled"
|
||||
:class="$style.slotRemoveIcon"
|
||||
size="xsmall"
|
||||
:icon="disabled ? 'none' : 'trash'"
|
||||
icon="trash-2"
|
||||
:data-test-id="`selectable-list-remove-slot-${item.name}`"
|
||||
@click="!disabled && removeFromSelectedItems(item.name)"
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
exports[`N8nSelectableList > renders disabled collection without selectables 1`] = `
|
||||
"<div>
|
||||
<!--v-if-->
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propB"><span class="n8n-text compact size-xsmall regular n8n-icon slotRemoveIcon slotRemoveIcon n8n-icon slotRemoveIcon slotRemoveIcon" data-test-id="selectable-list-remove-slot-propB"><!----></span>
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propB">
|
||||
<!--v-if-->
|
||||
<div class="slotContainer"></div>
|
||||
</div>
|
||||
</div>"
|
||||
@@ -12,10 +13,12 @@ exports[`N8nSelectableList > renders disabled collection without selectables 1`]
|
||||
exports[`N8nSelectableList > renders multiple elements with some pre-selected 1`] = `
|
||||
"<div>
|
||||
<div class="selectableContainer"><span class="selectableCell" data-test-id="selectable-list-selectable-propB"><div class="selectableTextSize">+ Add a propB</div></span><span class="selectableCell" data-test-id="selectable-list-selectable-propD"><div class="selectableTextSize">+ Add a propD</div></span></div>
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propA"><span class="n8n-text compact size-xsmall regular n8n-icon slotRemoveIcon slotRemoveIcon n8n-icon slotRemoveIcon slotRemoveIcon" data-test-id="selectable-list-remove-slot-propA"><!----></span>
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propA">
|
||||
<n8n-icon-stub icon="trash-2" size="xsmall" spin="false" class="slotRemoveIcon" data-test-id="selectable-list-remove-slot-propA"></n8n-icon-stub>
|
||||
<div class="slotContainer"></div>
|
||||
</div>
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propC"><span class="n8n-text compact size-xsmall regular n8n-icon slotRemoveIcon slotRemoveIcon n8n-icon slotRemoveIcon slotRemoveIcon" data-test-id="selectable-list-remove-slot-propC"><!----></span>
|
||||
<div class="slotComboContainer" data-test-id="selectable-list-slot-propC">
|
||||
<n8n-icon-stub icon="trash-2" size="xsmall" spin="false" class="slotRemoveIcon" data-test-id="selectable-list-remove-slot-propC"></n8n-icon-stub>
|
||||
<div class="slotContainer"></div>
|
||||
</div>
|
||||
</div>"
|
||||
|
||||
@@ -97,7 +97,7 @@ const scrollRight = () => scroll(50);
|
||||
<div>
|
||||
{{ option.label }}
|
||||
<span :class="$style.external">
|
||||
<N8nIcon icon="external-link-alt" size="xsmall" />
|
||||
<N8nIcon icon="external-link" size="small" />
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import type { KeyboardShortcut } from '@n8n/design-system/types/keyboardshortcut';
|
||||
|
||||
import type { IconName } from '../components/N8nIcon/icons';
|
||||
|
||||
export interface ActionDropdownItem {
|
||||
id: string;
|
||||
label: string;
|
||||
badge?: string;
|
||||
badgeProps?: Record<string, unknown>;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
divided?: boolean;
|
||||
disabled?: boolean;
|
||||
shortcut?: KeyboardShortcut;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type IconSize } from './icon';
|
||||
import type { TextFloat } from './text';
|
||||
import type { IconName } from '../components/N8nIcon/icons';
|
||||
|
||||
const BUTTON_ELEMENT = ['button', 'a'] as const;
|
||||
export type ButtonElement = (typeof BUTTON_ELEMENT)[number];
|
||||
@@ -17,7 +18,7 @@ export interface IconButtonProps {
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
float?: TextFloat;
|
||||
icon?: string | string[];
|
||||
icon?: IconName;
|
||||
loading?: boolean;
|
||||
outline?: boolean;
|
||||
size?: ButtonSize;
|
||||
|
||||
@@ -3,13 +3,17 @@ import type { AnchorHTMLAttributes, Component } from 'vue';
|
||||
import type { RouteLocationRaw, RouterLinkProps } from 'vue-router';
|
||||
|
||||
import type { IconColor } from './icon';
|
||||
import type { IconName } from '../components/N8nIcon/icons';
|
||||
|
||||
export type IMenuItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
icon?: string | { type: 'icon' | 'emoji'; value: string; color?: IconColor };
|
||||
icon?:
|
||||
| IconName
|
||||
| { type: 'icon'; value: IconName; color?: IconColor }
|
||||
| { type: 'emoji'; value: string; color?: IconColor };
|
||||
secondaryIcon?: {
|
||||
name: string;
|
||||
name: IconName;
|
||||
size?: 'xsmall' | 'small' | 'medium' | 'large';
|
||||
tooltip?: Partial<ElTooltipProps>;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { RouteLocationRaw } from 'vue-router';
|
||||
|
||||
import type { IconName } from '../components/N8nIcon/icons';
|
||||
|
||||
export interface TabOptions<Value extends string | number> {
|
||||
value: Value;
|
||||
label?: string;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
href?: string;
|
||||
tooltip?: string;
|
||||
align?: 'left' | 'right';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"baseUrl": ".",
|
||||
"rootDirs": [".", "../composables/src"],
|
||||
"outDir": "dist",
|
||||
"types": ["vite/client", "vitest/globals"],
|
||||
"types": ["vite/client", "unplugin-icons/types/vue", "vitest/globals"],
|
||||
"typeRoots": [
|
||||
"./node_modules/@testing-library",
|
||||
"./node_modules/@types",
|
||||
|
||||
@@ -21,7 +21,7 @@ export default mergeConfig(
|
||||
dts: false,
|
||||
resolvers: [
|
||||
iconsResolver({
|
||||
prefix: 'icon',
|
||||
prefix: 'Icon',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@iconify/json": "^2.2.228",
|
||||
"@iconify/json": "^2.2.349",
|
||||
"@n8n/eslint-config": "workspace:*",
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
@@ -121,8 +121,8 @@
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
"fake-indexeddb": "^6.0.0",
|
||||
"miragejs": "^0.1.48",
|
||||
"unplugin-icons": "^0.19.0",
|
||||
"unplugin-vue-components": "^0.27.2",
|
||||
"unplugin-icons": "catalog:frontend",
|
||||
"unplugin-vue-components": "catalog:frontend",
|
||||
"vite": "catalog:",
|
||||
"vite-plugin-static-copy": "2.2.0",
|
||||
"vite-svg-loader": "5.1.0",
|
||||
|
||||
@@ -70,6 +70,7 @@ import type { BulkCommand, Undoable } from '@/models/history';
|
||||
|
||||
import type { ProjectSharingData } from '@/types/projects.types';
|
||||
import type { PathItem } from '@n8n/design-system/components/N8nBreadcrumbs/Breadcrumbs.vue';
|
||||
import { type IconName } from '@n8n/design-system/src/components/N8nIcon/icons';
|
||||
|
||||
export * from '@n8n/design-system/types';
|
||||
|
||||
@@ -668,7 +669,7 @@ export type SimplifiedNodeType = Pick<
|
||||
export interface SubcategoryItemProps {
|
||||
description?: string;
|
||||
iconType?: string;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
iconProps?: {
|
||||
color?: string;
|
||||
};
|
||||
@@ -1072,7 +1073,7 @@ export interface ITab<Value extends string | number = string | number> {
|
||||
value: Value;
|
||||
label?: string;
|
||||
href?: string;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
align?: 'right';
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ const onBlur = (): void => {
|
||||
type="tertiary"
|
||||
text
|
||||
size="mini"
|
||||
icon="trash"
|
||||
icon="trash-2"
|
||||
data-test-id="assignment-remove"
|
||||
:class="[$style.iconButton, $style.extraTopPadding]"
|
||||
@click="onRemove"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useI18n } from '@n8n/i18n';
|
||||
import type { BaseTextKey } from '@n8n/i18n';
|
||||
import { ASSIGNMENT_TYPES } from './constants';
|
||||
import { computed } from 'vue';
|
||||
import { type IconName } from '@n8n/design-system/components/N8nIcon/icons';
|
||||
|
||||
interface Props {
|
||||
modelValue: string;
|
||||
@@ -19,7 +20,9 @@ const i18n = useI18n();
|
||||
|
||||
const types = ASSIGNMENT_TYPES;
|
||||
|
||||
const icon = computed(() => types.find((type) => type.type === props.modelValue)?.icon ?? 'cube');
|
||||
const icon = computed(
|
||||
(): IconName => types.find((type) => type.type === props.modelValue)?.icon ?? 'box',
|
||||
);
|
||||
|
||||
const onTypeChange = (type: string): void => {
|
||||
emit('update:model-value', type);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export const ASSIGNMENT_TYPES = [
|
||||
{ type: 'string', icon: 'font' },
|
||||
{ type: 'number', icon: 'hashtag' },
|
||||
{ type: 'boolean', icon: 'check-square' },
|
||||
import { type IconName } from '@n8n/design-system/components/N8nIcon/icons';
|
||||
|
||||
export const ASSIGNMENT_TYPES: Array<{ type: string; icon: IconName }> = [
|
||||
{ type: 'string', icon: 'case-upper' },
|
||||
{ type: 'number', icon: 'hash' },
|
||||
{ type: 'boolean', icon: 'square-check' },
|
||||
{ type: 'array', icon: 'list' },
|
||||
{ type: 'object', icon: 'cube' },
|
||||
{ type: 'object', icon: 'box' },
|
||||
];
|
||||
|
||||
@@ -37,8 +37,8 @@ const onClick = () => {
|
||||
|
||||
<template>
|
||||
<el-tag :type="theme" :disable-transitions="true" :class="$style.container">
|
||||
<font-awesome-icon
|
||||
:icon="theme === 'success' ? 'check-circle' : 'exclamation-triangle'"
|
||||
<n8n-icon
|
||||
:icon="theme === 'success' ? 'circle-check' : 'triangle-alert'"
|
||||
:class="theme === 'success' ? $style.icon : $style.dangerIcon"
|
||||
/>
|
||||
<div :class="$style.banner">
|
||||
|
||||
@@ -28,7 +28,7 @@ const onClick = () => {
|
||||
data-test-id="close-become-template-creator-cta"
|
||||
@click="store.dismissCta()"
|
||||
>
|
||||
<n8n-icon icon="times" size="xsmall" :title="i18n.baseText('generic.close')" />
|
||||
<n8n-icon icon="x" size="xsmall" :title="i18n.baseText('generic.close')" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ onMounted(() => {
|
||||
v-text="`${prompt.length} / ${ASK_AI_MAX_PROMPT_LENGTH}`"
|
||||
/>
|
||||
<a href="https://docs.n8n.io/code-examples/ai-code" target="_blank" :class="$style.help">
|
||||
<n8n-icon icon="question-circle" color="text-light" size="large" />{{
|
||||
<n8n-icon icon="circle-help" color="text-light" size="large" />{{
|
||||
i18n.baseText('codeNodeEditor.askAi.help')
|
||||
}}
|
||||
</a>
|
||||
|
||||
@@ -133,7 +133,7 @@ watch(
|
||||
{{ i18n.baseText('settings.communityNodes.failedToLoad.tooltip') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-icon icon="exclamation-triangle" color="danger" size="large" />
|
||||
<n8n-icon icon="triangle-alert" color="danger" size="large" />
|
||||
</n8n-tooltip>
|
||||
<n8n-tooltip
|
||||
v-else-if="hasUnverifiedPackagesUpdate || hasVerifiedPackageUpdate"
|
||||
@@ -152,7 +152,7 @@ watch(
|
||||
{{ i18n.baseText('settings.communityNodes.upToDate.tooltip') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-icon icon="check-circle" color="text-light" size="large" />
|
||||
<n8n-icon icon="circle-check" color="text-light" size="large" />
|
||||
</n8n-tooltip>
|
||||
<div :class="$style.cardActions">
|
||||
<n8n-action-toggle :actions="packageActions" @action="onAction"></n8n-action-toggle>
|
||||
|
||||
@@ -110,7 +110,7 @@ const onLearnMoreLinkClick = () => {
|
||||
</div>
|
||||
<n8n-button
|
||||
:label="i18n.baseText('settings.communityNodes.browseButton.label')"
|
||||
icon="external-link-alt"
|
||||
icon="external-link"
|
||||
:class="$style.browseButton"
|
||||
@click="openNPMPage"
|
||||
/>
|
||||
|
||||
@@ -225,7 +225,7 @@ watch(showOAuthSuccessBanner, (newValue, oldValue) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n8n-callout v-if="isManaged" theme="warning" icon="exclamation-triangle">
|
||||
<n8n-callout v-if="isManaged" theme="warning" icon="triangle-alert">
|
||||
{{ i18n.baseText('freeAi.credits.credentials.edit') }}
|
||||
</n8n-callout>
|
||||
<div v-else>
|
||||
|
||||
@@ -1106,7 +1106,7 @@ const { width } = useElementSize(credNameRef);
|
||||
<n8n-icon-button
|
||||
v-if="currentCredential && credentialPermissions.delete"
|
||||
:title="i18n.baseText('credentialEdit.credentialEdit.delete')"
|
||||
icon="trash"
|
||||
icon="trash-2"
|
||||
type="tertiary"
|
||||
:disabled="isSaving"
|
||||
:loading="isDeleting"
|
||||
|
||||
@@ -23,7 +23,7 @@ export const TEST_CREDENTIALS: ICredentialMap = {
|
||||
id: '2',
|
||||
type: 'team',
|
||||
name: 'Test Project',
|
||||
icon: { type: 'icon', value: 'exchange-alt' },
|
||||
icon: { type: 'icon', value: 'arrow-left-right' },
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
@@ -51,7 +51,7 @@ export const TEST_CREDENTIALS: ICredentialMap = {
|
||||
id: '2',
|
||||
type: 'team',
|
||||
name: 'Test Project',
|
||||
icon: { type: 'icon', value: 'exchange-alt' },
|
||||
icon: { type: 'icon', value: 'arrow-left-right' },
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
@@ -107,7 +107,7 @@ export const TEST_CREDENTIALS: ICredentialMap = {
|
||||
id: '2',
|
||||
type: 'team',
|
||||
name: 'Test Project',
|
||||
icon: { type: 'icon', value: 'exchange-alt' },
|
||||
icon: { type: 'icon', value: 'arrow-left-right' },
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
|
||||
@@ -89,7 +89,7 @@ function openCredentialType() {
|
||||
@update:model-value="onSelect"
|
||||
>
|
||||
<template #prefix>
|
||||
<font-awesome-icon icon="search" />
|
||||
<n8n-icon icon="search" />
|
||||
</template>
|
||||
<N8nOption
|
||||
v-for="credential in credentialsStore.allCredentialTypes"
|
||||
|
||||
@@ -462,7 +462,7 @@ async function onAskAssistantClick() {
|
||||
>
|
||||
<div class="copy-button">
|
||||
<N8nIconButton
|
||||
icon="copy"
|
||||
icon="files"
|
||||
type="secondary"
|
||||
size="mini"
|
||||
:text="true"
|
||||
@@ -484,7 +484,7 @@ async function onAskAssistantClick() {
|
||||
class="node-error-view__details"
|
||||
>
|
||||
<summary class="node-error-view__details-summary">
|
||||
<font-awesome-icon class="node-error-view__details-icon" icon="angle-right" />
|
||||
<n8n-icon class="node-error-view__details-icon" icon="chevron-right" />
|
||||
{{
|
||||
i18n.baseText('nodeErrorView.details.from', {
|
||||
interpolate: { node: `${nodeDefaultName}` },
|
||||
@@ -539,7 +539,7 @@ async function onAskAssistantClick() {
|
||||
|
||||
<details class="node-error-view__details">
|
||||
<summary class="node-error-view__details-summary">
|
||||
<font-awesome-icon class="node-error-view__details-icon" icon="angle-right" />
|
||||
<n8n-icon class="node-error-view__details-icon" icon="chevron-right" />
|
||||
{{ i18n.baseText('nodeErrorView.details.info') }}
|
||||
</summary>
|
||||
<div class="node-error-view__details-content">
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
import type { TestRunRecord } from '@/api/evaluation.ee';
|
||||
import { type IconName } from '@n8n/design-system/components/N8nIcon/icons';
|
||||
import type { IconColor } from '@n8n/design-system/types/icon';
|
||||
|
||||
export const statusDictionary: Record<TestRunRecord['status'], { icon: string; color: IconColor }> =
|
||||
{
|
||||
new: {
|
||||
icon: 'status-new',
|
||||
color: 'foreground-xdark',
|
||||
},
|
||||
running: {
|
||||
icon: 'spinner',
|
||||
color: 'secondary',
|
||||
},
|
||||
completed: {
|
||||
icon: 'status-completed',
|
||||
color: 'success',
|
||||
},
|
||||
error: {
|
||||
icon: 'exclamation-triangle',
|
||||
color: 'danger',
|
||||
},
|
||||
cancelled: {
|
||||
icon: 'status-canceled',
|
||||
color: 'foreground-xdark',
|
||||
},
|
||||
warning: {
|
||||
icon: 'status-warning',
|
||||
color: 'warning',
|
||||
},
|
||||
success: {
|
||||
icon: 'status-completed',
|
||||
color: 'success',
|
||||
},
|
||||
};
|
||||
export const statusDictionary: Record<
|
||||
TestRunRecord['status'],
|
||||
{ icon: IconName; color: IconColor }
|
||||
> = {
|
||||
new: {
|
||||
icon: 'status-new',
|
||||
color: 'foreground-xdark',
|
||||
},
|
||||
running: {
|
||||
icon: 'spinner',
|
||||
color: 'secondary',
|
||||
},
|
||||
completed: {
|
||||
icon: 'status-completed',
|
||||
color: 'success',
|
||||
},
|
||||
error: {
|
||||
icon: 'triangle-alert',
|
||||
color: 'danger',
|
||||
},
|
||||
cancelled: {
|
||||
icon: 'status-canceled',
|
||||
color: 'foreground-xdark',
|
||||
},
|
||||
warning: {
|
||||
icon: 'status-warning',
|
||||
color: 'warning',
|
||||
},
|
||||
success: {
|
||||
icon: 'status-completed',
|
||||
color: 'success',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ defineExpose({ focus, select });
|
||||
square
|
||||
outline
|
||||
type="tertiary"
|
||||
icon="external-link-alt"
|
||||
icon="external-link"
|
||||
size="mini"
|
||||
:class="$style['expression-editor-modal-opener']"
|
||||
data-test-id="expander"
|
||||
|
||||
@@ -133,11 +133,8 @@ async function onActionDropdownClick(id: string) {
|
||||
</span>
|
||||
</n8n-text>
|
||||
</div>
|
||||
<div v-if="provider.name === 'infisical'">
|
||||
<font-awesome-icon
|
||||
:class="$style['warningTriangle']"
|
||||
icon="exclamation-triangle"
|
||||
></font-awesome-icon>
|
||||
<div :class="$style.deprecationWarning" v-if="provider.name === 'infisical'">
|
||||
<n8n-icon :class="$style['warningTriangle']" icon="triangle-alert" />
|
||||
<N8nBadge class="mr-xs" theme="tertiary" bold data-test-id="card-badge">
|
||||
{{ i18n.baseText('settings.externalSecrets.card.deprecated') }}
|
||||
</N8nBadge>
|
||||
@@ -193,6 +190,10 @@ async function onActionDropdownClick(id: string) {
|
||||
margin-left: var(--spacing-s);
|
||||
}
|
||||
|
||||
.deprecationWarning {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.warningTriangle {
|
||||
color: var(--color-warning);
|
||||
margin-right: var(--spacing-2xs);
|
||||
|
||||
@@ -68,7 +68,7 @@ async function onUpdateConnected(value: boolean) {
|
||||
<n8n-icon
|
||||
v-if="provider.state === 'error'"
|
||||
color="danger"
|
||||
icon="exclamation-triangle"
|
||||
icon="triangle-alert"
|
||||
class="mr-2xs"
|
||||
/>
|
||||
<n8n-text :color="connectedTextColor" bold class="mr-2xs">
|
||||
|
||||
@@ -21,10 +21,7 @@ function onFeedback(feedback: 'positive' | 'negative') {
|
||||
{{ i18n.baseText('feedback.title') }}
|
||||
</N8nText>
|
||||
<N8nText v-else :color="modelValue === 'positive' ? 'success' : 'danger'">
|
||||
<FontAwesomeIcon
|
||||
:icon="modelValue === 'positive' ? 'thumbs-up' : 'thumbs-down'"
|
||||
class="mr-2xs"
|
||||
/>
|
||||
<N8nIcon :icon="modelValue === 'positive' ? 'thumbs-up' : 'thumbs-down'" class="mr-2xs" />
|
||||
{{ i18n.baseText(`feedback.${modelValue}`) }}
|
||||
</N8nText>
|
||||
<N8nTooltip v-if="!modelValue" :content="i18n.baseText('feedback.positive')">
|
||||
@@ -33,7 +30,7 @@ function onFeedback(feedback: 'positive' | 'negative') {
|
||||
data-test-id="feedback-button-positive"
|
||||
@click="onFeedback('positive')"
|
||||
>
|
||||
<FontAwesomeIcon icon="thumbs-up" />
|
||||
<N8nIcon icon="thumbs-up" />
|
||||
</span>
|
||||
</N8nTooltip>
|
||||
<N8nTooltip v-if="!modelValue" :content="i18n.baseText('feedback.negative')">
|
||||
@@ -42,7 +39,7 @@ function onFeedback(feedback: 'positive' | 'negative') {
|
||||
data-test-id="feedback-button-negative"
|
||||
@click="onFeedback('negative')"
|
||||
>
|
||||
<FontAwesomeIcon icon="thumbs-down" />
|
||||
<N8nIcon icon="thumbs-down" />
|
||||
</span>
|
||||
</N8nTooltip>
|
||||
</div>
|
||||
|
||||
@@ -168,7 +168,7 @@ const onBlur = (): void => {
|
||||
type="tertiary"
|
||||
text
|
||||
size="mini"
|
||||
icon="trash"
|
||||
icon="trash-2"
|
||||
data-test-id="filter-remove-condition"
|
||||
:title="i18n.baseText('filter.removeCondition')"
|
||||
:class="[$style.iconButton, $style.extraTopPadding]"
|
||||
@@ -231,7 +231,7 @@ const onBlur = (): void => {
|
||||
<template #content>
|
||||
{{ i18n.baseText('filter.condition.resolvedTrue') }}
|
||||
</template>
|
||||
<n8n-icon :class="$style.statusIcon" icon="check-circle" size="medium" color="text-light" />
|
||||
<n8n-icon :class="$style.statusIcon" icon="circle-check" size="medium" color="text-light" />
|
||||
</n8n-tooltip>
|
||||
|
||||
<n8n-tooltip
|
||||
@@ -241,7 +241,7 @@ const onBlur = (): void => {
|
||||
<template #content>
|
||||
{{ i18n.baseText('filter.condition.resolvedFalse') }}
|
||||
</template>
|
||||
<n8n-icon :class="$style.statusIcon" icon="times-circle" size="medium" color="text-light" />
|
||||
<n8n-icon :class="$style.statusIcon" icon="circle-x" size="medium" color="text-light" />
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -285,13 +285,13 @@ export const OPERATOR_GROUPS: FilterOperatorGroup[] = [
|
||||
{
|
||||
id: 'string',
|
||||
name: 'type.string',
|
||||
icon: 'font',
|
||||
icon: 'case-upper',
|
||||
children: OPERATORS.filter((operator) => operator.type === 'string'),
|
||||
},
|
||||
{
|
||||
id: 'number',
|
||||
name: 'type.number',
|
||||
icon: 'hashtag',
|
||||
icon: 'hash',
|
||||
children: OPERATORS.filter((operator) => operator.type === 'number'),
|
||||
},
|
||||
{
|
||||
@@ -303,7 +303,7 @@ export const OPERATOR_GROUPS: FilterOperatorGroup[] = [
|
||||
{
|
||||
id: 'boolean',
|
||||
name: 'type.boolean',
|
||||
icon: 'check-square',
|
||||
icon: 'square-check',
|
||||
children: OPERATORS.filter((operator) => operator.type === 'boolean'),
|
||||
},
|
||||
{
|
||||
@@ -315,7 +315,7 @@ export const OPERATOR_GROUPS: FilterOperatorGroup[] = [
|
||||
{
|
||||
id: 'object',
|
||||
name: 'type.object',
|
||||
icon: 'cube',
|
||||
icon: 'box',
|
||||
children: OPERATORS.filter((operator) => operator.type === 'object'),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { IconName } from '@n8n/design-system/components/N8nIcon/icons';
|
||||
import type { BaseTextKey } from '@n8n/i18n';
|
||||
import type { FilterConditionValue, FilterOperatorValue } from 'n8n-workflow';
|
||||
|
||||
@@ -8,7 +9,7 @@ export interface FilterOperator extends FilterOperatorValue {
|
||||
export interface FilterOperatorGroup {
|
||||
id: string;
|
||||
name: BaseTextKey;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
children: FilterOperator[];
|
||||
}
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ const trackWorkflowInputFieldAdded = () => {
|
||||
type="tertiary"
|
||||
text
|
||||
size="mini"
|
||||
icon="trash"
|
||||
icon="trash-2"
|
||||
data-test-id="fixed-collection-delete"
|
||||
:title="locale.baseText('fixedCollectionParameter.deleteItem')"
|
||||
@click="deleteOption(property.name, index)"
|
||||
@@ -315,7 +315,7 @@ const trackWorkflowInputFieldAdded = () => {
|
||||
type="tertiary"
|
||||
text
|
||||
size="mini"
|
||||
icon="trash"
|
||||
icon="trash-2"
|
||||
data-test-id="fixed-collection-delete"
|
||||
:title="locale.baseText('fixedCollectionParameter.deleteItem')"
|
||||
@click="deleteOption(property.name)"
|
||||
|
||||
@@ -130,6 +130,7 @@ const onBreadcrumbItemClick = async (item: PathItem) => {
|
||||
:class="$style['folder-icon']"
|
||||
icon="folder"
|
||||
size="xlarge"
|
||||
:strokeWidth="1"
|
||||
/>
|
||||
</template>
|
||||
<template #header>
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import {
|
||||
type Project,
|
||||
type ProjectIcon as ProjectIconType,
|
||||
ProjectTypes,
|
||||
} from '@/types/projects.types';
|
||||
import { type Project, ProjectTypes } from '@/types/projects.types';
|
||||
import { isIconOrEmoji, type IconOrEmoji } from '@n8n/design-system/components/N8nIconPicker/types';
|
||||
|
||||
type Props = {
|
||||
currentProject: Project;
|
||||
@@ -23,13 +20,15 @@ const emit = defineEmits<{
|
||||
|
||||
const i18n = useI18n();
|
||||
|
||||
const projectIcon = computed((): ProjectIconType => {
|
||||
const projectIcon = computed((): IconOrEmoji => {
|
||||
if (props.currentProject?.type === ProjectTypes.Personal) {
|
||||
return { type: 'icon', value: 'user' };
|
||||
} else if (props.currentProject?.name) {
|
||||
return props.currentProject.icon ?? { type: 'icon', value: 'layer-group' };
|
||||
return isIconOrEmoji(props.currentProject.icon)
|
||||
? props.currentProject.icon
|
||||
: { type: 'icon', value: 'layers' };
|
||||
} else {
|
||||
return { type: 'icon', value: 'home' };
|
||||
return { type: 'icon', value: 'house' };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ const onClaimCreditsClicked = async () => {
|
||||
<n8n-callout
|
||||
v-if="userCanClaimOpenAiCredits && !showSuccessCallout"
|
||||
theme="secondary"
|
||||
icon="exclamation-circle"
|
||||
icon="circle-alert"
|
||||
>
|
||||
{{
|
||||
i18n.baseText('freeAi.credits.callout.claim.title', {
|
||||
@@ -110,7 +110,7 @@ const onClaimCreditsClicked = async () => {
|
||||
/>
|
||||
</template>
|
||||
</n8n-callout>
|
||||
<n8n-callout v-else-if="showSuccessCallout" theme="success" icon="check-circle">
|
||||
<n8n-callout v-else-if="showSuccessCallout" theme="success" icon="circle-check">
|
||||
<n8n-text size="small">
|
||||
{{
|
||||
i18n.baseText('freeAi.credits.callout.success.title.part1', {
|
||||
|
||||