mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.3 KiB
251 lines
7.3 KiB
3 weeks ago
|
<script setup lang="ts">
|
||
|
import type { VNodeRef } from '@vue/runtime-core'
|
||
|
import type { ViewType } from 'nocodb-sdk'
|
||
|
import { viewTypeAlias } from 'nocodb-sdk'
|
||
|
import { LockType } from '#imports'
|
||
|
|
||
|
const props = defineProps<{
|
||
|
modelValue?: boolean
|
||
|
view?: ViewType
|
||
|
changeType?: LockType
|
||
|
}>()
|
||
|
|
||
|
const emits = defineEmits(['update:modelValue'])
|
||
|
|
||
|
const dialogShow = useVModel(props, 'modelValue', emits, { defaultValue: false })
|
||
|
|
||
|
const isForm = inject(IsFormInj, ref(false))
|
||
|
|
||
|
const { $api, $e } = useNuxtApp()
|
||
|
|
||
|
const { isUIAllowed } = useRoles()
|
||
|
|
||
|
const { user } = useGlobal()
|
||
|
|
||
|
const { idUserMap } = storeToRefs(useBase())
|
||
|
|
||
|
const { activeView } = storeToRefs(useViewsStore())
|
||
|
|
||
|
const view = computed(() => props.view || activeView.value)
|
||
|
|
||
|
const changeType = computed(() =>
|
||
|
view.value?.lock_type !== LockType.Locked ? LockType.Locked : props.changeType || LockType.Collaborative,
|
||
|
)
|
||
|
|
||
|
const focusInput: VNodeRef = (el) => el && el?.focus?.()
|
||
|
|
||
|
const formValidator = ref()
|
||
|
|
||
|
const isErrored = ref(false)
|
||
|
|
||
|
const form = reactive({
|
||
|
description: '',
|
||
|
})
|
||
|
|
||
|
const formRules = {
|
||
|
description: [{ max: 1000, message: 'Value must be at most 1000 characters long' }],
|
||
|
}
|
||
|
|
||
|
const isLoading = ref(false)
|
||
|
|
||
|
const changeLockType = async () => {
|
||
|
if (!view.value) return
|
||
|
|
||
|
if (changeType.value === LockType.Locked) {
|
||
|
const valid = await formValidator.value.validate()
|
||
|
|
||
|
if (!valid) return
|
||
|
}
|
||
|
|
||
|
const payload = {
|
||
|
lockedViewDescription: changeType.value === LockType.Locked ? form.description : '',
|
||
|
lockedByUserId: changeType.value === LockType.Locked ? user.value?.id : '',
|
||
|
}
|
||
|
|
||
|
isLoading.value = true
|
||
|
|
||
|
try {
|
||
|
await $api.dbView.update(view.value.id as string, {
|
||
|
lock_type: changeType.value,
|
||
|
meta: {
|
||
|
...parseProp(view.value.meta),
|
||
|
...payload,
|
||
|
},
|
||
|
})
|
||
|
|
||
|
view.value.meta = {
|
||
|
...parseProp(view.value.meta),
|
||
|
...payload,
|
||
|
}
|
||
|
|
||
|
view.value.lock_type = changeType.value
|
||
|
|
||
|
message.success(`Successfully Switched to ${view.value.lock_type} view`)
|
||
|
|
||
|
$e(`a:${viewTypeAlias[view.value.type] || 'view'}:lock`, { lockType: view.value.lock_type, title: view.value.title })
|
||
|
} catch (e: any) {
|
||
|
message.error(await extractSdkResponseErrorMsg(e))
|
||
|
} finally {
|
||
|
dialogShow.value = false
|
||
|
isLoading.value = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onKeyStroke('Enter', () => {
|
||
|
if (isLoading.value || !dialogShow.value || isForm.value || !(changeType.value !== LockType.Locked)) return
|
||
|
|
||
|
changeLockType()
|
||
|
})
|
||
|
|
||
|
watch(dialogShow, (newValue) => {
|
||
|
if (!newValue) {
|
||
|
form.description = ''
|
||
|
isErrored.value = false
|
||
|
}
|
||
|
})
|
||
|
|
||
|
watch(
|
||
|
() => form.description,
|
||
|
async () => {
|
||
|
if (changeType.value !== LockType.Locked) return
|
||
|
|
||
|
try {
|
||
|
isErrored.value = !(await formValidator.value.validate())
|
||
|
} catch (e: any) {
|
||
|
isErrored.value = true
|
||
|
}
|
||
|
},
|
||
|
)
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<div v-if="isForm" class="nc-unlock-view-wrapper rounded-2xl bg-white p-6 w-full max-w-[384px] flex flex-col gap-5">
|
||
|
<div class="flex flex-col gap-2">
|
||
|
<div class="text-base font-bold text-nc-content-gray-emphasis">
|
||
|
{{ $t('title.thisFormIsLocked') }}
|
||
|
</div>
|
||
|
<div v-if="view?.meta?.lockedViewDescription" class="text-sm bg-nc-bg-gray-light rounded-lg px-2 py-2">
|
||
|
{{ view?.meta?.lockedViewDescription }}
|
||
|
</div>
|
||
|
<div class="text-sm text-nc-content-gray">{{ $t('title.unlockThisVieToMakeChanges') }}</div>
|
||
|
<div class="text-sm text-nc-content-gray">
|
||
|
{{ $t('title.unlockViewTitleSubtitle') }}
|
||
|
<span v-if="idUserMap[view?.meta?.lockedByUserId]?.id === user.id" class="font-bold"> {{ t('general.you') }} </span>
|
||
|
<span v-else class="font-bold">
|
||
|
{{ idUserMap[view?.meta?.lockedByUserId]?.display_name || idUserMap[view?.meta?.lockedByUserId]?.email }}
|
||
|
</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<NcButton
|
||
|
v-if="isUIAllowed('fieldAdd')"
|
||
|
type="secondary"
|
||
|
size="small"
|
||
|
class="!w-full"
|
||
|
:loading="isLoading"
|
||
|
:disabled="isLoading"
|
||
|
@click="changeLockType"
|
||
|
>
|
||
|
<template #icon>
|
||
|
<GeneralIcon icon="ncUnlock" class="flex-none" />
|
||
|
</template>
|
||
|
{{ $t('labels.unlockView') }}
|
||
|
</NcButton>
|
||
|
</div>
|
||
|
<NcModal
|
||
|
v-else
|
||
|
v-model:visible="dialogShow"
|
||
|
:show-separator="false"
|
||
|
:header="$t('activity.createTable')"
|
||
|
size="small"
|
||
|
wrap-class-name="nc-lock-view-modal-wrapper"
|
||
|
@keydown.esc="dialogShow = false"
|
||
|
>
|
||
|
<template v-if="changeType === LockType.Locked" #header>
|
||
|
<div class="flex flex-col gap-2 w-full">
|
||
|
<div class="text-base font-bold text-nc-content-gray-emphasis">
|
||
|
{{ $t('title.lockThisView') }}
|
||
|
</div>
|
||
|
<div class="text-sm font-normal text-nc-content-gray-subtle">
|
||
|
{{ $t('title.lockThisViewSubtle') }}
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<a-form
|
||
|
ref="formValidator"
|
||
|
:model="form"
|
||
|
layout="vertical"
|
||
|
name="create-new-table-form"
|
||
|
class="flex flex-col gap-5 !mt-1 font-normal"
|
||
|
@finish="changeLockType"
|
||
|
>
|
||
|
<div v-if="changeType === LockType.Locked" class="flex flex-col gap-5">
|
||
|
<a-form-item name="description" :rules="formRules.description">
|
||
|
<a-textarea
|
||
|
:ref="focusInput"
|
||
|
v-model:value="form.description"
|
||
|
class="!rounded-lg !text-sm nc-input-shadow !min-h-[120px] max-h-[500px] nc-scrollbar-thin"
|
||
|
size="large"
|
||
|
hide-details
|
||
|
data-testid="nc-lock-view-description-input"
|
||
|
:placeholder="$t('placeholder.lockViewDescription')"
|
||
|
/>
|
||
|
</a-form-item>
|
||
|
</div>
|
||
|
<div v-else class="flex flex-col gap-2">
|
||
|
<div class="text-base font-bold text-nc-content-gray-emphasis">
|
||
|
{{ $t('title.unlockViewTitle') }}
|
||
|
</div>
|
||
|
<div v-if="view?.meta?.lockedViewDescription" class="text-sm bg-nc-bg-gray-light rounded-lg px-2 py-2">
|
||
|
{{ view?.meta?.lockedViewDescription }}
|
||
|
</div>
|
||
|
<div class="text-sm text-nc-content-gray">
|
||
|
{{ $t('title.unlockViewTitleSubtitle') }}
|
||
|
<span v-if="idUserMap[view?.meta?.lockedByUserId]?.id === user.id" class="font-bold"> {{ $t('general.you') }} </span>
|
||
|
<span v-else class="font-bold">
|
||
|
{{ idUserMap[view?.meta?.lockedByUserId]?.display_name || idUserMap[view?.meta?.lockedByUserId]?.email }}
|
||
|
</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div class="flex gap-2 items-center justify-end">
|
||
|
<NcButton type="secondary" size="small" :disabled="isLoading" data-testid="nc-cancel-btn" @click="dialogShow = false">{{
|
||
|
$t('general.cancel')
|
||
|
}}</NcButton>
|
||
|
|
||
|
<NcButton
|
||
|
type="primary"
|
||
|
html-type="submit"
|
||
|
size="small"
|
||
|
:loading="isLoading"
|
||
|
:disabled="isLoading || isErrored"
|
||
|
data-testid="nc-lock-or-unlock-btn"
|
||
|
>
|
||
|
<template #icon>
|
||
|
<GeneralIcon :icon="changeType === LockType.Locked ? 'ncLock' : 'ncUnlock'" class="flex-none" />
|
||
|
</template>
|
||
|
<div
|
||
|
class="flex"
|
||
|
:class="{
|
||
|
'-ml-1': !isLoading,
|
||
|
}"
|
||
|
>
|
||
|
{{ changeType === LockType.Locked ? $t('labels.lockView') : $t('labels.unlockView') }}
|
||
|
</div>
|
||
|
</NcButton>
|
||
|
</div>
|
||
|
</a-form>
|
||
|
</NcModal>
|
||
|
</template>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.ant-form-item {
|
||
|
@apply mb-0;
|
||
|
}
|
||
|
|
||
|
.nc-unlock-view-wrapper {
|
||
|
box-shadow: 0px 8px 8px -4px rgba(0, 0, 0, 0.04), 0px 20px 24px -4px rgba(0, 0, 0, 0.1);
|
||
|
}
|
||
|
</style>
|