|
|
@ -33,6 +33,7 @@ interface moveOp { |
|
|
|
index: number |
|
|
|
index: number |
|
|
|
order: number |
|
|
|
order: number |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const { t } = useI18n() |
|
|
|
|
|
|
|
|
|
|
|
const { $api } = useNuxtApp() |
|
|
|
const { $api } = useNuxtApp() |
|
|
|
|
|
|
|
|
|
|
@ -228,7 +229,7 @@ const duplicateField = async (field: TableExplorerColumn) => { |
|
|
|
case UITypes.Lookup: |
|
|
|
case UITypes.Lookup: |
|
|
|
case UITypes.Rollup: |
|
|
|
case UITypes.Rollup: |
|
|
|
case UITypes.Formula: |
|
|
|
case UITypes.Formula: |
|
|
|
return message.info('Not available at the moment') |
|
|
|
return message.info(t('msg.info.notAvailableAtTheMoment')) |
|
|
|
case UITypes.SingleSelect: |
|
|
|
case UITypes.SingleSelect: |
|
|
|
case UITypes.MultiSelect: |
|
|
|
case UITypes.MultiSelect: |
|
|
|
fieldPayload = { |
|
|
|
fieldPayload = { |
|
|
@ -270,7 +271,7 @@ const onFieldUpdate = (state: TableExplorerColumn) => { |
|
|
|
const col = fields.value.find((col) => compareCols(col, state)) |
|
|
|
const col = fields.value.find((col) => compareCols(col, state)) |
|
|
|
if (!col) return |
|
|
|
if (!col) return |
|
|
|
|
|
|
|
|
|
|
|
const diffs = diff(col, state) |
|
|
|
const diffs = diff(col, state) as Partial<TableExplorerColumn> |
|
|
|
|
|
|
|
|
|
|
|
// hack to prevent update status `Updated Field` when clicking on field first time |
|
|
|
// hack to prevent update status `Updated Field` when clicking on field first time |
|
|
|
let isUpdated = true |
|
|
|
let isUpdated = true |
|
|
@ -389,13 +390,13 @@ const onMove = (_event: { moved: { newIndex: number; oldIndex: number } }) => { |
|
|
|
if (op?.op === 'update') { |
|
|
|
if (op?.op === 'update') { |
|
|
|
const diffs = diff(op.column, field) |
|
|
|
const diffs = diff(op.column, field) |
|
|
|
if (!(Object.keys(diffs).length === 1 && 'column_order' in diffs)) { |
|
|
|
if (!(Object.keys(diffs).length === 1 && 'column_order' in diffs)) { |
|
|
|
message.warning('You cannot move field that is being edited. Either save or discard changes first') |
|
|
|
message.warning(t('msg.warning.multiField.moveEditedField')) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (op?.op === 'delete') { |
|
|
|
if (op?.op === 'delete') { |
|
|
|
message.warning('You cannot move field that is deleted. Either save or discard changes first') |
|
|
|
message.warning(t('msg.warning.multiField.moveDeletedField')) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -563,7 +564,7 @@ const isColumnsValid = computed(() => fields.value.every((f) => isColumnValid(f) |
|
|
|
|
|
|
|
|
|
|
|
const saveChanges = async () => { |
|
|
|
const saveChanges = async () => { |
|
|
|
if (!isColumnsValid.value) { |
|
|
|
if (!isColumnsValid.value) { |
|
|
|
message.error('Please complete the configuration of all fields before saving') |
|
|
|
message.error(t('msg.error.multiFieldSaveValidation')) |
|
|
|
return |
|
|
|
return |
|
|
|
} else if (!loading.value && ops.value.length < 1 && moveOps.value.length < 1 && visibilityOps.value.length < 1) { |
|
|
|
} else if (!loading.value && ops.value.length < 1 && moveOps.value.length < 1 && visibilityOps.value.length < 1) { |
|
|
|
return |
|
|
|
return |
|
|
@ -640,7 +641,7 @@ const saveChanges = async () => { |
|
|
|
|
|
|
|
|
|
|
|
visibilityOps.value = [] |
|
|
|
visibilityOps.value = [] |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
message.error('Something went wrong') |
|
|
|
message.error(t('msg.error.somethingWentWrong')) |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
loading.value = false |
|
|
|
loading.value = false |
|
|
|
} |
|
|
|
} |
|
|
@ -648,7 +649,7 @@ const saveChanges = async () => { |
|
|
|
|
|
|
|
|
|
|
|
const toggleVisibility = async (checked: boolean, field: Field) => { |
|
|
|
const toggleVisibility = async (checked: boolean, field: Field) => { |
|
|
|
if (field.fk_column_id && fieldStatuses.value[field.fk_column_id]) { |
|
|
|
if (field.fk_column_id && fieldStatuses.value[field.fk_column_id]) { |
|
|
|
message.warning('You cannot change visibility of a field that is being edited. Please save or discard changes first.') |
|
|
|
message.warning(t('msg.warning.multiField.fieldVisibility')) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if (visibilityOps.value.find((op) => op.column.fk_column_id === field.fk_column_id)) { |
|
|
|
if (visibilityOps.value.find((op) => op.column.fk_column_id === field.fk_column_id)) { |
|
|
@ -742,7 +743,7 @@ onKeyDown('Backspace', () => { |
|
|
|
onKeyDown('ArrowRight', () => { |
|
|
|
onKeyDown('ArrowRight', () => { |
|
|
|
if (document.activeElement?.tagName === 'TEXTAREA') return |
|
|
|
if (document.activeElement?.tagName === 'TEXTAREA') return |
|
|
|
if (activeField.value) { |
|
|
|
if (activeField.value) { |
|
|
|
const input = document.querySelector('.nc-fields-input') |
|
|
|
const input = document.querySelector('.nc-fields-input') as HTMLInputElement |
|
|
|
if (input) { |
|
|
|
if (input) { |
|
|
|
input.focus() |
|
|
|
input.focus() |
|
|
|
} |
|
|
|
} |
|
|
@ -821,7 +822,7 @@ watch( |
|
|
|
data-testid="nc-field-search-input" |
|
|
|
data-testid="nc-field-search-input" |
|
|
|
v-model:value="searchQuery" |
|
|
|
v-model:value="searchQuery" |
|
|
|
class="!h-8 !px-1 !rounded-lg !w-72" |
|
|
|
class="!h-8 !px-1 !rounded-lg !w-72" |
|
|
|
placeholder="Search field" |
|
|
|
:placeholder="$t('placeholder.searchFields')" |
|
|
|
> |
|
|
|
> |
|
|
|
<template #prefix> |
|
|
|
<template #prefix> |
|
|
|
<GeneralIcon icon="search" class="mx-1 h-3.5 w-3.5 text-gray-500 group-hover:text-black" /> |
|
|
|
<GeneralIcon icon="search" class="mx-1 h-3.5 w-3.5 text-gray-500 group-hover:text-black" /> |
|
|
@ -849,7 +850,7 @@ watch( |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="flex items-center gap-2"> |
|
|
|
<div class="flex items-center gap-2"> |
|
|
|
<GeneralIcon icon="plus" class="w-3" /> |
|
|
|
<GeneralIcon icon="plus" class="w-3" /> |
|
|
|
New Field |
|
|
|
{{ $t('labels.multiField.newField') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
</NcTooltip> |
|
|
|
</NcTooltip> |
|
|
@ -860,7 +861,7 @@ watch( |
|
|
|
:disabled="(!loading && ops.length < 1 && moveOps.length < 1 && visibilityOps.length < 1) || isLocked" |
|
|
|
:disabled="(!loading && ops.length < 1 && moveOps.length < 1 && visibilityOps.length < 1) || isLocked" |
|
|
|
@click="clearChanges()" |
|
|
|
@click="clearChanges()" |
|
|
|
> |
|
|
|
> |
|
|
|
Reset |
|
|
|
{{ $t('general.reset') }} |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
<NcTooltip :disabled="isLocked"> |
|
|
|
<NcTooltip :disabled="isLocked"> |
|
|
|
<template #title> {{ `${renderCmdOrCtrlKey()} + S` }} </template> |
|
|
|
<template #title> {{ `${renderCmdOrCtrlKey()} + S` }} </template> |
|
|
@ -876,7 +877,7 @@ watch( |
|
|
|
" |
|
|
|
" |
|
|
|
@click="saveChanges()" |
|
|
|
@click="saveChanges()" |
|
|
|
> |
|
|
|
> |
|
|
|
Save changes |
|
|
|
{{ $t('labels.multiField.saveChanges') }} |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
</NcTooltip> |
|
|
|
</NcTooltip> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -956,7 +957,7 @@ watch( |
|
|
|
class="bg-red-50 text-red-700" |
|
|
|
class="bg-red-50 text-red-700" |
|
|
|
data-testid="nc-field-status-deleted-field" |
|
|
|
data-testid="nc-field-status-deleted-field" |
|
|
|
> |
|
|
|
> |
|
|
|
Deleted field |
|
|
|
{{ $t('labels.multiField.deletedField') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
<NcBadge |
|
|
|
<NcBadge |
|
|
|
v-else-if="fieldStatus(field) === 'add'" |
|
|
|
v-else-if="fieldStatus(field) === 'add'" |
|
|
@ -965,7 +966,7 @@ watch( |
|
|
|
class="bg-green-50 text-green-700" |
|
|
|
class="bg-green-50 text-green-700" |
|
|
|
data-testid="nc-field-status-new-field" |
|
|
|
data-testid="nc-field-status-new-field" |
|
|
|
> |
|
|
|
> |
|
|
|
New field |
|
|
|
{{ $t('labels.multiField.newField') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
|
|
|
|
|
|
|
|
<NcBadge |
|
|
|
<NcBadge |
|
|
@ -975,7 +976,7 @@ watch( |
|
|
|
class="bg-orange-50 text-orange-700" |
|
|
|
class="bg-orange-50 text-orange-700" |
|
|
|
data-testid="nc-field-status-updated-field" |
|
|
|
data-testid="nc-field-status-updated-field" |
|
|
|
> |
|
|
|
> |
|
|
|
Updated field |
|
|
|
{{ $t('labels.multiField.updatedField') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
<NcBadge |
|
|
|
<NcBadge |
|
|
|
v-if="!isColumnValid(field)" |
|
|
|
v-if="!isColumnValid(field)" |
|
|
@ -984,7 +985,7 @@ watch( |
|
|
|
class="ml-1 bg-yellow-50 text-yellow-700" |
|
|
|
class="ml-1 bg-yellow-50 text-yellow-700" |
|
|
|
data-testid="nc-field-status-incomplete-configuration" |
|
|
|
data-testid="nc-field-status-incomplete-configuration" |
|
|
|
> |
|
|
|
> |
|
|
|
Incomplete configuration |
|
|
|
{{ $t('labels.multiField.incompleteConfiguration') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<NcButton |
|
|
|
<NcButton |
|
|
@ -998,7 +999,7 @@ watch( |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="flex items-center text-xs gap-1"> |
|
|
|
<div class="flex items-center text-xs gap-1"> |
|
|
|
<GeneralIcon icon="reload" /> |
|
|
|
<GeneralIcon icon="reload" /> |
|
|
|
Restore |
|
|
|
{{ $t('general.restore') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
<NcDropdown |
|
|
|
<NcDropdown |
|
|
@ -1053,7 +1054,7 @@ watch( |
|
|
|
@click="duplicateField(field)" |
|
|
|
@click="duplicateField(field)" |
|
|
|
data-testid="nc-field-item-action-duplicate" |
|
|
|
data-testid="nc-field-item-action-duplicate" |
|
|
|
> |
|
|
|
> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:copy" /><span>Duplicate</span> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:copy" /><span>{{ $t('general.duplicate') }}</span> |
|
|
|
</NcMenuItem> |
|
|
|
</NcMenuItem> |
|
|
|
<NcMenuItem |
|
|
|
<NcMenuItem |
|
|
|
v-if="!field.pv" |
|
|
|
v-if="!field.pv" |
|
|
@ -1061,14 +1062,18 @@ watch( |
|
|
|
@click="addField(field, true)" |
|
|
|
@click="addField(field, true)" |
|
|
|
data-testid="nc-field-item-action-insert-above" |
|
|
|
data-testid="nc-field-item-action-insert-above" |
|
|
|
> |
|
|
|
> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:arrow-up" /><span>Insert above</span> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:arrow-up" /><span>{{ |
|
|
|
|
|
|
|
$t('general.insertAbove') |
|
|
|
|
|
|
|
}}</span> |
|
|
|
</NcMenuItem> |
|
|
|
</NcMenuItem> |
|
|
|
<NcMenuItem |
|
|
|
<NcMenuItem |
|
|
|
key="table-explorer-insert-below" |
|
|
|
key="table-explorer-insert-below" |
|
|
|
@click="addField(field)" |
|
|
|
@click="addField(field)" |
|
|
|
data-testid="nc-field-item-action-insert-below" |
|
|
|
data-testid="nc-field-item-action-insert-below" |
|
|
|
> |
|
|
|
> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:arrow-down" /><span>Insert below</span> |
|
|
|
<Icon class="iconify text-gray-800" icon="lucide:arrow-down" /><span>{{ |
|
|
|
|
|
|
|
$t('general.insertBelow') |
|
|
|
|
|
|
|
}}</span> |
|
|
|
</NcMenuItem> |
|
|
|
</NcMenuItem> |
|
|
|
|
|
|
|
|
|
|
|
<a-menu-divider class="my-1.5" /> |
|
|
|
<a-menu-divider class="my-1.5" /> |
|
|
@ -1081,7 +1086,7 @@ watch( |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="text-red-500"> |
|
|
|
<div class="text-red-500"> |
|
|
|
<GeneralIcon icon="delete" class="group-hover:text-accent -ml-0.25 -mt-0.75 mr-0.5" /> |
|
|
|
<GeneralIcon icon="delete" class="group-hover:text-accent -ml-0.25 -mt-0.75 mr-0.5" /> |
|
|
|
Delete |
|
|
|
{{ $t('general.delete') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</NcMenuItem> |
|
|
|
</NcMenuItem> |
|
|
|
</template> |
|
|
|
</template> |
|
|
@ -1147,7 +1152,7 @@ watch( |
|
|
|
class="bg-red-50 text-red-700" |
|
|
|
class="bg-red-50 text-red-700" |
|
|
|
data-testid="nc-field-status-deleted-field" |
|
|
|
data-testid="nc-field-status-deleted-field" |
|
|
|
> |
|
|
|
> |
|
|
|
Deleted field |
|
|
|
{{ $t('labels.multiField.deletedField') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
|
|
|
|
|
|
|
|
<NcBadge |
|
|
|
<NcBadge |
|
|
@ -1157,7 +1162,7 @@ watch( |
|
|
|
class="bg-orange-50 text-orange-700" |
|
|
|
class="bg-orange-50 text-orange-700" |
|
|
|
data-testid="nc-field-status-updated-field" |
|
|
|
data-testid="nc-field-status-updated-field" |
|
|
|
> |
|
|
|
> |
|
|
|
Updated field |
|
|
|
{{ $t('labels.multiField.updatedField') }} |
|
|
|
</NcBadge> |
|
|
|
</NcBadge> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<NcButton |
|
|
|
<NcButton |
|
|
@ -1171,7 +1176,7 @@ watch( |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="flex items-center text-xs gap-1"> |
|
|
|
<div class="flex items-center text-xs gap-1"> |
|
|
|
<GeneralIcon icon="reload" /> |
|
|
|
<GeneralIcon icon="reload" /> |
|
|
|
Restore |
|
|
|
{{ $t('general.restore') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
<NcDropdown |
|
|
|
<NcDropdown |
|
|
@ -1252,9 +1257,9 @@ watch( |
|
|
|
/> |
|
|
|
/> |
|
|
|
<div v-else class="w-[25rem] flex flex-col justify-center p-4 items-center"> |
|
|
|
<div v-else class="w-[25rem] flex flex-col justify-center p-4 items-center"> |
|
|
|
<img src="~assets/img/fieldPlaceholder.svg" class="!w-[18rem]" /> |
|
|
|
<img src="~assets/img/fieldPlaceholder.svg" class="!w-[18rem]" /> |
|
|
|
<div class="text-2xl text-gray-600 font-bold text-center pt-6">Select a field</div> |
|
|
|
<div class="text-2xl text-gray-600 font-bold text-center pt-6">{{ $t('labels.multiField.selectField') }}</div> |
|
|
|
<div class="text-center text-sm px-2 text-gray-500 pt-6"> |
|
|
|
<div class="text-center text-sm px-2 text-gray-500 pt-6"> |
|
|
|
Make changes to field properties by selecting a field from the list |
|
|
|
{{ $t('labels.multiField.selectFieldLabel') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|