|
|
@ -2,7 +2,7 @@ |
|
|
|
import type { ComponentPublicInstance } from '@vue/runtime-core' |
|
|
|
import type { ComponentPublicInstance } from '@vue/runtime-core' |
|
|
|
import type { Form as AntForm, SelectProps } from 'ant-design-vue' |
|
|
|
import type { Form as AntForm, SelectProps } from 'ant-design-vue' |
|
|
|
import { capitalize } from '@vue/runtime-core' |
|
|
|
import { capitalize } from '@vue/runtime-core' |
|
|
|
import type { FormType, GalleryType, GridType, KanbanType, MapType, TableType } from 'nocodb-sdk' |
|
|
|
import {CalendarType, FormType, GalleryType, GridType, KanbanType, MapType, TableType} from 'nocodb-sdk' |
|
|
|
import { UITypes, ViewTypes, isSystemColumn } from 'nocodb-sdk' |
|
|
|
import { UITypes, ViewTypes, isSystemColumn } from 'nocodb-sdk' |
|
|
|
import { computed, message, nextTick, onBeforeMount, reactive, ref, useApi, useI18n, useVModel, watch } from '#imports' |
|
|
|
import { computed, message, nextTick, onBeforeMount, reactive, ref, useApi, useI18n, useVModel, watch } from '#imports' |
|
|
|
|
|
|
|
|
|
|
@ -14,11 +14,15 @@ interface Props { |
|
|
|
groupingFieldColumnId?: string |
|
|
|
groupingFieldColumnId?: string |
|
|
|
geoDataFieldColumnId?: string |
|
|
|
geoDataFieldColumnId?: string |
|
|
|
tableId: string |
|
|
|
tableId: string |
|
|
|
|
|
|
|
calendar_range: Array<{ |
|
|
|
|
|
|
|
fk_from_column_id: string, |
|
|
|
|
|
|
|
fk_to_column_id: string | null // for ee only |
|
|
|
|
|
|
|
}> |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface Emits { |
|
|
|
interface Emits { |
|
|
|
(event: 'update:modelValue', value: boolean): void |
|
|
|
(event: 'update:modelValue', value: boolean): void |
|
|
|
(event: 'created', value: GridType | KanbanType | GalleryType | FormType | MapType): void |
|
|
|
(event: 'created', value: GridType | KanbanType | GalleryType | FormType | MapType | CalendarType): void |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface Form { |
|
|
|
interface Form { |
|
|
@ -83,10 +87,10 @@ const form = reactive<Form>({ |
|
|
|
copy_from_id: null, |
|
|
|
copy_from_id: null, |
|
|
|
fk_grp_col_id: null, |
|
|
|
fk_grp_col_id: null, |
|
|
|
fk_geo_data_col_id: null, |
|
|
|
fk_geo_data_col_id: null, |
|
|
|
calendar_range: ViewTypes.CALENDAR === props.type ? { |
|
|
|
calendar_range: ViewTypes.CALENDAR === props.type ? props.calendar_range : [{ |
|
|
|
fk_from_column_id: '', |
|
|
|
fk_from_column_id: '', |
|
|
|
fk_to_column_id: null |
|
|
|
fk_to_column_id: null |
|
|
|
} : null, |
|
|
|
}], |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const viewSelectFieldOptions = ref<SelectProps['options']>([]) |
|
|
|
const viewSelectFieldOptions = ref<SelectProps['options']>([]) |
|
|
@ -276,7 +280,7 @@ onMounted(async () => { |
|
|
|
// take the first option |
|
|
|
// take the first option |
|
|
|
form.calendar_range = [{ |
|
|
|
form.calendar_range = [{ |
|
|
|
fk_from_column_id: viewSelectFieldOptions.value[0].value as string, |
|
|
|
fk_from_column_id: viewSelectFieldOptions.value[0].value as string, |
|
|
|
fk_to_column_id: null |
|
|
|
fk_to_column_id: null // for ee only |
|
|
|
}] |
|
|
|
}] |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// if there is no grouping field column, disable the create button |
|
|
|
// if there is no grouping field column, disable the create button |
|
|
@ -298,7 +302,8 @@ onMounted(async () => { |
|
|
|
:size="[ViewTypes.KANBAN, ViewTypes.MAP, ViewTypes.CALENDAR].includes(form.type) ? 'medium' : 'small'" |
|
|
|
:size="[ViewTypes.KANBAN, ViewTypes.MAP, ViewTypes.CALENDAR].includes(form.type) ? 'medium' : 'small'" |
|
|
|
> |
|
|
|
> |
|
|
|
<template #header> |
|
|
|
<template #header> |
|
|
|
<div class="flex flex-row items-center gap-x-1.5"> |
|
|
|
<div class="flex w-full flex-row justify-between items-center"> |
|
|
|
|
|
|
|
<div class="flex gap-x-1.5 items-center"> |
|
|
|
<GeneralViewIcon :meta="{ type: form.type }" class="nc-view-icon !text-xl" /> |
|
|
|
<GeneralViewIcon :meta="{ type: form.type }" class="nc-view-icon !text-xl" /> |
|
|
|
<template v-if="form.type === ViewTypes.GRID"> |
|
|
|
<template v-if="form.type === ViewTypes.GRID"> |
|
|
|
<template v-if="form.copy_from_id"> |
|
|
|
<template v-if="form.copy_from_id"> |
|
|
@ -348,11 +353,15 @@ onMounted(async () => { |
|
|
|
{{ $t('labels.duplicateView') }} |
|
|
|
{{ $t('labels.duplicateView') }} |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<a v-if="!form.copy_from_id" href="https://docs.nocodb.com/views/view-types/calendar/" target="_blank" class="text-sm !no-underline !hover:text-brand-500 text-brand-500 "> |
|
|
|
|
|
|
|
Go to Docs |
|
|
|
|
|
|
|
</a> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
<div class="mt-2"> |
|
|
|
<div class="mt-2"> |
|
|
|
<a-form v-if="isNecessaryColumnsPresent" ref="formValidator" layout="vertical" :model="form"> |
|
|
|
<a-form v-if="isNecessaryColumnsPresent" ref="formValidator" layout="vertical" :model="form"> |
|
|
|
<a-form-item name="title" :rules="viewNameRules" label="View Name"> |
|
|
|
<a-form-item name="title" :rules="viewNameRules"> |
|
|
|
<a-input |
|
|
|
<a-input |
|
|
|
ref="inputEl" |
|
|
|
ref="inputEl" |
|
|
|
v-model:value="form.title" |
|
|
|
v-model:value="form.title" |
|
|
@ -395,24 +404,38 @@ onMounted(async () => { |
|
|
|
/> |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-form-item> |
|
|
|
<div v-if="form.type === ViewTypes.CALENDAR" v-for="range in form.calendar_range" class="flex w-full gap-3"> |
|
|
|
<div v-if="form.type === ViewTypes.CALENDAR" v-for="range in form.calendar_range" class="flex w-full gap-3"> |
|
|
|
<div class="flex flex-col w-1/2"> |
|
|
|
<div class="flex flex-col gap-2 w-1/2"> |
|
|
|
<span> |
|
|
|
<span> |
|
|
|
{{ $t('labels.selectDateField') }} |
|
|
|
{{ $t('labels.organizeRecordsBy') }} |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
<NcSelect |
|
|
|
<NcSelect |
|
|
|
:value="range.fk_from_col_id" |
|
|
|
v-model:value="range.fk_from_column_id" |
|
|
|
class="w-full" |
|
|
|
class="w-full" |
|
|
|
:disabled="isMetaLoading" |
|
|
|
:disabled="isMetaLoading" |
|
|
|
:loading="isMetaLoading" |
|
|
|
:loading="isMetaLoading" |
|
|
|
:options="viewSelectFieldOptions" |
|
|
|
:options="viewSelectFieldOptions" |
|
|
|
/> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-if="isEeUI" class="flex flex-col w-1/2"> |
|
|
|
<div v-if="range.fk_to_column_id === null && isEeUI" class="flex flex-col justify-end w-1/2"> |
|
|
|
|
|
|
|
<div class="cursor-pointer flex items-center font-medium gap-1 mb-1" |
|
|
|
|
|
|
|
@click="range.fk_to_column_id = ''"> |
|
|
|
|
|
|
|
<component :is="iconMap.plus" class="h-4 w-4"/> |
|
|
|
|
|
|
|
{{ $t('activity.setEndDate') }} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else-if="isEeUI" class="flex gap-2 flex-col w-1/2"> |
|
|
|
|
|
|
|
<div class="flex flex-row justify-between"> |
|
|
|
<span> |
|
|
|
<span> |
|
|
|
{{ $t('labels.selectEndDateField') }} |
|
|
|
{{ $t('labels.endDateField') }} |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
|
|
|
|
<component :is="iconMap.delete" class="h-4 w-4 cursor-pointer text-red-500" |
|
|
|
|
|
|
|
@click="() => { |
|
|
|
|
|
|
|
range.fk_to_column_id = null |
|
|
|
|
|
|
|
}"/> |
|
|
|
|
|
|
|
</div> |
|
|
|
<NcSelect |
|
|
|
<NcSelect |
|
|
|
:value="range.fk_from_col_id" |
|
|
|
v-model:value="range.fk_to_column_id" |
|
|
|
class="w-full" |
|
|
|
class="w-full" |
|
|
|
:disabled="isMetaLoading" |
|
|
|
:disabled="isMetaLoading" |
|
|
|
:loading="isMetaLoading" |
|
|
|
:loading="isMetaLoading" |
|
|
|