mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
fix(editor): Fix design system typecheck errors (no-changelog) (#9447)
This commit is contained in:
@@ -3,6 +3,7 @@ import { computed, ref } from 'vue';
|
|||||||
import { uid } from '../../utils';
|
import { uid } from '../../utils';
|
||||||
import { ElColorPicker } from 'element-plus';
|
import { ElColorPicker } from 'element-plus';
|
||||||
import N8nInput from '../N8nInput';
|
import N8nInput from '../N8nInput';
|
||||||
|
import type { ElementPlusSizePropType } from '@/types';
|
||||||
|
|
||||||
export type ColorPickerProps = {
|
export type ColorPickerProps = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -19,10 +20,12 @@ export type ColorPickerProps = {
|
|||||||
defineOptions({ name: 'N8nColorPicker' });
|
defineOptions({ name: 'N8nColorPicker' });
|
||||||
const props = withDefaults(defineProps<ColorPickerProps>(), {
|
const props = withDefaults(defineProps<ColorPickerProps>(), {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
size: 'medium',
|
size: 'default',
|
||||||
showAlpha: false,
|
showAlpha: false,
|
||||||
colorFormat: 'hex',
|
colorFormat: 'hex',
|
||||||
popperClass: '',
|
popperClass: '',
|
||||||
|
predefine: undefined,
|
||||||
|
modelValue: undefined,
|
||||||
showInput: true,
|
showInput: true,
|
||||||
name: uid('color-picker'),
|
name: uid('color-picker'),
|
||||||
});
|
});
|
||||||
@@ -30,7 +33,7 @@ const props = withDefaults(defineProps<ColorPickerProps>(), {
|
|||||||
const color = ref(props.modelValue);
|
const color = ref(props.modelValue);
|
||||||
|
|
||||||
const colorPickerProps = computed(() => {
|
const colorPickerProps = computed(() => {
|
||||||
const { showInput, ...rest } = props;
|
const { showInput, modelValue, size, ...rest } = props;
|
||||||
return rest;
|
return rest;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,6 +43,8 @@ const emit = defineEmits<{
|
|||||||
(event: 'active-change', value: string): void;
|
(event: 'active-change', value: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const resolvedSize = computed(() => props.size as ElementPlusSizePropType);
|
||||||
|
|
||||||
const onChange = (value: string) => {
|
const onChange = (value: string) => {
|
||||||
emit('change', value);
|
emit('change', value);
|
||||||
};
|
};
|
||||||
@@ -61,7 +66,7 @@ const onColorSelect = (value: string) => {
|
|||||||
<span :class="['n8n-color-picker', $style.component]">
|
<span :class="['n8n-color-picker', $style.component]">
|
||||||
<ElColorPicker
|
<ElColorPicker
|
||||||
v-bind="colorPickerProps"
|
v-bind="colorPickerProps"
|
||||||
size="default"
|
:size="resolvedSize"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
@active-change="onActiveChange"
|
@active-change="onActiveChange"
|
||||||
@update:model-value="onColorSelect"
|
@update:model-value="onColorSelect"
|
||||||
@@ -70,7 +75,7 @@ const onColorSelect = (value: string) => {
|
|||||||
v-if="showInput"
|
v-if="showInput"
|
||||||
:class="$style.input"
|
:class="$style.input"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:size="props.size"
|
:size="size"
|
||||||
:model-value="color"
|
:model-value="color"
|
||||||
:name="name"
|
:name="name"
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ exports[`components > N8nColorPicker > should render with input 1`] = `
|
|||||||
<!--teleport end-->
|
<!--teleport end-->
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="el-input el-input--medium n8n-input input input"
|
class="el-input el-input--default n8n-input input input"
|
||||||
data-v-dab78bb8=""
|
data-v-dab78bb8=""
|
||||||
>
|
>
|
||||||
<!-- input -->
|
<!-- input -->
|
||||||
@@ -79,7 +79,6 @@ exports[`components > N8nColorPicker > should render with input 1`] = `
|
|||||||
<input
|
<input
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="el-input__inner"
|
class="el-input__inner"
|
||||||
maxlength="Infinity"
|
|
||||||
name="color-picker"
|
name="color-picker"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
rows="2"
|
rows="2"
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<N8nCheckbox
|
<N8nCheckbox
|
||||||
v-if="type === 'checkbox'"
|
v-if="type === 'checkbox'"
|
||||||
v-bind="$props"
|
|
||||||
ref="inputRef"
|
ref="inputRef"
|
||||||
|
:label="label"
|
||||||
|
:disabled="disabled"
|
||||||
|
:label-size="labelSize as CheckboxLabelSizePropType"
|
||||||
|
:model-value="modelValue as CheckboxModelValuePropType"
|
||||||
@update:model-value="onUpdateModelValue"
|
@update:model-value="onUpdateModelValue"
|
||||||
@focus="onFocus"
|
@focus="onFocus"
|
||||||
/>
|
/>
|
||||||
@@ -17,7 +20,7 @@
|
|||||||
{{ tooltipText }}
|
{{ tooltipText }}
|
||||||
</template>
|
</template>
|
||||||
<ElSwitch
|
<ElSwitch
|
||||||
:model-value="modelValue"
|
:model-value="modelValue as SwitchModelValuePropType"
|
||||||
:active-color="activeColor"
|
:active-color="activeColor"
|
||||||
:inactive-color="inactiveColor"
|
:inactive-color="inactiveColor"
|
||||||
@update:model-value="onUpdateModelValue"
|
@update:model-value="onUpdateModelValue"
|
||||||
@@ -59,9 +62,9 @@
|
|||||||
v-else
|
v-else
|
||||||
ref="inputRef"
|
ref="inputRef"
|
||||||
:name="name"
|
:name="name"
|
||||||
:type="type"
|
:type="type as InputTypePropType"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:model-value="modelValue"
|
:model-value="modelValue as InputModelValuePropType"
|
||||||
:maxlength="maxlength"
|
:maxlength="maxlength"
|
||||||
:autocomplete="autocomplete"
|
:autocomplete="autocomplete"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@@ -99,7 +102,18 @@ import N8nCheckbox from '../N8nCheckbox';
|
|||||||
import { ElSwitch } from 'element-plus';
|
import { ElSwitch } from 'element-plus';
|
||||||
|
|
||||||
import { getValidationError, VALIDATORS } from './validators';
|
import { getValidationError, VALIDATORS } from './validators';
|
||||||
import type { Rule, RuleGroup, IValidator, Validatable, FormState } from '../../types';
|
import type {
|
||||||
|
Rule,
|
||||||
|
RuleGroup,
|
||||||
|
IValidator,
|
||||||
|
Validatable,
|
||||||
|
InputModelValuePropType,
|
||||||
|
InputTypePropType,
|
||||||
|
SwitchModelValuePropType,
|
||||||
|
CheckboxModelValuePropType,
|
||||||
|
CheckboxLabelSizePropType,
|
||||||
|
InputAutocompletePropType,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
import { t } from '../../locale';
|
import { t } from '../../locale';
|
||||||
|
|
||||||
@@ -120,10 +134,10 @@ export interface Props {
|
|||||||
validators?: { [key: string]: IValidator | RuleGroup };
|
validators?: { [key: string]: IValidator | RuleGroup };
|
||||||
maxlength?: number;
|
maxlength?: number;
|
||||||
options?: Array<{ value: string | number; label: string; disabled?: boolean }>;
|
options?: Array<{ value: string | number; label: string; disabled?: boolean }>;
|
||||||
autocomplete?: string;
|
autocomplete?: InputAutocompletePropType;
|
||||||
name?: string;
|
name?: string;
|
||||||
focusInitially?: boolean;
|
focusInitially?: boolean;
|
||||||
labelSize?: 'small' | 'medium';
|
labelSize?: 'small' | 'medium' | 'large';
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
activeLabel?: string;
|
activeLabel?: string;
|
||||||
activeColor?: string;
|
activeColor?: string;
|
||||||
@@ -206,7 +220,7 @@ function onBlur() {
|
|||||||
$emit('blur');
|
$emit('blur');
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUpdateModelValue(value: FormState) {
|
function onUpdateModelValue(value: Validatable) {
|
||||||
state.isTyping = true;
|
state.isTyping = true;
|
||||||
$emit('update:modelValue', value);
|
$emit('update:modelValue', value);
|
||||||
}
|
}
|
||||||
@@ -225,9 +239,9 @@ const validationError = computed<string | null>(() => {
|
|||||||
const error = getInputValidationError();
|
const error = getInputValidationError();
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error.messageKey) {
|
if ('messageKey' in error) {
|
||||||
return t(error.messageKey, error.options);
|
return t(error.messageKey, error.options as object);
|
||||||
} else {
|
} else if ('message' in error) {
|
||||||
return error.message;
|
return error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const requiredValidator: IValidator<{}> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const minLengthValidator: IValidator<{ minimum: number }> = {
|
export const minLengthValidator: IValidator<{ minimum: number }> = {
|
||||||
validate: (value: Validatable, config: { minimum: number }) => {
|
validate: (value: Validatable, config) => {
|
||||||
if (typeof value === 'string' && value.length < config.minimum) {
|
if (typeof value === 'string' && value.length < config.minimum) {
|
||||||
return {
|
return {
|
||||||
messageKey: 'formInput.validator.minCharactersRequired',
|
messageKey: 'formInput.validator.minCharactersRequired',
|
||||||
@@ -76,7 +76,7 @@ export const emailValidator: IValidator<{}> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const containsUpperCaseValidator: IValidator<{ minimum: number }> = {
|
export const containsUpperCaseValidator: IValidator<{ minimum: number }> = {
|
||||||
validate: (value: Validatable, config: { minimum: number }) => {
|
validate: (value: Validatable, config) => {
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ export const containsUpperCaseValidator: IValidator<{ minimum: number }> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const matchRegex: IValidator<{ regex: RegExp; message: string }> = {
|
export const matchRegex: IValidator<{ regex: RegExp; message: string }> = {
|
||||||
validate: (value: Validatable, config: { regex: RegExp; message: string }) => {
|
validate: (value: Validatable, config) => {
|
||||||
if (!config.regex.test(`${value as string}`)) {
|
if (!config.regex.test(`${value as string}`)) {
|
||||||
return {
|
return {
|
||||||
message: config.message,
|
message: config.message,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export default defineComponent({
|
|||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
tagSize: {
|
tagSize: {
|
||||||
type: String,
|
type: String as PropType<'small' | 'medium'>,
|
||||||
default: 'small',
|
default: 'small',
|
||||||
validator: (value: string): boolean => ['small', 'medium'].includes(value),
|
validator: (value: string): boolean => ['small', 'medium'].includes(value),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<ElInput
|
<ElInput
|
||||||
ref="innerInput"
|
ref="innerInput"
|
||||||
:size="computedSize"
|
:model-value="modelValue"
|
||||||
|
:type="type"
|
||||||
|
:size="resolvedSize"
|
||||||
:class="['n8n-input', ...classes]"
|
:class="['n8n-input', ...classes]"
|
||||||
:autocomplete="autocomplete"
|
:autocomplete="autocomplete"
|
||||||
:name="name"
|
:name="name"
|
||||||
v-bind="{ ...$props, ...$attrs }"
|
:placeholder="placeholder"
|
||||||
|
:disabled="disabled"
|
||||||
|
:readonly="readonly"
|
||||||
|
:clearable="clearable"
|
||||||
|
:rows="rows"
|
||||||
|
:title="title"
|
||||||
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<template v-if="$slots.prepend" #prepend>
|
<template v-if="$slots.prepend" #prepend>
|
||||||
<slot name="prepend" />
|
<slot name="prepend" />
|
||||||
@@ -27,6 +35,7 @@ import { computed, ref } from 'vue';
|
|||||||
import { ElInput } from 'element-plus';
|
import { ElInput } from 'element-plus';
|
||||||
import { uid } from '../../utils';
|
import { uid } from '../../utils';
|
||||||
import type { InputSize, InputType } from '@/types/input';
|
import type { InputSize, InputType } from '@/types/input';
|
||||||
|
import type { ElementPlusSizePropType, InputAutocompletePropType } from '@/types';
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
modelValue?: string | number;
|
modelValue?: string | number;
|
||||||
@@ -40,12 +49,13 @@ interface InputProps {
|
|||||||
maxlength?: number;
|
maxlength?: number;
|
||||||
title?: string;
|
title?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
autocomplete?: 'off' | 'autocomplete';
|
autocomplete?: InputAutocompletePropType;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({ name: 'N8nInput' });
|
defineOptions({ name: 'N8nInput' });
|
||||||
const props = withDefaults(defineProps<InputProps>(), {
|
const props = withDefaults(defineProps<InputProps>(), {
|
||||||
modelValue: '',
|
modelValue: '',
|
||||||
|
type: 'text',
|
||||||
size: 'large',
|
size: 'large',
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@@ -58,7 +68,9 @@ const props = withDefaults(defineProps<InputProps>(), {
|
|||||||
autocomplete: 'off',
|
autocomplete: 'off',
|
||||||
});
|
});
|
||||||
|
|
||||||
const computedSize = computed(() => (props.size === 'xlarge' ? undefined : props.size));
|
const resolvedSize = computed(
|
||||||
|
() => (props.size === 'xlarge' ? undefined : props.size) as ElementPlusSizePropType,
|
||||||
|
);
|
||||||
|
|
||||||
const classes = computed(() => {
|
const classes = computed(() => {
|
||||||
const applied: string[] = [];
|
const applied: string[] = [];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ exports[`N8nInput > should render correctly 1`] = `
|
|||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<div class="el-input__wrapper">
|
<div class="el-input__wrapper">
|
||||||
<!-- prefix slot -->
|
<!-- prefix slot -->
|
||||||
<!--v-if--><input class="el-input__inner" name="input" rows="2" maxlength="Infinity" title="" type="text" autocomplete="off" tabindex="0" placeholder=""><!-- suffix slot -->
|
<!--v-if--><input class="el-input__inner" name="input" rows="2" title="" type="text" autocomplete="off" tabindex="0" placeholder=""><!-- suffix slot -->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
</div><!-- append slot -->
|
</div><!-- append slot -->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { InputSize } from '@/types';
|
import type { ElementPlusSizePropType, InputSize } from '@/types';
|
||||||
import { ElInputNumber } from 'element-plus';
|
import { ElInputNumber } from 'element-plus';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
type InputNumberProps = {
|
type InputNumberProps = {
|
||||||
size?: InputSize;
|
size?: InputSize;
|
||||||
@@ -10,9 +11,24 @@ type InputNumberProps = {
|
|||||||
precision?: number;
|
precision?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineProps<InputNumberProps>();
|
const props = withDefaults(defineProps<InputNumberProps>(), {
|
||||||
|
size: undefined,
|
||||||
|
step: 1,
|
||||||
|
precision: 0,
|
||||||
|
min: -Infinity,
|
||||||
|
max: Infinity,
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolvedSize = computed(() => props.size as ElementPlusSizePropType);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElInputNumber v-bind="{ ...$props, ...$attrs }" />
|
<ElInputNumber
|
||||||
|
:size="resolvedSize"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
:step="step"
|
||||||
|
:precision="precision"
|
||||||
|
v-bind="$attrs"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import type { TextSize } from '@/types/text';
|
|||||||
const THEME = ['primary', 'danger', 'text', 'secondary'] as const;
|
const THEME = ['primary', 'danger', 'text', 'secondary'] as const;
|
||||||
|
|
||||||
interface LinkProps {
|
interface LinkProps {
|
||||||
to?: RouteLocationRaw;
|
to?: RouteLocationRaw | string;
|
||||||
size?: TextSize;
|
size?: TextSize;
|
||||||
newWindow?: boolean;
|
newWindow?: boolean;
|
||||||
bold?: boolean;
|
bold?: boolean;
|
||||||
@@ -27,6 +27,8 @@ interface LinkProps {
|
|||||||
|
|
||||||
defineOptions({ name: 'N8nLink' });
|
defineOptions({ name: 'N8nLink' });
|
||||||
withDefaults(defineProps<LinkProps>(), {
|
withDefaults(defineProps<LinkProps>(), {
|
||||||
|
to: undefined,
|
||||||
|
size: undefined,
|
||||||
bold: false,
|
bold: false,
|
||||||
underline: false,
|
underline: false,
|
||||||
theme: 'primary',
|
theme: 'primary',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<template #content>{{ nodeTypeName }}</template>
|
<template #content>{{ nodeTypeName }}</template>
|
||||||
<div v-if="type !== 'unknown'" :class="$style.icon">
|
<div v-if="type !== 'unknown'" :class="$style.icon">
|
||||||
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
||||||
<FontAwesomeIcon v-else :icon="name" :class="$style.iconFa" :style="fontStyleData" />
|
<FontAwesomeIcon v-else :icon="`${name}`" :class="$style.iconFa" :style="fontStyleData" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else :class="$style.nodeIconPlaceholder">
|
<div v-else :class="$style.nodeIconPlaceholder">
|
||||||
{{ nodeTypeName ? nodeTypeName.charAt(0) : '?' }}
|
{{ nodeTypeName ? nodeTypeName.charAt(0) : '?' }}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<div v-if="type !== 'unknown'" :class="$style.icon">
|
<div v-if="type !== 'unknown'" :class="$style.icon">
|
||||||
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
<img v-if="type === 'file'" :src="src" :class="$style.nodeIconImage" />
|
||||||
<FontAwesomeIcon v-else :icon="name" :style="fontStyleData" />
|
<FontAwesomeIcon v-else :icon="`${name}`" :style="fontStyleData" />
|
||||||
<div v-if="badge" :class="$style.badge" :style="badgeStyleData">
|
<div v-if="badge" :class="$style.badge" :style="badgeStyleData">
|
||||||
<n8n-node-icon :type="badge.type" :src="badge.src" :size="badgeSize"></n8n-node-icon>
|
<n8n-node-icon :type="badge.type" :src="badge.src" :size="badgeSize"></n8n-node-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-link v-if="useRouterLink" :to="to" v-bind="$attrs">
|
<router-link v-if="useRouterLink && to" :to="to" v-bind="$attrs">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a v-else :href="to" :target="openNewWindow ? '_blank' : '_self'" v-bind="$attrs">
|
<a
|
||||||
|
v-else
|
||||||
|
:href="to ? `${to}` : undefined"
|
||||||
|
:target="openNewWindow ? '_blank' : '_self'"
|
||||||
|
v-bind="$attrs"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
@@ -12,7 +17,7 @@ import { computed } from 'vue';
|
|||||||
import { type RouteLocationRaw } from 'vue-router';
|
import { type RouteLocationRaw } from 'vue-router';
|
||||||
|
|
||||||
interface RouteProps {
|
interface RouteProps {
|
||||||
to?: RouteLocationRaw;
|
to?: RouteLocationRaw | string;
|
||||||
newWindow?: boolean;
|
newWindow?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
import { ElSelect } from 'element-plus';
|
import { ElSelect } from 'element-plus';
|
||||||
import { type PropType, defineComponent } from 'vue';
|
import { type PropType, defineComponent } from 'vue';
|
||||||
import type { SelectSize } from '@/types';
|
import type { SelectSize } from '@/types';
|
||||||
|
import { isEventBindingElementAttribute } from '../../utils';
|
||||||
|
|
||||||
type InnerSelectRef = InstanceType<typeof ElSelect>;
|
type InnerSelectRef = InstanceType<typeof ElSelect>;
|
||||||
|
|
||||||
@@ -86,13 +87,16 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
listeners() {
|
listeners() {
|
||||||
return Object.entries(this.$attrs).reduce<Record<string, () => {}>>((acc, [key, value]) => {
|
return Object.entries(this.$attrs).reduce<Record<string, (...args: unknown[]) => {}>>(
|
||||||
if (/^on[A-Z]/.test(key)) {
|
(acc, [key, value]) => {
|
||||||
|
if (isEventBindingElementAttribute(value, key)) {
|
||||||
acc[key] = value;
|
acc[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
computedSize(): InnerSelectRef['$props']['size'] {
|
computedSize(): InnerSelectRef['$props']['size'] {
|
||||||
if (this.size === 'medium') {
|
if (this.size === 'medium') {
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
onReinvite: action('reinvite'),
|
action: ({ action: actionName }: { action: string; userId: string }) => action(actionName),
|
||||||
onDelete: action('delete'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Template: StoryFn = (args, { argTypes }) => ({
|
const Template: StoryFn = (args, { argTypes }) => ({
|
||||||
@@ -23,8 +22,7 @@ const Template: StoryFn = (args, { argTypes }) => ({
|
|||||||
components: {
|
components: {
|
||||||
N8nUsersList,
|
N8nUsersList,
|
||||||
},
|
},
|
||||||
template:
|
template: '<n8n-users-list v-bind="args" :actions="actions" @action="action" />',
|
||||||
'<n8n-users-list v-bind="args" :actions="actions" @reinvite="onReinvite" @delete="onDelete" />',
|
|
||||||
methods,
|
methods,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ interface UsersListProps {
|
|||||||
|
|
||||||
const props = withDefaults(defineProps<UsersListProps>(), {
|
const props = withDefaults(defineProps<UsersListProps>(), {
|
||||||
readonly: false,
|
readonly: false,
|
||||||
|
currentUserId: '',
|
||||||
users: () => [],
|
users: () => [],
|
||||||
actions: () => [],
|
actions: () => [],
|
||||||
isSamlLoginEnabled: false,
|
isSamlLoginEnabled: false,
|
||||||
@@ -101,11 +102,15 @@ const defaultGuard = () => true;
|
|||||||
const getActions = (user: IUser): UserAction[] => {
|
const getActions = (user: IUser): UserAction[] => {
|
||||||
if (user.isOwner) return [];
|
if (user.isOwner) return [];
|
||||||
|
|
||||||
return props.actions.filter((action) => (action.guard || defaultGuard)(user));
|
return props.actions.filter((action) => (action.guard ?? defaultGuard)(user));
|
||||||
};
|
};
|
||||||
|
|
||||||
const $emit = defineEmits(['*']);
|
const $emit = defineEmits(['action']);
|
||||||
const onUserAction = (user: IUser, action: string) => $emit(action, user.id);
|
const onUserAction = (user: IUser, action: string) =>
|
||||||
|
$emit('action', {
|
||||||
|
action,
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { VNode } from 'vue';
|
import type { Component, VNode } from 'vue';
|
||||||
|
|
||||||
export type DatatableRowDataType = string | number | boolean | null | undefined;
|
export type DatatableRowDataType = string | number | boolean | null | undefined;
|
||||||
|
|
||||||
@@ -14,5 +14,5 @@ export interface DatatableColumn {
|
|||||||
label: string;
|
label: string;
|
||||||
classes?: string[];
|
classes?: string[];
|
||||||
width?: string;
|
width?: string;
|
||||||
render?: (row: DatatableRow) => (() => VNode | VNode[]) | DatatableRowDataType;
|
render?: Component | ((row: DatatableRow) => (() => VNode | VNode[]) | DatatableRowDataType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ export type IValidator<T = unknown> = {
|
|||||||
validate: (
|
validate: (
|
||||||
value: Validatable,
|
value: Validatable,
|
||||||
config: T,
|
config: T,
|
||||||
) => false | { messageKey: string; message?: string; options?: unknown } | null;
|
) =>
|
||||||
|
| false
|
||||||
|
| { message: string; options?: unknown }
|
||||||
|
| { messageKey: string; options?: unknown }
|
||||||
|
| null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FormState = {
|
export type FormState = {
|
||||||
@@ -45,13 +49,7 @@ export type IFormInput = {
|
|||||||
infoText?: string;
|
infoText?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
options?: Array<{ label: string; value: string; disabled?: boolean }>;
|
options?: Array<{ label: string; value: string; disabled?: boolean }>;
|
||||||
autocomplete?:
|
autocomplete?: InputAutocompletePropType;
|
||||||
| 'off'
|
|
||||||
| 'new-password'
|
|
||||||
| 'current-password'
|
|
||||||
| 'given-name'
|
|
||||||
| 'family-name'
|
|
||||||
| 'email'; // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
|
|
||||||
capitalize?: boolean;
|
capitalize?: boolean;
|
||||||
focusInitially?: boolean;
|
focusInitially?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -72,3 +70,17 @@ export type IFormBoxConfig = {
|
|||||||
redirectLink?: string;
|
redirectLink?: string;
|
||||||
redirectText?: string;
|
redirectText?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CheckboxLabelSizePropType = 'small' | 'medium' | undefined;
|
||||||
|
export type CheckboxModelValuePropType = boolean | undefined;
|
||||||
|
export type SwitchModelValuePropType = boolean | undefined;
|
||||||
|
export type InputModelValuePropType = string | number | undefined;
|
||||||
|
export type InputTypePropType = 'number' | 'text' | 'email' | 'password' | 'textarea' | undefined;
|
||||||
|
export type InputAutocompletePropType =
|
||||||
|
| 'off'
|
||||||
|
| 'new-password'
|
||||||
|
| 'current-password'
|
||||||
|
| 'given-name'
|
||||||
|
| 'family-name'
|
||||||
|
| 'email'; // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
|
||||||
|
export type ElementPlusSizePropType = '' | 'small' | 'large' | 'default' | undefined;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './event-bus';
|
export * from './event-bus';
|
||||||
export * from './markdown';
|
export * from './markdown';
|
||||||
|
export * from './typeguards';
|
||||||
export * from './uid';
|
export * from './uid';
|
||||||
export * from './valueByPath';
|
export * from './valueByPath';
|
||||||
|
|||||||
6
packages/design-system/src/utils/typeguards.ts
Normal file
6
packages/design-system/src/utils/typeguards.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function isEventBindingElementAttribute(
|
||||||
|
_attributeValue: unknown,
|
||||||
|
attributeName: string,
|
||||||
|
): _attributeValue is (...args: unknown[]) => {} {
|
||||||
|
return /^on[A-Z]/.test(attributeName);
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"types": ["vitest/globals"],
|
"types": ["vitest/globals"],
|
||||||
"typeRoots": ["@testing-library", "@types", "../../node_modules"],
|
"typeRoots": ["./node_modules/@testing-library", "./node_modules/@types", "../../node_modules", "../../node_modules/@types"],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -55,12 +55,7 @@
|
|||||||
:users="usersStore.allUsers"
|
:users="usersStore.allUsers"
|
||||||
:current-user-id="usersStore.currentUserId"
|
:current-user-id="usersStore.currentUserId"
|
||||||
:is-saml-login-enabled="ssoStore.isSamlLoginEnabled"
|
:is-saml-login-enabled="ssoStore.isSamlLoginEnabled"
|
||||||
@delete="onDelete"
|
@action="onUsersListAction"
|
||||||
@reinvite="onReinvite"
|
|
||||||
@copy-invite-link="onCopyInviteLink"
|
|
||||||
@copy-password-reset-link="onCopyPasswordResetLink"
|
|
||||||
@allow-s-s-o-manual-login="onAllowSSOManualLogin"
|
|
||||||
@disallow-s-s-o-manual-login="onDisallowSSOManualLogin"
|
|
||||||
>
|
>
|
||||||
<template #actions="{ user }">
|
<template #actions="{ user }">
|
||||||
<n8n-select
|
<n8n-select
|
||||||
@@ -192,6 +187,28 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async onUsersListAction({ action, userId }: { action: string; userId: string }) {
|
||||||
|
switch (action) {
|
||||||
|
case 'delete':
|
||||||
|
await this.onDelete(userId);
|
||||||
|
break;
|
||||||
|
case 'reinvite':
|
||||||
|
await this.onReinvite(userId);
|
||||||
|
break;
|
||||||
|
case 'copyInviteLink':
|
||||||
|
await this.onCopyInviteLink(userId);
|
||||||
|
break;
|
||||||
|
case 'copyPasswordResetLink':
|
||||||
|
await this.onCopyPasswordResetLink(userId);
|
||||||
|
break;
|
||||||
|
case 'allowSSOManualLogin':
|
||||||
|
await this.onAllowSSOManualLogin(userId);
|
||||||
|
break;
|
||||||
|
case 'disallowSSOManualLogin':
|
||||||
|
await this.onDisallowSSOManualLogin(userId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
redirectToSetup() {
|
redirectToSetup() {
|
||||||
void this.$router.push({ name: VIEWS.SETUP });
|
void this.$router.push({ name: VIEWS.SETUP });
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user