mirror of
https://github.com/unraid/api.git
synced 2026-01-02 22:50:02 -06:00
fix: storybook
This commit is contained in:
@@ -92,42 +92,9 @@ function translateRCloneOptionToJsonSchema({
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the UI schema for RClone remote configuration using Categorization for provider options.
|
||||
*/
|
||||
export function getRcloneConfigFormSchema({
|
||||
providerTypes = [],
|
||||
selectedProvider = '',
|
||||
providerOptions = {},
|
||||
}: {
|
||||
providerTypes?: string[];
|
||||
selectedProvider?: string;
|
||||
providerOptions?: Record<string, RCloneProviderOptionResponse[]>;
|
||||
}): SettingSlice {
|
||||
const options = providerOptions[selectedProvider] || [];
|
||||
|
||||
const basicSlice = getBasicConfigSlice({ providerTypes });
|
||||
const standardConfigSlice = getProviderConfigSlice({
|
||||
selectedProvider,
|
||||
providerOptions: options,
|
||||
type: 'standard',
|
||||
});
|
||||
const advancedConfigSlice = getProviderConfigSlice({
|
||||
selectedProvider,
|
||||
providerOptions: options,
|
||||
type: 'advanced',
|
||||
});
|
||||
|
||||
const mergedProperties = mergeSettingSlices([basicSlice, standardConfigSlice, advancedConfigSlice]);
|
||||
|
||||
return {
|
||||
properties: mergedProperties.properties,
|
||||
elements: mergedProperties.elements,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 1: Basic configuration - name and type selection
|
||||
* Returns a SettingSlice containing properties and a VerticalLayout UI element with options.step = 0.
|
||||
*/
|
||||
function getBasicConfigSlice({ providerTypes }: { providerTypes: string[] }): SettingSlice {
|
||||
// Create UI elements for basic configuration (Step 1)
|
||||
@@ -178,30 +145,33 @@ function getBasicConfigSlice({ providerTypes }: { providerTypes: string[] }): Se
|
||||
},
|
||||
};
|
||||
|
||||
// Wrap the basic elements in a VerticalLayout
|
||||
// Wrap the basic elements in a VerticalLayout marked for step 0
|
||||
const verticalLayoutElement: UIElement = {
|
||||
type: 'VerticalLayout',
|
||||
elements: basicConfigElements,
|
||||
options: { step: 0 }, // Assign to step 0
|
||||
};
|
||||
|
||||
return {
|
||||
properties: basicConfigProperties as unknown as DataSlice,
|
||||
// Return the VerticalLayout as the single element for this slice
|
||||
elements: [verticalLayoutElement],
|
||||
elements: [verticalLayoutElement], // Return the VerticalLayout as the single element
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2/3: Provider-specific configuration based on the selected provider and whether to show advanced options
|
||||
* Step 2/3: Provider-specific configuration based on the selected provider and type (standard/advanced).
|
||||
* Returns a SettingSlice containing properties and a VerticalLayout UI element with options.step = stepIndex.
|
||||
*/
|
||||
export function getProviderConfigSlice({
|
||||
function getProviderConfigSlice({
|
||||
selectedProvider,
|
||||
providerOptions,
|
||||
type = 'standard',
|
||||
stepIndex, // Added stepIndex parameter
|
||||
}: {
|
||||
selectedProvider: string;
|
||||
providerOptions: RCloneProviderOptionResponse[];
|
||||
type?: 'standard' | 'advanced';
|
||||
stepIndex: number; // Required step index for the rule
|
||||
}): SettingSlice {
|
||||
// Default properties when no provider is selected
|
||||
let configProperties: DataSlice = {};
|
||||
@@ -213,7 +183,7 @@ export function getProviderConfigSlice({
|
||||
};
|
||||
}
|
||||
|
||||
// Filter options based on the showAdvancedOptions flag
|
||||
// Filter options based on the type (standard/advanced)
|
||||
const filteredOptions = providerOptions.filter((option) => {
|
||||
if (type === 'advanced' && option.Advanced === true) {
|
||||
return true;
|
||||
@@ -233,8 +203,7 @@ export function getProviderConfigSlice({
|
||||
return acc;
|
||||
}, [] as RCloneProviderOptionResponse[]);
|
||||
|
||||
// If no options match the filter (e.g., asking for advanced but none exist), return empty
|
||||
// Use uniqueOptionsByName instead of filteredOptions from here on
|
||||
// If no options match the filter, return empty
|
||||
if (uniqueOptionsByName.length === 0) {
|
||||
return {
|
||||
properties: configProperties,
|
||||
@@ -242,7 +211,7 @@ export function getProviderConfigSlice({
|
||||
};
|
||||
}
|
||||
|
||||
// Create dynamic UI elements based on unique provider options
|
||||
// Create dynamic UI control elements based on unique provider options
|
||||
const controlElements = uniqueOptionsByName.map<UIElement>((option) => {
|
||||
const format = getJsonFormElementForType({
|
||||
rcloneType: option.Type,
|
||||
@@ -278,7 +247,7 @@ export function getProviderConfigSlice({
|
||||
}
|
||||
|
||||
// --- Start: Add dynamic visibility rule based on Provider --- //
|
||||
let rule: { effect: RuleEffect; condition: SchemaBasedCondition } | undefined = undefined;
|
||||
let providerRule: { effect: RuleEffect; condition: SchemaBasedCondition } | undefined = undefined;
|
||||
const providerFilter = option.Provider?.trim();
|
||||
|
||||
if (providerFilter) {
|
||||
@@ -293,12 +262,12 @@ export function getProviderConfigSlice({
|
||||
? { not: { enum: providers } } // Show if type is NOT in the list
|
||||
: { enum: providers }; // Show if type IS in the list
|
||||
|
||||
rule = {
|
||||
providerRule = {
|
||||
effect: RuleEffect.SHOW,
|
||||
condition: {
|
||||
scope: '#/properties/type',
|
||||
schema: conditionSchema,
|
||||
},
|
||||
} as SchemaBasedCondition,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -309,8 +278,8 @@ export function getProviderConfigSlice({
|
||||
scope: `#/properties/parameters/properties/${option.Name}`,
|
||||
label: option.Help || option.Name,
|
||||
options: controlOptions,
|
||||
// Add the rule if it was generated
|
||||
...(rule && { rule }),
|
||||
// Add the provider-specific rule if it was generated
|
||||
...(providerRule && { rule: providerRule }),
|
||||
};
|
||||
return uiElement;
|
||||
});
|
||||
@@ -319,30 +288,36 @@ export function getProviderConfigSlice({
|
||||
const paramProperties: Record<string, JsonSchema7> = {};
|
||||
uniqueOptionsByName.forEach((option) => {
|
||||
if (option) {
|
||||
// Ensure option exists before translating
|
||||
paramProperties[option.Name] = translateRCloneOptionToJsonSchema({ option });
|
||||
console.log('paramProperties', option.Name, paramProperties[option.Name]);
|
||||
}
|
||||
});
|
||||
|
||||
// Only add parameters object if there are properties
|
||||
if (Object.keys(paramProperties).length > 0) {
|
||||
// Initialize parameters object if it doesn't exist
|
||||
// Ensure parameters object exists and has a properties key
|
||||
if (!configProperties.parameters) {
|
||||
configProperties.parameters = {
|
||||
type: 'object',
|
||||
properties: {} as Record<string, JsonSchema7>,
|
||||
} as unknown as DataSlice;
|
||||
configProperties.parameters = { type: 'object', properties: {} } as any;
|
||||
} else if (!(configProperties.parameters as any).properties) {
|
||||
(configProperties.parameters as any).properties = {};
|
||||
}
|
||||
|
||||
// Merge the properties into the existing parameters object
|
||||
// Merge the new paramProperties into the existing parameters.properties
|
||||
(configProperties.parameters as any).properties = {
|
||||
...(configProperties.parameters as any).properties,
|
||||
...paramProperties,
|
||||
};
|
||||
}
|
||||
|
||||
// Wrap the control elements in a VerticalLayout marked for the specified stepIndex
|
||||
const verticalLayoutElement: UIElement = {
|
||||
type: 'VerticalLayout',
|
||||
elements: controlElements,
|
||||
options: { step: stepIndex }, // Assign to the specified stepIndex
|
||||
};
|
||||
|
||||
return {
|
||||
properties: configProperties,
|
||||
elements: controlElements,
|
||||
elements: [verticalLayoutElement], // Return the VerticalLayout as the single element
|
||||
};
|
||||
}
|
||||
|
||||
@@ -418,90 +393,8 @@ function getJsonFormElementForType({
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a combined form schema for the rclone backup configuration UI
|
||||
*/
|
||||
export function getRcloneConfigSlice(): SettingSlice {
|
||||
const elements: UIElement[] = [
|
||||
{
|
||||
type: 'Label',
|
||||
text: 'Configure RClone Backup',
|
||||
options: {
|
||||
format: 'title',
|
||||
description:
|
||||
'This 3-step process will guide you through setting up your RClone backup configuration.',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'SteppedLayout',
|
||||
options: {
|
||||
stepControl: '#/properties/configStep',
|
||||
steps: [
|
||||
{ label: 'Set up Remote Config', description: 'Name and provider selection' },
|
||||
{ label: 'Set up Drive', description: 'Provider-specific configuration' },
|
||||
{ label: 'Advanced Config', description: 'Optional advanced settings' },
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Basic properties for the rclone backup configuration
|
||||
const properties: Record<string, JsonSchema7> = {
|
||||
configStep: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 2,
|
||||
default: 0,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
properties: properties as unknown as DataSlice,
|
||||
elements,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete form schemas (data and UI) for the RClone configuration
|
||||
*/
|
||||
export function getRcloneConfigSchemas(
|
||||
properties: DataSlice,
|
||||
elements: UIElement[]
|
||||
): {
|
||||
dataSchema: Record<string, any>;
|
||||
uiSchema: Layout;
|
||||
} {
|
||||
return {
|
||||
dataSchema: {
|
||||
type: 'object',
|
||||
properties,
|
||||
},
|
||||
uiSchema: {
|
||||
type: 'SteppedLayout',
|
||||
options: {
|
||||
stepControl: '#/properties/configStep',
|
||||
steps: [
|
||||
{ label: 'Set up Remote Config', description: 'Name and provider selection' },
|
||||
{ label: 'Set up Drive', description: 'Provider-specific configuration' },
|
||||
{ label: 'Advanced Config', description: 'Optional advanced settings' },
|
||||
],
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
type: 'Label',
|
||||
options: {
|
||||
format: 'title',
|
||||
description:
|
||||
'This 3-step process will guide you through setting up your RClone backup configuration.',
|
||||
},
|
||||
},
|
||||
...elements,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the complete settings schema for a given provider
|
||||
* Builds the complete settings schema for the RClone config UI, returning the final dataSchema and uiSchema.
|
||||
* Integrates step-specific elements directly into the SteppedLayout's elements array.
|
||||
*/
|
||||
export function buildRcloneConfigSchema({
|
||||
providerTypes = [],
|
||||
@@ -511,14 +404,105 @@ export function buildRcloneConfigSchema({
|
||||
providerTypes?: string[];
|
||||
selectedProvider?: string;
|
||||
providerOptions?: Record<string, RCloneProviderOptionResponse[]>;
|
||||
}): SettingSlice {
|
||||
// Get the base slice and form schema
|
||||
const baseSlice = getRcloneConfigSlice();
|
||||
const formSlice = getRcloneConfigFormSchema({
|
||||
providerTypes,
|
||||
}): {
|
||||
dataSchema: Record<string, any>;
|
||||
uiSchema: Layout;
|
||||
} {
|
||||
// --- Schema Definition ---
|
||||
|
||||
// Define the step control property - REMOVED as SteppedLayout uses local state
|
||||
// const stepControlProperty: Record<string, JsonSchema7> = {
|
||||
// configStep: {
|
||||
// type: 'number',
|
||||
// minimum: 0,
|
||||
// maximum: 2, // 3 steps: 0, 1, 2
|
||||
// default: 0,
|
||||
// },
|
||||
// };
|
||||
|
||||
// --- Step Content Generation ---
|
||||
|
||||
const optionsForProvider = providerOptions[selectedProvider] || [];
|
||||
|
||||
// Step 0: Basic Config
|
||||
const basicSlice = getBasicConfigSlice({ providerTypes });
|
||||
|
||||
// Step 1: Standard Provider Config
|
||||
const standardConfigSlice = getProviderConfigSlice({
|
||||
selectedProvider,
|
||||
providerOptions,
|
||||
providerOptions: optionsForProvider,
|
||||
type: 'standard',
|
||||
stepIndex: 1, // Assign to step 1
|
||||
});
|
||||
|
||||
return mergeSettingSlices([baseSlice, formSlice]);
|
||||
// Step 2: Advanced Provider Config
|
||||
const advancedConfigSlice = getProviderConfigSlice({
|
||||
selectedProvider,
|
||||
providerOptions: optionsForProvider,
|
||||
type: 'advanced',
|
||||
stepIndex: 2, // Assign to step 2
|
||||
});
|
||||
|
||||
// --- UI Schema Definition ---
|
||||
|
||||
// Define the SteppedLayout UI element, now containing step content elements
|
||||
const steppedLayoutElement: UIElement = {
|
||||
type: 'SteppedLayout',
|
||||
options: {
|
||||
steps: [
|
||||
{ label: 'Set up Remote Config', description: 'Name and provider selection' },
|
||||
{ label: 'Set up Drive', description: 'Provider-specific configuration' },
|
||||
{ label: 'Advanced Config', description: 'Optional advanced settings' },
|
||||
],
|
||||
},
|
||||
// Nest the step content elements directly inside the SteppedLayout
|
||||
elements: [
|
||||
...(basicSlice.elements || []),
|
||||
...(standardConfigSlice.elements || []),
|
||||
...(advancedConfigSlice.elements || []),
|
||||
],
|
||||
};
|
||||
|
||||
// Define the overall title label
|
||||
const titleLabel: UIElement = {
|
||||
type: 'Label',
|
||||
text: 'Configure RClone Remote',
|
||||
options: {
|
||||
format: 'title',
|
||||
description:
|
||||
'This 3-step process will guide you through setting up your RClone remote configuration.',
|
||||
},
|
||||
};
|
||||
|
||||
// --- Merging and Final Output ---
|
||||
|
||||
// Merge all properties: basic + standard + advanced
|
||||
const mergedProperties = mergeSettingSlices([
|
||||
basicSlice,
|
||||
standardConfigSlice,
|
||||
advancedConfigSlice,
|
||||
]);
|
||||
|
||||
// Construct the final dataSchema
|
||||
const dataSchema = {
|
||||
type: 'object',
|
||||
properties: mergedProperties.properties,
|
||||
// Add required fields if necessary, e.g., ['name', 'type']
|
||||
// required: ['name', 'type'], // Example: Make name and type required globally
|
||||
};
|
||||
|
||||
// Construct the final uiSchema with Title + SteppedLayout (containing steps)
|
||||
const uiSchema: Layout = {
|
||||
type: 'VerticalLayout',
|
||||
elements: [
|
||||
titleLabel,
|
||||
steppedLayoutElement, // The Stepper control, now containing its step elements
|
||||
// Step content elements are now *inside* steppedLayoutElement.elements
|
||||
],
|
||||
};
|
||||
|
||||
return { dataSchema, uiSchema };
|
||||
}
|
||||
|
||||
// Add optional console log for debugging
|
||||
// console.log('Generated RClone Config Schema:', JSON.stringify({ dataSchema, uiSchema }, null, 2));
|
||||
|
||||
@@ -4,7 +4,7 @@ import { type Layout } from '@jsonforms/core';
|
||||
|
||||
import { RCloneProviderOptionResponse } from '@app/unraid-api/graph/resolvers/rclone/rclone.model.js';
|
||||
|
||||
import { buildRcloneConfigSchema, getRcloneConfigSchemas } from './jsonforms/rclone-jsonforms-config.js';
|
||||
import { buildRcloneConfigSchema } from './jsonforms/rclone-jsonforms-config.js';
|
||||
import { RCloneApiService } from './rclone-api.service.js';
|
||||
|
||||
/**
|
||||
@@ -51,12 +51,10 @@ export class RCloneFormService {
|
||||
await this.loadProviderInfo();
|
||||
}
|
||||
|
||||
const { properties, elements } = buildRcloneConfigSchema({
|
||||
return buildRcloneConfigSchema({
|
||||
providerTypes: this.providerNames,
|
||||
selectedProvider,
|
||||
providerOptions: this.providerOptions,
|
||||
});
|
||||
|
||||
return getRcloneConfigSchemas(properties, elements);
|
||||
}
|
||||
}
|
||||
|
||||
346
pnpm-lock.yaml
generated
346
pnpm-lock.yaml
generated
@@ -704,20 +704,23 @@ importers:
|
||||
specifier: ^4.4.1
|
||||
version: 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.3)
|
||||
'@storybook/addon-essentials':
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(@types/react@19.0.8)(storybook@8.6.9(prettier@3.5.3))
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(@types/react@19.0.8)(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-interactions':
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-links':
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/builder-vite':
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))
|
||||
'@storybook/vue3':
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(storybook@8.6.12(prettier@3.5.3))(vue@3.5.13(typescript@5.8.3))
|
||||
'@storybook/vue3-vite':
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.16(tailwindcss@3.4.17)
|
||||
@@ -760,6 +763,9 @@ importers:
|
||||
autoprefixer:
|
||||
specifier: ^10.4.20
|
||||
version: 10.4.21(postcss@8.5.3)
|
||||
concurrently:
|
||||
specifier: ^9.1.2
|
||||
version: 9.1.2
|
||||
eslint:
|
||||
specifier: ^9.17.0
|
||||
version: 9.23.0(jiti@2.4.2)
|
||||
@@ -794,8 +800,8 @@ importers:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
storybook:
|
||||
specifier: ^8.5.8
|
||||
version: 8.6.9(prettier@3.5.3)
|
||||
specifier: ^8.6.12
|
||||
version: 8.6.12(prettier@3.5.3)
|
||||
tailwind-rem-to-rem:
|
||||
specifier: github:unraid/tailwind-rem-to-rem
|
||||
version: '@unraid/tailwind-rem-to-rem@https://codeload.github.com/unraid/tailwind-rem-to-rem/tar.gz/4b907d0cdb3abda88de9813e33c13c3e7b1300c4(tailwindcss@3.4.17)'
|
||||
@@ -3590,105 +3596,105 @@ packages:
|
||||
'@speed-highlight/core@1.2.7':
|
||||
resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==}
|
||||
|
||||
'@storybook/addon-actions@8.6.9':
|
||||
resolution: {integrity: sha512-H2v17sMbSl8jhSulPxcOyChsFbzik9E7mgCWIf4P114KcIUokWLVuALnSOeqHME6lY0pPBZs3DgvVVMVMm7zNw==}
|
||||
'@storybook/addon-actions@8.6.12':
|
||||
resolution: {integrity: sha512-B5kfiRvi35oJ0NIo53CGH66H471A3XTzrfaa6SxXEJsgxxSeKScG5YeXcCvLiZfvANRQ7QDsmzPUgg0o3hdMXw==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-backgrounds@8.6.9':
|
||||
resolution: {integrity: sha512-DiNpKJq4sEqTCGwwGs8fwi1hxBniCQMxsJFfrYlIx0HTyfA7AMROqP9fyv1aCV1JWDiwlL+cwCurkoyhpuZioQ==}
|
||||
'@storybook/addon-backgrounds@8.6.12':
|
||||
resolution: {integrity: sha512-lmIAma9BiiCTbJ8YfdZkXjpnAIrOUcgboLkt1f6XJ78vNEMnLNzD9gnh7Tssz1qrqvm34v9daDjIb+ggdiKp3Q==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-controls@8.6.9':
|
||||
resolution: {integrity: sha512-YXBYsbHqdYhmrbGI+wv9LAr/LlKnPt9f9GL+9rw82lnYadWObYxzUxs+PPLNO5tc14fd2g+FMVHOfovaRdFvrQ==}
|
||||
'@storybook/addon-controls@8.6.12':
|
||||
resolution: {integrity: sha512-9VSRPJWQVb9wLp21uvpxDGNctYptyUX0gbvxIWOHMH3R2DslSoq41lsC/oQ4l4zSHVdL+nq8sCTkhBxIsjKqdQ==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-docs@8.6.9':
|
||||
resolution: {integrity: sha512-yAP59G5Vd+E6O9KLfBR5ALdOFA5yEZ0n1f8Ne9jwF+NGu1U8KNIfWnZmBYaBGe+bpYn0CWV5AfdFvw83bzHYpw==}
|
||||
'@storybook/addon-docs@8.6.12':
|
||||
resolution: {integrity: sha512-kEezQjAf/p3SpDzLABgg4fbT48B6dkT2LiZCKTRmCrJVtuReaAr4R9MMM6Jsph6XjbIj/SvOWf3CMeOPXOs9sg==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-essentials@8.6.9':
|
||||
resolution: {integrity: sha512-n3DSSIjDsVDw7uOatP2remC5SVSIfjwHcLGor85xLd1SQUh98wednM1Iby19qc/QR69UuOL0nB/d5yG1ifh0sA==}
|
||||
'@storybook/addon-essentials@8.6.12':
|
||||
resolution: {integrity: sha512-Y/7e8KFlttaNfv7q2zoHMPdX6hPXHdsuQMAjYl5NG9HOAJREu4XBy4KZpbcozRe4ApZ78rYsN/MO1EuA+bNMIA==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-highlight@8.6.9':
|
||||
resolution: {integrity: sha512-I0gBHgaH74wX6yf5S7zUmdfr25hwPONpSAqPPGBSNYu0Jj9Je+ANr1y4T1I3cOaEvf73QntDhCgHC6/iqY90Fw==}
|
||||
'@storybook/addon-highlight@8.6.12':
|
||||
resolution: {integrity: sha512-9FITVxdoycZ+eXuAZL9ElWyML/0fPPn9UgnnAkrU7zkMi+Segq/Tx7y+WWanC5zfWZrXAuG6WTOYEXeWQdm//w==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-interactions@8.6.9':
|
||||
resolution: {integrity: sha512-KpSVjcDD+5vmGA78MM2blsfy8J/PfuIMb74nJufgjci2xlzUxB8dGEFJACZPfqM5kUuUv/AhHHsAzP1r/wr83Q==}
|
||||
'@storybook/addon-interactions@8.6.12':
|
||||
resolution: {integrity: sha512-cTAJlTq6uVZBEbtwdXkXoPQ4jHOAGKQnYSezBT4pfNkdjn/FnEeaQhMBDzf14h2wr5OgBnJa6Lmd8LD9ficz4A==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-links@8.6.9':
|
||||
resolution: {integrity: sha512-cYYlsaMHvEJzGqJ3BO5BpXaa00AxYtEKjJEFP7q/LDZBxMnrChzDygFUTAAbUTHF4U3mNCrl1KuyoUL3nMQquA==}
|
||||
'@storybook/addon-links@8.6.12':
|
||||
resolution: {integrity: sha512-AfKujFHoAxhxq4yu+6NwylltS9lf5MPs1eLLXvOlwo3l7Y/c68OdxJ7j68vLQhs9H173WVYjKyjbjFxJWf/YYg==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
|
||||
'@storybook/addon-measure@8.6.9':
|
||||
resolution: {integrity: sha512-2GrHtaYZgM7qeil5/XfNJrdnan7hoLLUyU7w7fph0EVl7tiwmhtp4He0PX9hrT/Abk2HxeCP4WU2fAGwIuTkYg==}
|
||||
'@storybook/addon-measure@8.6.12':
|
||||
resolution: {integrity: sha512-tACmwqqOvutaQSduw8SMb62wICaT1rWaHtMN3vtWXuxgDPSdJQxLP+wdVyRYMAgpxhLyIO7YRf++Hfha9RHgFg==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-outline@8.6.9':
|
||||
resolution: {integrity: sha512-YXfiSmjdpXGNYns9NZfdiEbwRfOW/Naym0dIH7s1LAlZZPJvtEYe2hNUOjBfAEm8ZhC1fA1+pZFnspOQHPENlA==}
|
||||
'@storybook/addon-outline@8.6.12':
|
||||
resolution: {integrity: sha512-1ylwm+n1s40S91No0v9T4tCjZORu3GbnjINlyjYTDLLhQHyBQd3nWR1Y1eewU4xH4cW9SnSLcMQFS/82xHqU6A==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-toolbars@8.6.9':
|
||||
resolution: {integrity: sha512-WOO3CHyzqEql9xnNzi7BUkPRPGHGMCtAR+szGeWqmuj3GZLqXwDOb8HDa3aVMIhVEKhk5jN2zGQmxH53vReBNQ==}
|
||||
'@storybook/addon-toolbars@8.6.12':
|
||||
resolution: {integrity: sha512-HEcSzo1DyFtIu5/ikVOmh5h85C1IvK9iFKSzBR6ice33zBOaehVJK+Z5f487MOXxPsZ63uvWUytwPyViGInj+g==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/addon-viewport@8.6.9':
|
||||
resolution: {integrity: sha512-1xkozyB1zs3eSNTc8ePAMcajUfbKvNMTjs5LYdts2N1Ss0xeZ+K/gphfRg0GaYsNvRYi5piufag/niHCGkT3hA==}
|
||||
'@storybook/addon-viewport@8.6.12':
|
||||
resolution: {integrity: sha512-EXK2LArAnABsPP0leJKy78L/lbMWow+EIJfytEP5fHaW4EhMR6h7Hzaqzre6U0IMMr/jVFa1ci+m0PJ0eQc2bw==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/blocks@8.6.9':
|
||||
resolution: {integrity: sha512-+vSRkHLD7ho3Wd1WVA1KrYAnv7BnGHOhHWHAgTR5IdeMdgzQxm6+HHeqGB5sncilA0AjVC6udBIgHbCSuD61dA==}
|
||||
'@storybook/blocks@8.6.12':
|
||||
resolution: {integrity: sha512-DohlTq6HM1jDbHYiXL4ZvZ00VkhpUp5uftzj/CZDLY1fYHRjqtaTwWm2/OpceivMA8zDitLcq5atEZN+f+siTg==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
'@storybook/builder-vite@8.6.9':
|
||||
resolution: {integrity: sha512-8U11A7sLPvvcnJQ3pXyoX1LdJDpa4+JOYcASL9A+DL591jkfYKxhim7R4BOHO55aetmqQAoA/LEAD5runu7zoQ==}
|
||||
'@storybook/builder-vite@8.6.12':
|
||||
resolution: {integrity: sha512-Gju21ud/3Qw4v2vLNaa5SuJECsI9ICNRr2G0UyCCzRvCHg8jpA9lDReu2NqhLDyFIuDG+ZYT38gcaHEUoNQ8KQ==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
vite: ^4.0.0 || ^5.0.0 || ^6.0.0
|
||||
|
||||
'@storybook/components@8.6.9':
|
||||
resolution: {integrity: sha512-CqWUAYK/RgV++sXfiDG63DM2JF2FeidvnMO5/bki2hFbEqgs0/yy7BKUjhsGmuri5y+r9B2FJhW0WnE6PI8NWw==}
|
||||
'@storybook/components@8.6.12':
|
||||
resolution: {integrity: sha512-FiaE8xvCdvKC2arYusgtlDNZ77b8ysr8njAYQZwwaIHjy27TbR2tEpLDCmUwSbANNmivtc/xGEiDDwcNppMWlQ==}
|
||||
peerDependencies:
|
||||
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
|
||||
|
||||
'@storybook/core@8.6.9':
|
||||
resolution: {integrity: sha512-psYxJAlj34ZaDAk+OvT/He6ZuUh0eGiHVtZNe0xWbNp5pQvOBjf+dg48swdI6KEbVs3aeU+Wnyra/ViU2RtA+Q==}
|
||||
'@storybook/core@8.6.12':
|
||||
resolution: {integrity: sha512-t+ZuDzAlsXKa6tLxNZT81gEAt4GNwsKP/Id2wluhmUWD/lwYW0uum1JiPUuanw8xD6TdakCW/7ULZc7aQUBLCQ==}
|
||||
peerDependencies:
|
||||
prettier: ^2 || ^3
|
||||
peerDependenciesMeta:
|
||||
prettier:
|
||||
optional: true
|
||||
|
||||
'@storybook/csf-plugin@8.6.9':
|
||||
resolution: {integrity: sha512-IQnhyaVUkcRR9e4xiHN83xMQtTMH+lJp472iMifUIqxx/Yw137BTef2DEEp6EnRct4yKrch24+Nl65LWg0mRpQ==}
|
||||
'@storybook/csf-plugin@8.6.12':
|
||||
resolution: {integrity: sha512-6s8CnP1aoKPb3XtC0jRLUp8M5vTA8RhGAwQDKUsFpCC7g89JR9CaKs9FY2ZSzsNbjR15uASi7b3K8BzeYumYQg==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/global@5.0.0':
|
||||
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
|
||||
@@ -3700,50 +3706,50 @@ packages:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
|
||||
'@storybook/instrumenter@8.6.9':
|
||||
resolution: {integrity: sha512-Gp6OSiu9KA/p1HWd7VW9TtpWX32ZBfqRVrOm4wW1AM6B4XACbQWFE/aQ25HwU834yfdJkr2BW+uUH8DBAQ6kTw==}
|
||||
'@storybook/instrumenter@8.6.12':
|
||||
resolution: {integrity: sha512-VK5fYAF8jMwWP/u3YsmSwKGh+FeSY8WZn78flzRUwirp2Eg1WWjsqPRubAk7yTpcqcC/km9YMF3KbqfzRv2s/A==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/manager-api@8.6.9':
|
||||
resolution: {integrity: sha512-mxq9B9rxAraOCBapGKsUDfI+8yNtFhTgKMZCxmHoUCxvAHaIt4S9JcdX0qQQKUsBTr/b2hHm0O7A8DYrbgBRfw==}
|
||||
'@storybook/manager-api@8.6.12':
|
||||
resolution: {integrity: sha512-O0SpISeJLNTQvhSBOsWzzkCgs8vCjOq1578rwqHlC6jWWm4QmtfdyXqnv7rR1Hk08kQ+Dzqh0uhwHx0nfwy4nQ==}
|
||||
peerDependencies:
|
||||
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
|
||||
|
||||
'@storybook/preview-api@8.6.9':
|
||||
resolution: {integrity: sha512-hW3Z8NBrGs2bNunaHgrLjpfrOcWsxH0ejAqaba8MolPXjzNs0lTFF/Ela7pUsh2m1R4/kiD+WfddQzyipUo4Mg==}
|
||||
'@storybook/preview-api@8.6.12':
|
||||
resolution: {integrity: sha512-84FE3Hrs0AYKHqpDZOwx1S/ffOfxBdL65lhCoeI8GoWwCkzwa9zEP3kvXBo/BnEDO7nAfxvMhjASTZXbKRJh5Q==}
|
||||
peerDependencies:
|
||||
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
|
||||
|
||||
'@storybook/react-dom-shim@8.6.9':
|
||||
resolution: {integrity: sha512-SjqP6r5yy87OJRAiq1JzFazn6VWfptOA2HaxOiP8zRhJgG41K0Vseh8tbZdycj1AzJYSCcnKaIcfd/GEo/41+g==}
|
||||
'@storybook/react-dom-shim@8.6.12':
|
||||
resolution: {integrity: sha512-51QvoimkBzYs8s3rCYnY5h0cFqLz/Mh0vRcughwYaXckWzDBV8l67WBO5Xf5nBsukCbWyqBVPpEQLww8s7mrLA==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/test@8.6.9':
|
||||
resolution: {integrity: sha512-lIJA6jup3ZZNkKFyUiy1q2tHWZv5q5bTaLxTnI85XIWr+sFCZG5oo3pOQESBkX4V95rv8sq9gEmEWySZvW7MBw==}
|
||||
'@storybook/test@8.6.12':
|
||||
resolution: {integrity: sha512-0BK1Eg+VD0lNMB1BtxqHE3tP9FdkUmohtvWG7cq6lWvMrbCmAmh3VWai3RMCCDOukPFpjabOr8BBRLVvhNpv2w==}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
|
||||
'@storybook/theming@8.6.9':
|
||||
resolution: {integrity: sha512-FQafe66itGnIh0V42R65tgFKyz0RshpIs0pTrxrdByuB2yKsep+f8ZgKLJE3fCKw/Egw4bUuICo2m8d7uOOumA==}
|
||||
'@storybook/theming@8.6.12':
|
||||
resolution: {integrity: sha512-6VjZg8HJ2Op7+KV7ihJpYrDnFtd9D1jrQnUS8LckcpuBXrIEbaut5+34ObY8ssQnSqkk2GwIZBBBQYQBCVvkOw==}
|
||||
peerDependencies:
|
||||
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
|
||||
|
||||
'@storybook/vue3-vite@8.6.9':
|
||||
resolution: {integrity: sha512-TTPzFwK7Yb1diC0o4uUrdmoDYVHRqRlH/xD8sZzud+N7MK+OJ7HPyCN8bw3e6HdsqLdJmfos45hRVTBgTYLOYA==}
|
||||
'@storybook/vue3-vite@8.6.12':
|
||||
resolution: {integrity: sha512-ihYH2TiV14B8V1mrCVVrbjuf+F6+V/78oWofVkvnUQnpwH4CnAySGf6bz6c6/Y6qEr9r30ECUe6/sS0TMt1ZAQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
vite: ^4.0.0 || ^5.0.0 || ^6.0.0
|
||||
|
||||
'@storybook/vue3@8.6.9':
|
||||
resolution: {integrity: sha512-asGlWyITyMGytNO+yXrWKcU+Ygk9G9zlmb0mVoTFxZGLiq/Wk3OmHmOlf5g0LyU8bkps43ZdkovEXfvMwQVm6A==}
|
||||
'@storybook/vue3@8.6.12':
|
||||
resolution: {integrity: sha512-mgGRMrFghDW5nHCDbdbhC4YUrOs7mCzwEuLZtdcvpB8TUPP62lTSnv3Gvcz8r12HjyIK6Jow9WgjTtdownGzkA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
storybook: ^8.6.9
|
||||
storybook: ^8.6.12
|
||||
vue: ^3.0.0
|
||||
|
||||
'@stylistic/eslint-plugin@4.2.0':
|
||||
@@ -4234,6 +4240,7 @@ packages:
|
||||
'@unraid/libvirt@2.1.0':
|
||||
resolution: {integrity: sha512-yF/sAzYukM+VpDdAebf0z0O2mE5mGOEAW5lIafFkYoMiu60zNkNmr5IoA9hWCMmQkBOUCam8RZGs9YNwRjMtMQ==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [x64, arm64]
|
||||
os: [linux, darwin]
|
||||
|
||||
'@unraid/shared-callbacks@1.1.1':
|
||||
@@ -5585,6 +5592,11 @@ packages:
|
||||
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||
engines: {'0': node >= 6.0}
|
||||
|
||||
concurrently@9.1.2:
|
||||
resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
confbox@0.1.8:
|
||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||
|
||||
@@ -10823,8 +10835,8 @@ packages:
|
||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
storybook@8.6.9:
|
||||
resolution: {integrity: sha512-Iw4+R4V3yX7MhXJaLBAT4oLtZ+SaTzX8KvUNZiQzvdD+TrFKVA3QKV8gvWjstGyU2dd+afE1Ph6EG5Xa2Az2CA==}
|
||||
storybook@8.6.12:
|
||||
resolution: {integrity: sha512-Z/nWYEHBTLK1ZBtAWdhxC0l5zf7ioJ7G4+zYqtTdYeb67gTnxNj80gehf8o8QY9L2zA2+eyMRGLC2V5fI7Z3Tw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
prettier: ^2 || ^3
|
||||
@@ -11247,6 +11259,10 @@ packages:
|
||||
resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tree-kill@1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
|
||||
trim-newlines@3.0.1:
|
||||
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -15430,125 +15446,125 @@ snapshots:
|
||||
|
||||
'@speed-highlight/core@1.2.7': {}
|
||||
|
||||
'@storybook/addon-actions@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-actions@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
'@types/uuid': 9.0.8
|
||||
dequal: 2.0.3
|
||||
polished: 4.3.1
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
uuid: 9.0.1
|
||||
|
||||
'@storybook/addon-backgrounds@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-backgrounds@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
memoizerific: 1.11.3
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
|
||||
'@storybook/addon-controls@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-controls@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
dequal: 2.0.3
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
|
||||
'@storybook/addon-docs@8.6.9(@types/react@19.0.8)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-docs@8.6.12(@types/react@19.0.8)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@mdx-js/react': 3.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||
'@storybook/blocks': 8.6.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/csf-plugin': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/react-dom-shim': 8.6.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/blocks': 8.6.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/csf-plugin': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/react-dom-shim': 8.6.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@storybook/addon-essentials@8.6.9(@types/react@19.0.8)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-essentials@8.6.12(@types/react@19.0.8)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/addon-actions': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-backgrounds': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-controls': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-docs': 8.6.9(@types/react@19.0.8)(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-highlight': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-measure': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-outline': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-toolbars': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/addon-viewport': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
'@storybook/addon-actions': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-backgrounds': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-controls': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-docs': 8.6.12(@types/react@19.0.8)(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-highlight': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-measure': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-outline': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-toolbars': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/addon-viewport': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@storybook/addon-highlight@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-highlight@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/addon-interactions@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-interactions@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
'@storybook/instrumenter': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/test': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/instrumenter': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/test': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
polished: 4.3.1
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
|
||||
'@storybook/addon-links@8.6.9(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-links@8.6.12(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
optionalDependencies:
|
||||
react: 19.0.0
|
||||
|
||||
'@storybook/addon-measure@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-measure@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
tiny-invariant: 1.3.3
|
||||
|
||||
'@storybook/addon-outline@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-outline@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
|
||||
'@storybook/addon-toolbars@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-toolbars@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/addon-viewport@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/addon-viewport@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
memoizerific: 1.11.3
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/blocks@8.6.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/blocks@8.6.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/icons': 1.4.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
optionalDependencies:
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
|
||||
'@storybook/builder-vite@8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))':
|
||||
'@storybook/builder-vite@8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))':
|
||||
dependencies:
|
||||
'@storybook/csf-plugin': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/csf-plugin': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
browser-assert: 1.2.1
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
vite: 6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1)
|
||||
|
||||
'@storybook/components@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/components@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/core@8.6.9(prettier@3.5.3)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/core@8.6.12(prettier@3.5.3)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/theming': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/theming': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
better-opn: 3.0.2
|
||||
browser-assert: 1.2.1
|
||||
esbuild: 0.25.1
|
||||
@@ -15567,9 +15583,9 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@storybook/csf-plugin@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/csf-plugin@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
unplugin: 1.16.1
|
||||
|
||||
'@storybook/global@5.0.0': {}
|
||||
@@ -15579,48 +15595,48 @@ snapshots:
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
|
||||
'@storybook/instrumenter@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/instrumenter@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
'@vitest/utils': 2.1.9
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/manager-api@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/manager-api@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/preview-api@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/preview-api@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/react-dom-shim@8.6.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/react-dom-shim@8.6.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
'@storybook/global': 5.0.0
|
||||
'@storybook/instrumenter': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/instrumenter': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@testing-library/dom': 10.4.0
|
||||
'@testing-library/jest-dom': 6.5.0
|
||||
'@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0)
|
||||
'@vitest/expect': 2.0.5
|
||||
'@vitest/spy': 2.0.5
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/theming@8.6.9(storybook@8.6.9(prettier@3.5.3))':
|
||||
'@storybook/theming@8.6.12(storybook@8.6.12(prettier@3.5.3))':
|
||||
dependencies:
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
|
||||
'@storybook/vue3-vite@8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))':
|
||||
'@storybook/vue3-vite@8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@storybook/builder-vite': 8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))
|
||||
'@storybook/vue3': 8.6.9(storybook@8.6.9(prettier@3.5.3))(vue@3.5.13(typescript@5.8.3))
|
||||
'@storybook/builder-vite': 8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))
|
||||
'@storybook/vue3': 8.6.12(storybook@8.6.12(prettier@3.5.3))(vue@3.5.13(typescript@5.8.3))
|
||||
find-package-json: 1.2.0
|
||||
magic-string: 0.30.17
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
typescript: 5.8.3
|
||||
vite: 6.2.3(@types/node@22.15.3)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1)
|
||||
vue-component-meta: 2.2.8(typescript@5.8.3)
|
||||
@@ -15628,15 +15644,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- vue
|
||||
|
||||
'@storybook/vue3@8.6.9(storybook@8.6.9(prettier@3.5.3))(vue@3.5.13(typescript@5.8.3))':
|
||||
'@storybook/vue3@8.6.12(storybook@8.6.12(prettier@3.5.3))(vue@3.5.13(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@storybook/components': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/components': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/global': 5.0.0
|
||||
'@storybook/manager-api': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/preview-api': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/theming': 8.6.9(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/manager-api': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/preview-api': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@storybook/theming': 8.6.12(storybook@8.6.12(prettier@3.5.3))
|
||||
'@vue/compiler-core': 3.5.13
|
||||
storybook: 8.6.9(prettier@3.5.3)
|
||||
storybook: 8.6.12(prettier@3.5.3)
|
||||
ts-dedent: 2.2.0
|
||||
type-fest: 2.19.0
|
||||
vue: 3.5.13(typescript@5.8.3)
|
||||
@@ -17762,6 +17778,16 @@ snapshots:
|
||||
readable-stream: 3.6.2
|
||||
typedarray: 0.0.6
|
||||
|
||||
concurrently@9.1.2:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
lodash: 4.17.21
|
||||
rxjs: 7.8.2
|
||||
shell-quote: 1.8.2
|
||||
supports-color: 8.1.1
|
||||
tree-kill: 1.2.2
|
||||
yargs: 17.7.2
|
||||
|
||||
confbox@0.1.8: {}
|
||||
|
||||
confbox@0.2.1: {}
|
||||
@@ -23821,9 +23847,9 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
storybook@8.6.9(prettier@3.5.3):
|
||||
storybook@8.6.12(prettier@3.5.3):
|
||||
dependencies:
|
||||
'@storybook/core': 8.6.9(prettier@3.5.3)(storybook@8.6.9(prettier@3.5.3))
|
||||
'@storybook/core': 8.6.12(prettier@3.5.3)(storybook@8.6.12(prettier@3.5.3))
|
||||
optionalDependencies:
|
||||
prettier: 3.5.3
|
||||
transitivePeerDependencies:
|
||||
@@ -24285,6 +24311,8 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
trim-newlines@3.0.1: {}
|
||||
|
||||
ts-api-utils@2.1.0(typescript@5.8.3):
|
||||
@@ -25244,7 +25272,7 @@ snapshots:
|
||||
isarray: 2.0.5
|
||||
which-boxed-primitive: 1.1.1
|
||||
which-collection: 1.0.2
|
||||
which-typed-array: 1.1.18
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
which-collection@1.0.2:
|
||||
dependencies:
|
||||
|
||||
@@ -22,9 +22,9 @@ const config: StorybookConfig = {
|
||||
autodocs: "tag",
|
||||
},
|
||||
async viteFinal(config) {
|
||||
config.root = dirname(require.resolve('@storybook/builder-vite'));
|
||||
return {
|
||||
...config,
|
||||
root: dirname(require.resolve('@storybook/builder-vite')),
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': join(dirname(new URL(import.meta.url).pathname), '../src'),
|
||||
@@ -32,6 +32,9 @@ const config: StorybookConfig = {
|
||||
'@/lib': join(dirname(new URL(import.meta.url).pathname), '../src/lib'),
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: [...(config.optimizeDeps?.include ?? []), '@unraid/tailwind-rem-to-rem'],
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["../src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["../stories/**/*", "../src/**/*"]
|
||||
}
|
||||
@@ -6,89 +6,134 @@ import prettier from 'eslint-plugin-prettier';
|
||||
import vuePlugin from 'eslint-plugin-vue';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
|
||||
files: ['**/*.ts', '**/*.tsx', '**/*.vue'],
|
||||
languageOptions: {
|
||||
parser: require('vue-eslint-parser'),
|
||||
parserOptions: {
|
||||
// Common rules shared across file types
|
||||
const commonRules = {
|
||||
'@typescript-eslint/no-unused-vars': ['off'],
|
||||
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
||||
'no-relative-import-paths/no-relative-import-paths': [
|
||||
'error',
|
||||
{ allowSameFolder: false, rootDir: 'src', prefix: '@' },
|
||||
],
|
||||
'prettier/prettier': 'error',
|
||||
'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
name: '__dirname',
|
||||
message: 'Use import.meta.url instead of __dirname in ESM',
|
||||
},
|
||||
{
|
||||
name: '__filename',
|
||||
message: 'Use import.meta.url instead of __filename in ESM',
|
||||
},
|
||||
],
|
||||
'eol-last': ['error', 'always'],
|
||||
'@typescript-eslint/no-explicit-any': [
|
||||
'error',
|
||||
{
|
||||
ignoreRestArgs: true,
|
||||
fixToUnknown: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Vue-specific rules
|
||||
const vueRules = {
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'always',
|
||||
component: 'always',
|
||||
},
|
||||
},
|
||||
],
|
||||
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
|
||||
'vue/component-definition-name-casing': ['error', 'PascalCase'],
|
||||
'vue/no-unsupported-features': [
|
||||
'error',
|
||||
{
|
||||
version: '^3.3.0',
|
||||
},
|
||||
],
|
||||
'vue/no-undef-components': ['error'],
|
||||
'vue/no-unused-properties': [
|
||||
'error',
|
||||
{
|
||||
groups: ['props'],
|
||||
deepData: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Common language options
|
||||
const commonLanguageOptions = {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
browser: true,
|
||||
window: true,
|
||||
document: true,
|
||||
es2022: true,
|
||||
HTMLElement: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default [
|
||||
// Base config from recommended configs
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
|
||||
// TypeScript Files (.ts)
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
globals: {
|
||||
browser: true,
|
||||
window: true,
|
||||
document: true,
|
||||
es2022: true,
|
||||
HTMLElement: true,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'no-relative-import-paths': noRelativeImportPaths,
|
||||
prettier: prettier,
|
||||
import: importPlugin,
|
||||
vue: vuePlugin,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': ['off'],
|
||||
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
||||
'no-relative-import-paths/no-relative-import-paths': [
|
||||
'error',
|
||||
{ allowSameFolder: false, rootDir: 'src', prefix: '@' },
|
||||
],
|
||||
'prettier/prettier': 'error',
|
||||
'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
name: '__dirname',
|
||||
message: 'Use import.meta.url instead of __dirname in ESM',
|
||||
},
|
||||
{
|
||||
name: '__filename',
|
||||
message: 'Use import.meta.url instead of __filename in ESM',
|
||||
},
|
||||
],
|
||||
'eol-last': ['error', 'always'],
|
||||
// Vue specific rules
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'always',
|
||||
component: 'always',
|
||||
parserOptions: {
|
||||
...commonLanguageOptions,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
|
||||
'vue/component-definition-name-casing': ['error', 'PascalCase'],
|
||||
'vue/no-unsupported-features': [
|
||||
'error',
|
||||
{
|
||||
version: '^3.3.0',
|
||||
},
|
||||
],
|
||||
'vue/no-undef-components': ['error'],
|
||||
'vue/no-unused-properties': [
|
||||
'error',
|
||||
{
|
||||
groups: ['props'],
|
||||
deepData: false,
|
||||
},
|
||||
],
|
||||
// Allow empty object types and any types in Vue component definitions
|
||||
'@typescript-eslint/no-explicit-any': [
|
||||
'error',
|
||||
{
|
||||
ignoreRestArgs: true,
|
||||
fixToUnknown: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: {
|
||||
'no-relative-import-paths': noRelativeImportPaths,
|
||||
prettier: prettier,
|
||||
import: importPlugin,
|
||||
},
|
||||
rules: {
|
||||
...commonRules,
|
||||
},
|
||||
},
|
||||
|
||||
ignores: ['src/graphql/generated/client/**/*'],
|
||||
});
|
||||
|
||||
// Vue Files (.vue)
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parser: require('vue-eslint-parser'),
|
||||
parserOptions: {
|
||||
...commonLanguageOptions,
|
||||
parser: tseslint.parser,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'no-relative-import-paths': noRelativeImportPaths,
|
||||
prettier: prettier,
|
||||
import: importPlugin,
|
||||
vue: vuePlugin,
|
||||
},
|
||||
rules: {
|
||||
...commonRules,
|
||||
...vueRules,
|
||||
},
|
||||
},
|
||||
|
||||
// Ignores
|
||||
{
|
||||
ignores: ['src/graphql/generated/client/**/*'],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
"test:ui": "vitest --ui",
|
||||
"coverage": "vitest run --coverage",
|
||||
"// Build": "",
|
||||
"prebuild": "npm run clean",
|
||||
"build": "vite build",
|
||||
"build:watch": "vite build -c vite.web-component.ts --mode production --watch",
|
||||
"build:watch": "concurrently \"pnpm build:wc --watch\" \"pnpm build --watch\"",
|
||||
"build:watch:main": "vite build --watch",
|
||||
"build:wc": "REM_PLUGIN=true vite build -c vite.web-component.ts --mode production",
|
||||
"build:all": "vite build && vite build -c vite.web-component.ts --mode production",
|
||||
"clean": "rimraf dist",
|
||||
@@ -60,11 +60,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||
"@storybook/addon-essentials": "^8.5.8",
|
||||
"@storybook/addon-interactions": "^8.5.8",
|
||||
"@storybook/addon-links": "^8.5.8",
|
||||
"@storybook/builder-vite": "^8.5.8",
|
||||
"@storybook/vue3-vite": "^8.5.8",
|
||||
"@storybook/addon-essentials": "^8.6.12",
|
||||
"@storybook/addon-interactions": "^8.6.12",
|
||||
"@storybook/addon-links": "^8.6.12",
|
||||
"@storybook/builder-vite": "^8.6.12",
|
||||
"@storybook/vue3": "^8.6.12",
|
||||
"@storybook/vue3-vite": "^8.6.12",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@testing-library/vue": "^8.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
@@ -79,6 +80,7 @@
|
||||
"@vue/test-utils": "^2.4.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"concurrently": "^9.1.2",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
@@ -90,7 +92,7 @@
|
||||
"prettier": "3.5.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"rimraf": "^6.0.1",
|
||||
"storybook": "^8.5.8",
|
||||
"storybook": "^8.6.12",
|
||||
"tailwind-rem-to-rem": "github:unraid/tailwind-rem-to-rem",
|
||||
"tailwindcss": "^3.0.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
|
||||
20
unraid-ui/src/components.ts
Normal file
20
unraid-ui/src/components.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export * from '@/components/common/badge';
|
||||
export * from '@/components/brand';
|
||||
export * from '@/components/common/button';
|
||||
export * from '@/components/layout';
|
||||
export * from '@/components/common/dropdown-menu';
|
||||
export * from '@/components/common/loading';
|
||||
export * from '@/components/form/input';
|
||||
export * from '@/components/form/label';
|
||||
export * from '@/components/form/number';
|
||||
export * from '@/components/form/lightswitch';
|
||||
export * from '@/components/form/select';
|
||||
export * from '@/components/form/switch';
|
||||
export * from '@/components/common/scroll-area';
|
||||
export * from '@/components/common/stepper';
|
||||
export * from '@/components/common/sheet';
|
||||
export * from '@/components/common/tabs';
|
||||
export * from '@/components/common/tooltip';
|
||||
export * from '@/components/common/toast';
|
||||
export * from '@/components/common/popover';
|
||||
export * from '@/components/brand';
|
||||
@@ -1,5 +1,6 @@
|
||||
export { default as DropdownMenu } from './DropdownMenu.vue';
|
||||
import DropdownMenu from './DropdownMenu.vue';
|
||||
|
||||
export { DropdownMenu };
|
||||
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue';
|
||||
export { default as DropdownMenuContent } from './DropdownMenuContent.vue';
|
||||
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue';
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
export { Badge } from '@/components/common/badge';
|
||||
export { BrandButton, BrandLoading, BrandLogo, BrandLogoConnect } from '@/components/brand';
|
||||
export { Button } from '@/components/common/button';
|
||||
export { CardWrapper, PageContainer } from '@/components/layout';
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
} from '@/components/common/dropdown-menu';
|
||||
export { Bar, Error, Spinner } from '@/components/common/loading';
|
||||
export { Input } from '@/components/form/input';
|
||||
export { Label } from '@/components/form/label';
|
||||
export { Lightswitch } from '@/components/form/lightswitch';
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectItemText,
|
||||
SelectLabel,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/form/select';
|
||||
export { Switch } from '@/components/form/switch';
|
||||
export { ScrollArea, ScrollBar } from '@/components/common/scroll-area';
|
||||
export {
|
||||
Sheet,
|
||||
SheetTrigger,
|
||||
SheetContent,
|
||||
SheetClose,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
} from '@/components/common/sheet';
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/common/tabs';
|
||||
export { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from '@/components/common/tooltip';
|
||||
export { Toaster } from '@/components/common/toast';
|
||||
@@ -1,61 +0,0 @@
|
||||
<template>
|
||||
<div :class="styles.categorization.root">
|
||||
<div :class="styles.categorization.category">
|
||||
<template v-for="(category, index) in categories" :key="`category-${index}`">
|
||||
<div v-if="category.value.visible" @click="selected = index">
|
||||
<button
|
||||
:class="[selected === index ? styles.categorization.selected : '']"
|
||||
:disabled="!category.value.enabled"
|
||||
>
|
||||
<label>{{ category.value.label }}</label>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div :class="styles.categorization.panel">
|
||||
<DispatchRenderer
|
||||
v-if="categories[selected]"
|
||||
:schema="layout.schema"
|
||||
:uischema="categories[selected].value.uischema"
|
||||
:path="layout.path"
|
||||
:enabled="layout.enabled"
|
||||
:renderers="layout.renderers"
|
||||
:cells="layout.cells"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { JsonFormsRendererRegistryEntry, Layout } from '@jsonforms/core';
|
||||
import { and, categorizationHasCategory, isCategorization, rankWith } from '@jsonforms/core';
|
||||
import {
|
||||
DispatchRenderer,
|
||||
rendererProps,
|
||||
useJsonFormsCategorization,
|
||||
type RendererProps,
|
||||
} from '@jsonforms/vue';
|
||||
import { useVanillaLayout } from '@jsonforms/vue-vanilla';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
const layoutRenderer = defineComponent({
|
||||
name: 'CategorizationAccordionRenderer',
|
||||
components: {
|
||||
DispatchRenderer,
|
||||
},
|
||||
props: {
|
||||
...rendererProps<Layout>(),
|
||||
},
|
||||
setup(props: RendererProps<Layout>) {
|
||||
return useVanillaLayout(useJsonFormsCategorization(props));
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: 0,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default layoutRenderer;
|
||||
</script>
|
||||
71
unraid-ui/src/forms/LabelRenderer.vue
Normal file
71
unraid-ui/src/forms/LabelRenderer.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import { rankWith, uiTypeIs, type UISchemaElement } from '@jsonforms/core';
|
||||
import { rendererProps, useJsonFormsRenderer } from '@jsonforms/vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
// Define a type for our specific Label UI Schema
|
||||
interface LabelUISchema extends UISchemaElement {
|
||||
text?: string;
|
||||
options?: {
|
||||
description?: string;
|
||||
format?: 'title' | 'heading' | 'documentation' | string; // Add other formats as needed
|
||||
};
|
||||
}
|
||||
|
||||
const props = defineProps(rendererProps<UISchemaElement>());
|
||||
|
||||
// Destructure the renderer ref from the hook's return value
|
||||
const { renderer } = useJsonFormsRenderer(props);
|
||||
|
||||
// Cast the uischema inside the computed ref to our specific type
|
||||
const typedUISchema = computed(() => renderer.value.uischema as LabelUISchema);
|
||||
|
||||
// Access properties via renderer.value
|
||||
const labelText = computed(() => typedUISchema.value.text);
|
||||
const descriptionText = computed(() => typedUISchema.value.options?.description);
|
||||
const labelFormat = computed(() => typedUISchema.value.options?.format);
|
||||
|
||||
// --- Access visibility via renderer.value ---
|
||||
const isVisible = computed(() => renderer.value.visible); // Use renderer.value.visible for visibility check
|
||||
|
||||
// Conditional classes or elements based on format
|
||||
const labelClass = computed(() => {
|
||||
switch (labelFormat.value) {
|
||||
case 'title':
|
||||
return 'text-xl font-semibold mb-2'; // Example styling for title
|
||||
case 'heading':
|
||||
return 'text-lg font-medium mt-4 mb-1'; // Example styling for heading
|
||||
default:
|
||||
return 'font-medium'; // Default label styling
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionClass = computed(() => {
|
||||
switch (labelFormat.value) {
|
||||
case 'documentation':
|
||||
return 'text-sm text-gray-500 italic p-2 border-l-4 border-gray-300 bg-gray-50 my-2'; // Example styling for documentation
|
||||
default:
|
||||
return 'text-sm text-gray-600 mt-1'; // Default description styling
|
||||
}
|
||||
});
|
||||
|
||||
// Use v-html for description if it might contain HTML (like the documentation link)
|
||||
// Ensure any HTML is sanitized if it comes from untrusted sources.
|
||||
// Assuming the documentation link is safe here.
|
||||
const allowHtml = computed(() => labelFormat.value === 'documentation');
|
||||
|
||||
// --- Tester Export ---
|
||||
export const labelRendererTester = rankWith(
|
||||
10, // Adjust rank as needed
|
||||
uiTypeIs('Label')
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Use the computed isVisible based on renderer.value.visible -->
|
||||
<div v-if="isVisible" class="my-2">
|
||||
<label v-if="labelText" :class="labelClass">{{ labelText }}</label>
|
||||
<p v-if="descriptionText && allowHtml" :class="descriptionClass" v-html="descriptionText" />
|
||||
<p v-else-if="descriptionText" :class="descriptionClass">{{ descriptionText }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,62 +8,42 @@ import StepperTitle from '@/components/common/stepper/StepperTitle.vue';
|
||||
import StepperTrigger from '@/components/common/stepper/StepperTrigger.vue';
|
||||
import { CheckIcon } from '@heroicons/vue/24/solid'; // Example icon
|
||||
import {
|
||||
// ControlElement, // No longer needed here, DispatchRenderer handles it
|
||||
type JsonSchema,
|
||||
type Layout,
|
||||
type UISchemaElement,
|
||||
// Actions, // No longer needed
|
||||
} from '@jsonforms/core';
|
||||
import { DispatchRenderer, useJsonFormsLayout, type RendererProps } from '@jsonforms/vue';
|
||||
import { computed, inject } from 'vue';
|
||||
import { computed, ref } from 'vue'; // Import ref, remove inject/onMounted
|
||||
|
||||
// Define props based on RendererProps<Layout>
|
||||
const props = defineProps<RendererProps<Layout>>();
|
||||
|
||||
// --- JSON Forms Composables and Context ---
|
||||
const { layout } = useJsonFormsLayout(props);
|
||||
// Inject core jsonforms functionality (safer than relying on potentially non-exported composables)
|
||||
const jsonforms = inject<any>('jsonforms');
|
||||
const core = computed(() => jsonforms?.core);
|
||||
const dispatch = computed(() => jsonforms?.dispatch);
|
||||
|
||||
// --- Step Configuration ---
|
||||
|
||||
// Expect options.steps: [{ label: string, description: string }, ...]
|
||||
const stepsConfig = computed(() => props.uischema.options?.steps || []);
|
||||
|
||||
// Get the path to the step control property from uischema options (e.g., '#/properties/configStep')
|
||||
const stepControlPath = computed(() => props.uischema.options?.stepControl as string | undefined);
|
||||
|
||||
// --- Current Step Logic ---
|
||||
|
||||
// Function to safely extract the step value from the data without lodash
|
||||
const getCurrentStep = () => {
|
||||
if (!stepControlPath.value || !core?.value?.data) return 0;
|
||||
const pathSegments = stepControlPath.value.startsWith('#/')
|
||||
? stepControlPath.value.substring(2).split('/')
|
||||
: stepControlPath.value.split('.'); // Allow dot notation too
|
||||
// Use local state for the current step index
|
||||
const localCurrentStep = ref(0);
|
||||
|
||||
let currentData = core.value.data;
|
||||
for (const segment of pathSegments) {
|
||||
if (currentData === null || typeof currentData !== 'object' || !(segment in currentData)) {
|
||||
return 0; // Path not found or data structure incorrect, default to step 0
|
||||
}
|
||||
currentData = currentData[segment];
|
||||
}
|
||||
return typeof currentData === 'number' ? currentData : 0; // Return step number or default
|
||||
};
|
||||
|
||||
const currentStep = computed(getCurrentStep);
|
||||
// currentStep now reflects the local state
|
||||
const currentStep = computed(() => localCurrentStep.value);
|
||||
|
||||
// --- Step Update Logic ---
|
||||
|
||||
const updateStep = (newStep: number) => {
|
||||
if (!stepControlPath.value || !dispatch?.value || newStep < 0 || newStep >= stepsConfig.value.length)
|
||||
// Validate step index bounds
|
||||
if (newStep < 0 || newStep >= stepsConfig.value.length) {
|
||||
return;
|
||||
|
||||
// Use Actions.update to modify the data property controlling the step
|
||||
const updateAction = jsonforms.Actions.update(stepControlPath.value, newStep);
|
||||
dispatch.value(updateAction);
|
||||
}
|
||||
// Simply update the local state
|
||||
localCurrentStep.value = newStep;
|
||||
};
|
||||
|
||||
// --- Filtered Elements for Current Step ---
|
||||
@@ -91,7 +71,6 @@ const getStepState = (stepIndex: number): StepState => {
|
||||
<StepperItem
|
||||
v-for="(step, index) in stepsConfig"
|
||||
:key="index"
|
||||
v-slot="{ state }"
|
||||
class="relative flex w-full flex-col items-center justify-center"
|
||||
:step="index + 1"
|
||||
:disabled="getStepState(index) === 'inactive'"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* @prop renderers - Available renderers
|
||||
* @prop cells - Available cells
|
||||
*/
|
||||
import { Label } from '@/components/form/label';
|
||||
|
||||
import type { VerticalLayout } from '@jsonforms/core';
|
||||
import { DispatchRenderer, type RendererProps } from '@jsonforms/vue';
|
||||
import { computed } from 'vue';
|
||||
@@ -21,14 +21,14 @@ import { computed } from 'vue';
|
||||
const props = defineProps<RendererProps<VerticalLayout>>();
|
||||
|
||||
const elements = computed(() => {
|
||||
console.log('elements', props.uischema?.elements);
|
||||
return props.uischema?.elements || [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-settings items-baseline gap-y-6">
|
||||
<div class="flex flex-col gap-y-2">
|
||||
<template v-for="(element, index) in elements" :key="index">
|
||||
<Label v-if="element.label" class="text-end">{{ element.label ?? index }}</Label>
|
||||
<DispatchRenderer
|
||||
class="ml-10"
|
||||
:schema="props.schema"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import CategorizationAccordionRenderer from '@/forms/CategorizationAccordionRenderer.vue';
|
||||
import comboBoxRenderer from '@/forms/ComboBoxField.vue';
|
||||
import inputFieldRenderer from '@/forms/InputField.vue';
|
||||
import MissingRenderer from '@/forms/MissingRenderer.vue';
|
||||
@@ -12,7 +11,6 @@ import VerticalLayout from '@/forms/VerticalLayout.vue';
|
||||
import {
|
||||
and,
|
||||
isBooleanControl,
|
||||
isCategorization,
|
||||
isControl,
|
||||
isEnumControl,
|
||||
isIntegerControl,
|
||||
@@ -26,6 +24,7 @@ import {
|
||||
uiTypeIs,
|
||||
} from '@jsonforms/core';
|
||||
import type { JsonFormsRendererRegistryEntry, JsonSchema } from '@jsonforms/core';
|
||||
import { LabelRenderer } from '@jsonforms/vue-vanilla';
|
||||
|
||||
const isStringArray = (schema: JsonSchema): boolean => {
|
||||
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return false;
|
||||
@@ -45,7 +44,7 @@ const formSelectEntry: JsonFormsRendererRegistryEntry = {
|
||||
|
||||
const formComboBoxEntry: JsonFormsRendererRegistryEntry = {
|
||||
renderer: comboBoxRenderer,
|
||||
tester: rankWith(4, and(isControl, optionIs('type', 'combobox'))),
|
||||
tester: rankWith(4, and(isControl, optionIs('format', 'combobox'))),
|
||||
};
|
||||
|
||||
const numberFieldEntry: JsonFormsRendererRegistryEntry = {
|
||||
@@ -73,11 +72,6 @@ const missingRendererEntry: JsonFormsRendererRegistryEntry = {
|
||||
tester: rankWith(3, isControl),
|
||||
};
|
||||
|
||||
const categorizationAccordionEntry: JsonFormsRendererRegistryEntry = {
|
||||
renderer: CategorizationAccordionRenderer,
|
||||
tester: rankWith(5, isCategorization),
|
||||
};
|
||||
|
||||
const verticalLayoutEntry: JsonFormsRendererRegistryEntry = {
|
||||
renderer: VerticalLayout,
|
||||
tester: rankWith(2, and(isLayout, uiTypeIs('VerticalLayout'))),
|
||||
@@ -88,14 +82,13 @@ const steppedLayoutEntry: JsonFormsRendererRegistryEntry = {
|
||||
tester: rankWith(3, and(isLayout, uiTypeIs('SteppedLayout'))),
|
||||
};
|
||||
|
||||
/**
|
||||
* JSONForms renderers for Unraid UI
|
||||
*
|
||||
* This file exports a list of JSONForms renderers that are used in the Unraid UI.
|
||||
* It combines the vanilla renderers with the custom renderers defined in
|
||||
* `@unraid/ui/src/forms/renderer-entries.ts`.
|
||||
*/
|
||||
const labelRendererEntry: JsonFormsRendererRegistryEntry = {
|
||||
renderer: LabelRenderer,
|
||||
tester: rankWith(3, and(uiTypeIs('Label'))),
|
||||
};
|
||||
|
||||
export const jsonFormsRenderers = [
|
||||
labelRendererEntry,
|
||||
verticalLayoutEntry,
|
||||
steppedLayoutEntry,
|
||||
formSwitchEntry,
|
||||
@@ -106,5 +99,4 @@ export const jsonFormsRenderers = [
|
||||
preconditionsLabelEntry,
|
||||
stringArrayEntry,
|
||||
missingRendererEntry,
|
||||
categorizationAccordionEntry,
|
||||
];
|
||||
|
||||
@@ -1,177 +1,18 @@
|
||||
// Styles
|
||||
import '@/styles/index.css';
|
||||
import {
|
||||
BrandButton,
|
||||
brandButtonVariants,
|
||||
BrandLoading,
|
||||
brandLoadingVariants,
|
||||
BrandLogo,
|
||||
BrandLogoConnect,
|
||||
type BrandButtonProps,
|
||||
} from '@/components/brand';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@/components/common/accordion';
|
||||
// Components
|
||||
import { Badge, type BadgeProps } from '@/components/common/badge';
|
||||
import { Button, buttonVariants, type ButtonProps } from '@/components/common/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuArrow,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/common/dropdown-menu';
|
||||
import { Bar, Error, Spinner } from '@/components/common/loading';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/common/popover';
|
||||
import { ScrollArea, ScrollBar } from '@/components/common/scroll-area';
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@/components/common/sheet';
|
||||
import {
|
||||
Stepper,
|
||||
StepperDescription,
|
||||
StepperItem,
|
||||
StepperSeparator,
|
||||
StepperTitle,
|
||||
StepperTrigger,
|
||||
} from '@/components/common/stepper';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/common/tabs';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/common/tooltip';
|
||||
import { Input } from '@/components/form/input';
|
||||
import { Label } from '@/components/form/label';
|
||||
import { Lightswitch } from '@/components/form/lightswitch';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectItemText,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/form/select';
|
||||
import { Switch } from '@/components/form/switch';
|
||||
import { CardWrapper, PageContainer } from '@/components/layout';
|
||||
// Composables
|
||||
import useTeleport from '@/composables/useTeleport';
|
||||
// Lib
|
||||
import { cn } from '@/lib/utils';
|
||||
// Config
|
||||
import tailwindConfig from '../tailwind.config';
|
||||
export * from '@/components';
|
||||
|
||||
// Export
|
||||
export {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
Bar,
|
||||
Badge,
|
||||
BrandButton,
|
||||
brandButtonVariants,
|
||||
BrandLoading,
|
||||
brandLoadingVariants,
|
||||
BrandLogo,
|
||||
BrandLogoConnect,
|
||||
Button,
|
||||
buttonVariants,
|
||||
CardWrapper,
|
||||
cn,
|
||||
DropdownMenu,
|
||||
DropdownMenuArrow,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuPortal,
|
||||
Error,
|
||||
Input,
|
||||
Label,
|
||||
PageContainer,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
ScrollBar,
|
||||
ScrollArea,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectItemText,
|
||||
SelectLabel,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
Spinner,
|
||||
Stepper,
|
||||
StepperDescription,
|
||||
StepperItem,
|
||||
StepperSeparator,
|
||||
StepperTitle,
|
||||
StepperTrigger,
|
||||
Switch,
|
||||
tailwindConfig,
|
||||
Lightswitch,
|
||||
Tabs,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
TabsContent,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
TooltipProvider,
|
||||
useTeleport,
|
||||
|
||||
// Type exports
|
||||
type BrandButtonProps,
|
||||
type BadgeProps,
|
||||
type ButtonProps,
|
||||
};
|
||||
export { Toaster } from '@/components/common/toast';
|
||||
export * from '@/components/common/popover';
|
||||
export * from '@/components/form/number';
|
||||
// JsonForms
|
||||
export * from '@/forms/renderers';
|
||||
|
||||
// Lib
|
||||
export * from '@/lib/utils';
|
||||
|
||||
// Config
|
||||
export { default as tailwindConfig } from '../tailwind.config';
|
||||
|
||||
// Composables
|
||||
export { default as useTeleport } from '@/composables/useTeleport';
|
||||
|
||||
// Additional exports not in components.ts
|
||||
|
||||
@@ -10,25 +10,68 @@ type RegisterParams = {
|
||||
pathToSharedCss?: string;
|
||||
};
|
||||
|
||||
// Type for our simplified Vue component representation
|
||||
type CustomElementComponent = {
|
||||
styles?: string[];
|
||||
render?: Function;
|
||||
setup?: Function;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export function registerAllComponents(params: RegisterParams = {}) {
|
||||
const { namePrefix = 'uui', pathToSharedCss = './src/styles/index.css' } = params;
|
||||
Object.entries(Components).forEach(([name, component]) => {
|
||||
// add our shared css to each web component
|
||||
component.styles ??= [];
|
||||
component.styles.unshift(`@import "${pathToSharedCss}"`);
|
||||
|
||||
Object.entries(Components).forEach(([name, originalComponent]) => {
|
||||
// Use explicit type assertion instead of type predicates
|
||||
try {
|
||||
// Skip anything that doesn't look like a Vue component
|
||||
if (typeof originalComponent !== 'object' || originalComponent === null) {
|
||||
if (debugImports) {
|
||||
console.log(`[register components] Skipping non-object: ${name}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip function values
|
||||
if (typeof originalComponent === 'function') {
|
||||
if (debugImports) {
|
||||
console.log(`[register components] Skipping function: ${name}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if not a Vue component
|
||||
if (!('render' in originalComponent || 'setup' in originalComponent)) {
|
||||
if (debugImports) {
|
||||
console.log(`[register components] Skipping non-component object: ${name}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// translate ui component names from PascalCase to kebab-case
|
||||
let elementName = kebabCase(name);
|
||||
if (!elementName) {
|
||||
console.log('[register components] Could not translate component name to kebab-case:', name);
|
||||
elementName = name;
|
||||
}
|
||||
elementName = namePrefix + elementName;
|
||||
// Now we can safely use type assertion since we've validated the component
|
||||
const component = originalComponent as CustomElementComponent;
|
||||
|
||||
// add our shared css to each web component
|
||||
component.styles ??= [];
|
||||
component.styles.unshift(`@import "${pathToSharedCss}"`);
|
||||
|
||||
// register custom web components
|
||||
if (debugImports) {
|
||||
console.log(name, elementName, component.styles);
|
||||
// translate ui component names from PascalCase to kebab-case
|
||||
let elementName = kebabCase(name);
|
||||
if (!elementName) {
|
||||
console.log('[register components] Could not translate component name to kebab-case:', name);
|
||||
elementName = name;
|
||||
}
|
||||
elementName = namePrefix + elementName;
|
||||
|
||||
// register custom web components
|
||||
if (debugImports) {
|
||||
console.log(name, elementName, component.styles);
|
||||
}
|
||||
|
||||
// Use appropriate casting for defineCustomElement
|
||||
customElements.define(elementName, defineCustomElement(component as any));
|
||||
} catch (error) {
|
||||
console.error(`[register components] Error registering component ${name}:`, error);
|
||||
}
|
||||
customElements.define(elementName, defineCustomElement(component));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3';
|
||||
import { MoreVertical } from 'lucide-vue-next';
|
||||
import Button from '../../../src/components/common/button/Button.vue';
|
||||
import DropdownMenu from '../../../src/components/common/dropdown-menu/DropdownMenu.vue';
|
||||
import DropdownMenuArrow from '../../../src/components/common/dropdown-menu/DropdownMenuArrow.vue';
|
||||
import DropdownMenuContent from '../../../src/components/common/dropdown-menu/DropdownMenuContent.vue';
|
||||
import DropdownMenuItem from '../../../src/components/common/dropdown-menu/DropdownMenuItem.vue';
|
||||
import DropdownMenuLabel from '../../../src/components/common/dropdown-menu/DropdownMenuLabel.vue';
|
||||
import DropdownMenuSeparator from '../../../src/components/common/dropdown-menu/DropdownMenuSeparator.vue';
|
||||
import DropdownMenuTrigger from '../../../src/components/common/dropdown-menu/DropdownMenuTrigger.vue';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuArrow,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/common/dropdown-menu';
|
||||
import { Button } from '@/components/common/button';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Common/DropdownMenu',
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"node",
|
||||
"happy-dom",
|
||||
"@vue/test-utils",
|
||||
"@testing-library/vue"
|
||||
"@testing-library/vue",
|
||||
],
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
@@ -44,7 +44,10 @@
|
||||
"tailwind.config.ts",
|
||||
"src/theme/**/*.ts",
|
||||
"**/*.config.ts",
|
||||
"eslint.config.ts"
|
||||
"eslint.config.ts",
|
||||
"stories/**/*.ts",
|
||||
"stories/**/*.tsx",
|
||||
"stories/**/*.vue"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
||||
@@ -10,7 +10,6 @@ import type { CreateRCloneRemoteInput } from '~/composables/gql/graphql';
|
||||
import {
|
||||
CREATE_REMOTE,
|
||||
GET_RCLONE_CONFIG_FORM,
|
||||
LIST_REMOTES,
|
||||
} from '~/components/RClone/graphql/settings.query';
|
||||
import { useUnraidApiStore } from '~/store/unraidApi';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user