Browse Source

fix(nc-gui): create, update calendar range

pull/7611/head
DarkPhoenix2704 6 months ago
parent
commit
27e2c935dc
  1. 49
      packages/nc-gui/components/dlg/ViewCreate.vue
  2. 65
      packages/nc-gui/components/smartsheet/toolbar/CalendarRange.vue
  3. 13
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  4. 3
      packages/nc-gui/lang/en.json

49
packages/nc-gui/components/dlg/ViewCreate.vue

@ -2,7 +2,7 @@
import type { ComponentPublicInstance } from '@vue/runtime-core'
import type { Form as AntForm, SelectProps } from 'ant-design-vue'
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 { computed, message, nextTick, onBeforeMount, reactive, ref, useApi, useI18n, useVModel, watch } from '#imports'
@ -14,11 +14,15 @@ interface Props {
groupingFieldColumnId?: string
geoDataFieldColumnId?: string
tableId: string
calendar_range: Array<{
fk_from_column_id: string,
fk_to_column_id: string | null // for ee only
}>
}
interface Emits {
(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 {
@ -83,10 +87,10 @@ const form = reactive<Form>({
copy_from_id: null,
fk_grp_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_to_column_id: null
} : null,
}],
})
const viewSelectFieldOptions = ref<SelectProps['options']>([])
@ -276,7 +280,7 @@ onMounted(async () => {
// take the first option
form.calendar_range = [{
fk_from_column_id: viewSelectFieldOptions.value[0].value as string,
fk_to_column_id: null
fk_to_column_id: null // for ee only
}]
} else {
// 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'"
>
<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" />
<template v-if="form.type === ViewTypes.GRID">
<template v-if="form.copy_from_id">
@ -348,11 +353,15 @@ onMounted(async () => {
{{ $t('labels.duplicateView') }}
</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>
</template>
<div class="mt-2">
<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
ref="inputEl"
v-model:value="form.title"
@ -395,24 +404,38 @@ onMounted(async () => {
/>
</a-form-item>
<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>
{{ $t('labels.selectDateField') }}
{{ $t('labels.organizeRecordsBy') }}
</span>
<NcSelect
:value="range.fk_from_col_id"
v-model:value="range.fk_from_column_id"
class="w-full"
:disabled="isMetaLoading"
:loading="isMetaLoading"
:options="viewSelectFieldOptions"
/>
</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>
{{ $t('labels.selectEndDateField') }}
{{ $t('labels.endDateField') }}
</span>
<component :is="iconMap.delete" class="h-4 w-4 cursor-pointer text-red-500"
@click="() => {
range.fk_to_column_id = null
}"/>
</div>
<NcSelect
:value="range.fk_from_col_id"
v-model:value="range.fk_to_column_id"
class="w-full"
:disabled="isMetaLoading"
:loading="isMetaLoading"

65
packages/nc-gui/components/smartsheet/toolbar/CalendarRange.vue

@ -19,7 +19,7 @@ const {eventBus} = useSmartsheetStoreOrThrow()
const meta = inject(MetaInj, ref())
const { $e } = useNuxtApp()
const { $e, $api } = useNuxtApp()
const activeView = inject(ActiveViewInj, ref())
@ -37,44 +37,41 @@ watch(
async (newVal, oldVal) => {
if (newVal !== oldVal && meta.value) {
await loadViewColumns()
// For now we are adding a calendar range by default
// TODO: Remove this when we have a way to add calendar range
await addCalendarRange()
}
},
{immediate: true},
)
// TODO: Fetch calendar range from viewColumnsComposable
const calendarRange = computed<{ fk_from_column_id: string; fk_to_column_id: string | null }[]>(() => {
const tempCalendarRange: { fk_from_column_id: string; fk_to_column_id: string | null }[] = []
// Object.values(fields.value).forEach((col) => {
// if (col.calendar_range) {
// tempCalendarRange.push({
// fk_from_col_id: col.fk_from_column_id,
// fk_to_column_id: col.fk_to_column_id,
// })
// }
// })
const tempCalendarRange: { fk_from_column_id: string; fk_to_column_id: string | null }[] = [];
if (!activeView.value || !activeView.value.view) return tempCalendarRange;
activeView.value.view.calendar_range?.forEach((range) => {
tempCalendarRange.push({
fk_from_column_id: range.fk_from_column_id,
fk_to_column_id: range.fk_to_column_id,
})
})
return tempCalendarRange
})
// We keep the calendar range here and update it when the user selects a new range
const _calendar_ranges = ref<{ fk_from_column_id: string; fk_to_column_id: string | null }[]>([])
const _calendar_ranges = ref<{ fk_from_column_id: string; fk_to_column_id: string | null }[]>(calendarRange.value)
const saveCalendarRanges = async () => {
if(activeView.value) {
try {
for(const range of _calendar_ranges.value) {
if(!range.fk_from_column_id) continue;
// TODO: Update calendar range in viewColumnsComposable
$e('c:calendar:change-calendar-range', {
viewId: activeView.value.id,
fk_from_column_id: range.fk_from_column_id,
fk_to_column_id: range.fk_to_column_id,
})
const calRanges = _calendar_ranges.value.map((range) => {
if (range.fk_from_column_id) {
return {
fk_from_column_id: range.fk_from_column_id,
fk_to_column_id: range.fk_to_column_id,
}
}
})
await $api.dbView.calendarUpdate(activeView.value?.id as string, {
calendar_range: calRanges as { fk_from_column_id: string; fk_to_column_id: string | null }[],
})
} catch (e) {
console.log(e)
message.error('There was an error while updating view!')
@ -131,19 +128,19 @@ const dateFieldOptions = computed<SelectProps['options']>(() => {
<a-divider class="!my-2"/>
</div>
<div v-for="cal in _calendar_ranges" 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>
{{ $t('labels.selectDateField') }}
{{ $t('labels.organizeRecordsBy') }}
</span>
<NcSelect
:value="cal.fk_from_column_id"
v-model:value="cal.fk_from_column_id"
:options="dateFieldOptions"
class="w-full"
@click.stop
@change="saveCalendarRanges"
/>
</div>
<div v-if="cal.fk_to_column_id === null" class="flex flex-col justify-end w-1/2">
<div v-if="cal.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="cal.fk_to_column_id = ''">
<component :is="iconMap.plus" class="h-4 w-4"/>
@ -151,17 +148,19 @@ const dateFieldOptions = computed<SelectProps['options']>(() => {
</div>
</div>
<div v-if="isEeUI && cal.fk_to_column_id !== null" class="flex flex-col w-1/2">
<div v-else-if="isEeUI" class="flex flex-col gap-2 w-1/2">
<div class="flex flex-row justify-between">
<span>
{{ $t('labels.selectEndDateField') }}
{{ $t('labels.endDateField') }}
</span>
<component :is="iconMap.delete" class="h-4 w-4 cursor-pointer text-red-500"
@click="cal.fk_to_column_id = null"/>
@click="() => {
cal.fk_to_column_id = null
saveCalendarRanges()
}"/>
</div>
<NcSelect
:value="cal.fk_to_column_id"
v-model:value="cal.fk_to_column_id"
:options="dateFieldOptions"
:disabled="!cal.fk_from_column_id"
:placeholder="$t('placeholder.notSelected')"

13
packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import type { ColumnType, GalleryType, KanbanType } from 'nocodb-sdk'
import {CalendarType, ColumnType, GalleryType, KanbanType} from 'nocodb-sdk'
import { UITypes, ViewTypes, isVirtualCol } from 'nocodb-sdk'
import Draggable from 'vuedraggable'
@ -151,7 +151,7 @@ const coverOptions = computed<SelectProps['options']>(() => {
const updateCoverImage = async (val?: string | null) => {
if (
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) &&
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN || activeView.value?.type === ViewTypes.CALENDAR) &&
activeView.value?.id &&
activeView.value?.view
) {
@ -165,6 +165,11 @@ const updateCoverImage = async (val?: string | null) => {
fk_cover_image_col_id: val,
})
;(activeView.value.view as KanbanType).fk_cover_image_col_id = val
} else if (activeView.value?.type === ViewTypes.CALENDAR) {
await $api.dbView.calendarUpdate(activeView.value?.id, {
fk_cover_image_col_id: val,
})
;(activeView.value.view as CalendarType).fk_cover_image_col_id = val
}
reloadViewMetaHook?.trigger()
}
@ -173,7 +178,7 @@ const updateCoverImage = async (val?: string | null) => {
const coverImageColumnId = computed({
get: () => {
const fk_cover_image_col_id =
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) && activeView.value?.view
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN || activeView.value?.type === ViewTypes.CALENDAR) && activeView.value?.view
? (activeView.value?.view as GalleryType).fk_cover_image_col_id
: undefined
// check if `fk_cover_image_col_id` is in `coverOptions`
@ -305,7 +310,7 @@ useMenuCloseOnEsc(open)
<!-- Fields -->
<span v-if="!isMobileMode" class="text-capitalize text-sm font-medium">
<template v-if="activeView?.type === ViewTypes.KANBAN || activeView?.type === ViewTypes.GALLERY || ViewTypes.CALENDAR">
<template v-if="activeView?.type === ViewTypes.KANBAN || activeView?.type === ViewTypes.GALLERY || activeView?.type === ViewTypes.CALENDAR">
{{ $t('title.editCards') }}
</template>
<template v-else>

3
packages/nc-gui/lang/en.json

@ -435,6 +435,7 @@
"newProvider": "New Provider",
"generalSettings": "General Settings",
"ssoSettings": "SSO Settings",
"organizeRecordsBy": "Organize records by",
"heading1": "Heading 1",
"heading2": "Heading 2",
"heading3": "Heading 3",
@ -479,7 +480,7 @@
"singularLabel": "Singular Label",
"pluralLabel": "Plural Label",
"selectDateField": "Select a date field",
"selectEndDateField": "Select end date field",
"endDateField": "End date field",
"optional": "(Optional)",
"clickToMake": "Click to make",
"visibleForRole": "visible for role:",

Loading…
Cancel
Save