diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 3f73e08ba7..5555e60382 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -19,6 +19,10 @@ body { --navbar-bg: #fafafa; --navbar-border: #e0e0e0; --nc-grid-bg: #fdfdfd; + + --ant-primary-color-hover: #5c85ff !important; + --ant-primary-color-active: #3366ff !important; + --ant-primary-color-outline: rgba(51, 102, 255, 0.24) !important; } ::-moz-selection { @@ -810,6 +814,6 @@ svg.nc-virtual-cell-icon { box-shadow: 0 0 0 2px #fff, 0 0 0 4px #3366ff; } -.text-nowrap{ +.text-nowrap { text-wrap: nowrap; -} \ No newline at end of file +} diff --git a/packages/nc-gui/components/smartsheet/Form.vue b/packages/nc-gui/components/smartsheet/Form.vue index 9a4ee0c3fa..b35e9324ca 100644 --- a/packages/nc-gui/components/smartsheet/Form.vue +++ b/packages/nc-gui/components/smartsheet/Form.vue @@ -1301,7 +1301,7 @@ useEventListener(
-
+
{{ $t('objects.viewType.form') }} {{ $t('objects.fields') }}
@@ -1633,7 +1633,7 @@ useEventListener(
{{ $t('labels.limitOptions') }}
-
{{ $t('labels.limitOptionsSubtext') }}.
+
{{ $t('labels.limitOptionsSubtext') }}.
v-if="isSelectTypeCol(activeField.uidt)" class="nc-form-field-appearance-settings p-4 flex flex-col gap-4 border-b border-gray-200" > -
{{ $t('general.appearance') }}
+
{{ $t('general.appearance') }}
diff --git a/packages/nc-gui/composables/useFormViewStore.ts b/packages/nc-gui/composables/useFormViewStore.ts index 8c6e56d645..26b1c03b8b 100644 --- a/packages/nc-gui/composables/useFormViewStore.ts +++ b/packages/nc-gui/composables/useFormViewStore.ts @@ -48,9 +48,24 @@ const [useProvideFormViewStore, useFormViewStore] = useInjectionState( for (const column of visibleColumns.value) { let rules: RuleObject[] = [ { - required: isRequired(column, column.required), - message: t('msg.error.fieldRequired'), - ...(column.uidt === UITypes.Checkbox && isRequired(column, column.required) ? { type: 'enum', enum: [1, true] } : {}), + validator: (_rule: RuleObject, value: any) => { + return new Promise((resolve, reject) => { + if (isRequired(column, column.required)) { + if (typeof value === 'string') { + value = value.trim() + } + + if ( + (column.uidt === UITypes.Checkbox && !value) || + (column.uidt !== UITypes.Checkbox && !requiredFieldValidatorFn(value)) + ) { + return reject(t('msg.error.fieldRequired')) + } + } + + return resolve() + }) + }, }, ] diff --git a/packages/nc-gui/composables/useSharedFormViewStore.ts b/packages/nc-gui/composables/useSharedFormViewStore.ts index e12c036617..38ff33918a 100644 --- a/packages/nc-gui/composables/useSharedFormViewStore.ts +++ b/packages/nc-gui/composables/useSharedFormViewStore.ts @@ -194,23 +194,28 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share if (!formColumns.value) return rulesObj for (const column of formColumns.value) { - let rules: RuleObject[] = [] - - rules.push({ - validator: (_rule: RuleObject, value: any) => { - return new Promise((resolve, reject) => { - if (isRequired(column)) { - if (column.uidt === UITypes.Checkbox && !value) { - return reject(t('msg.error.fieldRequired')) - } else if (column.uidt !== UITypes.Checkbox) - if (value === null || !value?.length) { + let rules: RuleObject[] = [ + { + validator: (_rule: RuleObject, value: any) => { + return new Promise((resolve, reject) => { + if (isRequired(column)) { + if (typeof value === 'string') { + value = value.trim() + } + + if ( + (column.uidt === UITypes.Checkbox && !value) || + (column.uidt !== UITypes.Checkbox && !requiredFieldValidatorFn(value)) + ) { return reject(t('msg.error.fieldRequired')) } - } - return resolve() - }) + } + + return resolve() + }) + }, }, - }) + ] const additionalRules = extractFieldValidator(parseProp(column.meta).validators ?? [], column) rules = [...rules, ...additionalRules] diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 670dc102e9..c00a3561de 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -1497,7 +1497,7 @@ "theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots", "parameterKeyCannotBeEmpty": "Parameter key cannot be empty", "duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed", - "fieldRequired": "{value} cannot be empty.", + "fieldRequired": "This field cannot be empty.", "projectNotAccessible": "Base not accessible", "copyToClipboardError": "Failed to copy to clipboard", "pasteFromClipboardError": "Failed to paste from clipboard", diff --git a/packages/nc-gui/utils/formValidations.ts b/packages/nc-gui/utils/formValidations.ts index f13b331315..9b7dc80810 100644 --- a/packages/nc-gui/utils/formValidations.ts +++ b/packages/nc-gui/utils/formValidations.ts @@ -64,6 +64,37 @@ export const formNumberInputValidator = (cal: ColumnType) => { } } +export const requiredFieldValidatorFn = (value: unknown) => { + value = unref(value) + if (Array.isArray(value)) return !!value.length + + if (value === undefined || value === null) { + return false + } + + if (value === false) { + return true + } + + if (typeof value === 'object') { + for (let _ in value) return true + + return false + } + + return !!String(value).length +} + +export const isEmptyValidatorValue = (v: Validation) => { + if (v.type === StringValidationType.Regex) { + return v.type && typeof v.regex === 'string' ? !v.regex.trim() : v.regex === null + } else if (v.type && v.value !== undefined) { + return v.type && typeof v.value === 'string' ? !v.value.trim() : v.value === null + } + + return false +} + export const extractFieldValidator = (_validators: Validation[], element: ColumnType) => { const rules: RuleObject[] = [] diff --git a/packages/nc-gui/windi.config.ts b/packages/nc-gui/windi.config.ts index bc035334ae..e4bad724c8 100644 --- a/packages/nc-gui/windi.config.ts +++ b/packages/nc-gui/windi.config.ts @@ -111,6 +111,9 @@ export default defineConfig({ primary: 'rgba(var(--color-primary), var(--tw-ring-opacity))', accent: 'rgba(var(--color-accent), var(--tw-ring-opacity))', }, + boxShadow: { + selected: '0px 0px 0px 2px var(--ant-primary-color-outline)', + }, colors: { ...windiColors, ...themeColors,