|
|
@ -1,7 +1,7 @@ |
|
|
|
<script lang="ts" setup> |
|
|
|
<script lang="ts" setup> |
|
|
|
import type { ColumnType, KanbanType, ViewType } from 'nocodb-sdk' |
|
|
|
import type { ColumnType, KanbanType, ViewType } from 'nocodb-sdk' |
|
|
|
import { ViewTypes } from 'nocodb-sdk' |
|
|
|
import { ViewTypes } from 'nocodb-sdk' |
|
|
|
import { PreFilledMode, useMetas } from '#imports' |
|
|
|
import { PreFilledMode, iconMap, message, storeToRefs, useBase, useMetas } from '#imports' |
|
|
|
|
|
|
|
|
|
|
|
const { view: _view, $api } = useSmartsheetStoreOrThrow() |
|
|
|
const { view: _view, $api } = useSmartsheetStoreOrThrow() |
|
|
|
const { $e } = useNuxtApp() |
|
|
|
const { $e } = useNuxtApp() |
|
|
@ -11,6 +11,14 @@ const { dashboardUrl } = useDashboard() |
|
|
|
|
|
|
|
|
|
|
|
const viewStore = useViewsStore() |
|
|
|
const viewStore = useViewsStore() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { viewsByTable } = storeToRefs(viewStore) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { showShareModal } = storeToRefs(useShare()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const baseStore = useBase() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { navigateToProjectPage } = baseStore |
|
|
|
|
|
|
|
|
|
|
|
const { metas } = useMetas() |
|
|
|
const { metas } = useMetas() |
|
|
|
|
|
|
|
|
|
|
|
const workspaceStore = useWorkspace() |
|
|
|
const workspaceStore = useWorkspace() |
|
|
@ -44,8 +52,34 @@ const activeView = computed<(ViewType & { meta: object & Record<string, any> }) |
|
|
|
}, |
|
|
|
}, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const viewsInTable = computed({ |
|
|
|
|
|
|
|
get: () => { |
|
|
|
|
|
|
|
if (!activeView.value) return [] |
|
|
|
|
|
|
|
return viewsByTable.value.get(activeView.value?.fk_model_id) || [] |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
set: (val) => { |
|
|
|
|
|
|
|
viewsByTable.value.set(activeView.value?.fk_model_id, val) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedViewId = ref<string | undefined>(activeView.value?.id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(activeView, (val) => { |
|
|
|
|
|
|
|
selectedViewId.value = val?.id |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedView = computed<(ViewType & { meta: object & Record<string, any> }) | undefined>({ |
|
|
|
|
|
|
|
get: () => { |
|
|
|
|
|
|
|
if (!selectedViewId.value) return |
|
|
|
|
|
|
|
return viewsInTable.value.find((v) => v.id === selectedViewId.value) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
set: (val) => { |
|
|
|
|
|
|
|
viewsInTable.value = viewsInTable.value.map((v) => (v.id === selectedViewId.value ? val : v)) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const isPublicShared = computed(() => { |
|
|
|
const isPublicShared = computed(() => { |
|
|
|
return !!activeView.value?.uuid |
|
|
|
return !!selectedView.value?.uuid |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const url = computed(() => { |
|
|
|
const url = computed(() => { |
|
|
@ -55,27 +89,27 @@ const url = computed(() => { |
|
|
|
const passwordProtectedLocal = ref(false) |
|
|
|
const passwordProtectedLocal = ref(false) |
|
|
|
|
|
|
|
|
|
|
|
const passwordProtected = computed(() => { |
|
|
|
const passwordProtected = computed(() => { |
|
|
|
return !!activeView.value?.password || passwordProtectedLocal.value |
|
|
|
return !!selectedView.value?.password || passwordProtectedLocal.value |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const password = computed({ |
|
|
|
const password = computed({ |
|
|
|
get: () => (passwordProtected.value ? activeView.value?.password ?? '' : ''), |
|
|
|
get: () => (passwordProtected.value ? selectedView.value?.password ?? '' : ''), |
|
|
|
set: async (value) => { |
|
|
|
set: async (value) => { |
|
|
|
if (!activeView.value) return |
|
|
|
if (!selectedView.value) return |
|
|
|
|
|
|
|
|
|
|
|
activeView.value = { ...(activeView.value as any), password: passwordProtected.value ? value : null } |
|
|
|
selectedView.value = { ...(selectedView.value as any), password: passwordProtected.value ? value : null } |
|
|
|
|
|
|
|
|
|
|
|
updateSharedView() |
|
|
|
updateSharedView() |
|
|
|
}, |
|
|
|
}, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const viewTheme = computed({ |
|
|
|
const viewTheme = computed({ |
|
|
|
get: () => !!activeView.value?.meta.withTheme, |
|
|
|
get: () => !!selectedView.value?.meta.withTheme, |
|
|
|
set: (withTheme) => { |
|
|
|
set: (withTheme) => { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
|
|
|
|
|
|
|
|
activeView.value.meta = { |
|
|
|
selectedView.value.meta = { |
|
|
|
...activeView.value.meta, |
|
|
|
...selectedView.value.meta, |
|
|
|
withTheme, |
|
|
|
withTheme, |
|
|
|
} |
|
|
|
} |
|
|
|
saveTheme() |
|
|
|
saveTheme() |
|
|
@ -84,15 +118,15 @@ const viewTheme = computed({ |
|
|
|
|
|
|
|
|
|
|
|
const togglePasswordProtected = async () => { |
|
|
|
const togglePasswordProtected = async () => { |
|
|
|
passwordProtectedLocal.value = !passwordProtected.value |
|
|
|
passwordProtectedLocal.value = !passwordProtected.value |
|
|
|
if (!activeView.value) return |
|
|
|
if (!selectedView.value) return |
|
|
|
if (isUpdating.value.password) return |
|
|
|
if (isUpdating.value.password) return |
|
|
|
|
|
|
|
|
|
|
|
isUpdating.value.password = true |
|
|
|
isUpdating.value.password = true |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (passwordProtected.value) { |
|
|
|
if (passwordProtected.value) { |
|
|
|
activeView.value = { ...(activeView.value as any), password: null } |
|
|
|
selectedView.value = { ...(selectedView.value as any), password: null } |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
activeView.value = { ...(activeView.value as any), password: '' } |
|
|
|
selectedView.value = { ...(selectedView.value as any), password: '' } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
await updateSharedView() |
|
|
|
await updateSharedView() |
|
|
@ -103,35 +137,35 @@ const togglePasswordProtected = async () => { |
|
|
|
|
|
|
|
|
|
|
|
const withRTL = computed({ |
|
|
|
const withRTL = computed({ |
|
|
|
get: () => { |
|
|
|
get: () => { |
|
|
|
if (!activeView.value?.meta) return false |
|
|
|
if (!selectedView.value?.meta) return false |
|
|
|
|
|
|
|
|
|
|
|
if (typeof activeView.value?.meta === 'string') { |
|
|
|
if (typeof selectedView.value?.meta === 'string') { |
|
|
|
activeView.value.meta = JSON.parse(activeView.value.meta) |
|
|
|
selectedView.value.meta = JSON.parse(selectedView.value.meta) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return !!(activeView.value?.meta as any)?.rtl |
|
|
|
return !!(selectedView.value?.meta as any)?.rtl |
|
|
|
}, |
|
|
|
}, |
|
|
|
set: (rtl) => { |
|
|
|
set: (rtl) => { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
|
|
|
|
|
|
|
|
if (typeof activeView.value?.meta === 'string') { |
|
|
|
if (typeof selectedView.value?.meta === 'string') { |
|
|
|
activeView.value.meta = JSON.parse(activeView.value.meta) |
|
|
|
selectedView.value.meta = JSON.parse(selectedView.value.meta) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
activeView.value.meta = { ...(activeView.value.meta as any), rtl } |
|
|
|
selectedView.value.meta = { ...(selectedView.value.meta as any), rtl } |
|
|
|
updateSharedView() |
|
|
|
updateSharedView() |
|
|
|
}, |
|
|
|
}, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const allowCSVDownload = computed({ |
|
|
|
const allowCSVDownload = computed({ |
|
|
|
get: () => !!(activeView.value?.meta as any)?.allowCSVDownload, |
|
|
|
get: () => !!(selectedView.value?.meta as any)?.allowCSVDownload, |
|
|
|
set: async (allow) => { |
|
|
|
set: async (allow) => { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
|
|
|
|
|
|
|
|
isUpdating.value.download = true |
|
|
|
isUpdating.value.download = true |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
activeView.value.meta = { ...activeView.value.meta, allowCSVDownload: allow } |
|
|
|
selectedView.value.meta = { ...selectedView.value.meta, allowCSVDownload: allow } |
|
|
|
await saveAllowCSVDownload() |
|
|
|
await saveAllowCSVDownload() |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
isUpdating.value.download = false |
|
|
|
isUpdating.value.download = false |
|
|
@ -140,22 +174,22 @@ const allowCSVDownload = computed({ |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const surveyMode = computed({ |
|
|
|
const surveyMode = computed({ |
|
|
|
get: () => !!activeView.value?.meta.surveyMode, |
|
|
|
get: () => !!selectedView.value?.meta.surveyMode, |
|
|
|
set: (survey) => { |
|
|
|
set: (survey) => { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
|
|
|
|
|
|
|
|
activeView.value.meta = { ...activeView.value.meta, surveyMode: survey } |
|
|
|
selectedView.value.meta = { ...selectedView.value.meta, surveyMode: survey } |
|
|
|
saveSurveyMode() |
|
|
|
saveSurveyMode() |
|
|
|
}, |
|
|
|
}, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const formPreFill = computed({ |
|
|
|
const formPreFill = computed({ |
|
|
|
get: () => ({ |
|
|
|
get: () => ({ |
|
|
|
preFillEnabled: parseProp(activeView.value?.meta)?.preFillEnabled ?? false, |
|
|
|
preFillEnabled: parseProp(selectedView.value?.meta)?.preFillEnabled ?? false, |
|
|
|
preFilledMode: parseProp(activeView.value?.meta)?.preFilledMode || PreFilledMode.Default, |
|
|
|
preFilledMode: parseProp(selectedView.value?.meta)?.preFilledMode || PreFilledMode.Default, |
|
|
|
}), |
|
|
|
}), |
|
|
|
set: (value) => { |
|
|
|
set: (value) => { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
|
|
|
|
|
|
|
|
if (formPreFill.value.preFillEnabled !== value.preFillEnabled) { |
|
|
|
if (formPreFill.value.preFillEnabled !== value.preFillEnabled) { |
|
|
|
$e(`a:view:share:prefilled-mode-${value.preFillEnabled ? 'enabled' : 'disabled'}`) |
|
|
|
$e(`a:view:share:prefilled-mode-${value.preFillEnabled ? 'enabled' : 'disabled'}`) |
|
|
@ -165,8 +199,8 @@ const formPreFill = computed({ |
|
|
|
$e(`a:view:share:${value.preFilledMode}-prefilled-mode`) |
|
|
|
$e(`a:view:share:${value.preFilledMode}-prefilled-mode`) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
activeView.value.meta = { |
|
|
|
selectedView.value.meta = { |
|
|
|
...activeView.value.meta, |
|
|
|
...selectedView.value.meta, |
|
|
|
...value, |
|
|
|
...value, |
|
|
|
} |
|
|
|
} |
|
|
|
savePreFilledMode() |
|
|
|
savePreFilledMode() |
|
|
@ -181,10 +215,10 @@ const handleChangeFormPreFill = (value: { preFillEnabled?: boolean; preFilledMod |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function sharedViewUrl() { |
|
|
|
function sharedViewUrl() { |
|
|
|
if (!activeView.value) return |
|
|
|
if (!selectedView.value) return |
|
|
|
|
|
|
|
|
|
|
|
let viewType |
|
|
|
let viewType |
|
|
|
switch (activeView.value.type) { |
|
|
|
switch (selectedView.value.type) { |
|
|
|
case ViewTypes.FORM: |
|
|
|
case ViewTypes.FORM: |
|
|
|
viewType = 'form' |
|
|
|
viewType = 'form' |
|
|
|
break |
|
|
|
break |
|
|
@ -213,30 +247,30 @@ function sharedViewUrl() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return encodeURI( |
|
|
|
return encodeURI( |
|
|
|
`${dashboardUrl1}#/nc/${viewType}/${activeView.value.uuid}${surveyMode.value ? '/survey' : ''}${ |
|
|
|
`${dashboardUrl1}#/nc/${viewType}/${selectedView.value.uuid}${surveyMode.value ? '/survey' : ''}${ |
|
|
|
viewStore.preFillFormSearchParams && formPreFill.value.preFillEnabled ? `?${viewStore.preFillFormSearchParams}` : '' |
|
|
|
viewStore.preFillFormSearchParams && formPreFill.value.preFillEnabled ? `?${viewStore.preFillFormSearchParams}` : '' |
|
|
|
}`, |
|
|
|
}`, |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const toggleViewShare = async () => { |
|
|
|
const toggleViewShare = async () => { |
|
|
|
if (!activeView.value?.id) return |
|
|
|
if (!selectedView.value?.id) return |
|
|
|
|
|
|
|
|
|
|
|
if (activeView.value?.uuid) { |
|
|
|
if (selectedView.value?.uuid) { |
|
|
|
await $api.dbViewShare.delete(activeView.value.id) |
|
|
|
await $api.dbViewShare.delete(selectedView.value.id) |
|
|
|
|
|
|
|
|
|
|
|
activeView.value = { ...activeView.value, uuid: undefined, password: undefined } |
|
|
|
selectedView.value = { ...selectedView.value, uuid: undefined, password: undefined } |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
const response = await $api.dbViewShare.create(activeView.value.id) |
|
|
|
const response = await $api.dbViewShare.create(selectedView.value.id) |
|
|
|
activeView.value = { ...activeView.value, ...(response as any) } |
|
|
|
selectedView.value = { ...selectedView.value, ...(response as any) } |
|
|
|
|
|
|
|
|
|
|
|
if (activeView.value!.type === ViewTypes.KANBAN) { |
|
|
|
if (selectedView.value!.type === ViewTypes.KANBAN) { |
|
|
|
// extract grouping column meta |
|
|
|
// extract grouping column meta |
|
|
|
const groupingFieldColumn = metas.value[viewStore.activeView!.fk_model_id].columns!.find( |
|
|
|
const groupingFieldColumn = metas.value[selectedView.value!.fk_model_id].columns!.find( |
|
|
|
(col: ColumnType) => col.id === ((viewStore.activeView!.view! as KanbanType).fk_grp_col_id! as string), |
|
|
|
(col: ColumnType) => col.id === ((selectedView.value.view! as KanbanType).fk_grp_col_id! as string), |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
activeView.value!.meta = { ...activeView.value!.meta, groupingFieldColumn } |
|
|
|
selectedView.value!.meta = { ...selectedView.value!.meta, groupingFieldColumn } |
|
|
|
|
|
|
|
|
|
|
|
await updateSharedView() |
|
|
|
await updateSharedView() |
|
|
|
} |
|
|
|
} |
|
|
@ -279,12 +313,12 @@ async function saveTheme() { |
|
|
|
|
|
|
|
|
|
|
|
async function updateSharedView() { |
|
|
|
async function updateSharedView() { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (!activeView.value?.meta) return |
|
|
|
if (!selectedView.value?.meta) return |
|
|
|
const meta = activeView.value.meta |
|
|
|
const meta = selectedView.value.meta |
|
|
|
|
|
|
|
|
|
|
|
await $api.dbViewShare.update(activeView.value.id!, { |
|
|
|
await $api.dbViewShare.update(selectedView.value.id!, { |
|
|
|
meta, |
|
|
|
meta, |
|
|
|
password: activeView.value.password, |
|
|
|
password: selectedView.value.password, |
|
|
|
}) |
|
|
|
}) |
|
|
|
} catch (e: any) { |
|
|
|
} catch (e: any) { |
|
|
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
|
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
|
@ -297,31 +331,55 @@ async function savePreFilledMode() { |
|
|
|
await updateSharedView() |
|
|
|
await updateSharedView() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
watchEffect(() => {}) |
|
|
|
const openManageAccess = async () => { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
await navigateToProjectPage({ page: 'collaborator' }) |
|
|
|
|
|
|
|
showShareModal.value = false |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
console.error(e) |
|
|
|
|
|
|
|
message.error('Failed to open manage access') |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
</script> |
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div class="flex flex-col py-2 px-3 mb-1"> |
|
|
|
<div class="flex flex-col !h-80 justify-between"> |
|
|
|
<div class="flex flex-col w-full mt-2.5 px-3 py-2.5 border-gray-200 border-1 rounded-md gap-y-2"> |
|
|
|
<div class="flex flex-col p-3 border-gray-200 border-1 rounded-lg gap-y-2"> |
|
|
|
<div class="flex flex-row w-full justify-between py-0.5"> |
|
|
|
<div class="flex flex-row items-center justify-between"> |
|
|
|
<div class="text-gray-900 font-medium">{{ $t('activity.enabledPublicViewing') }}</div> |
|
|
|
<div class="flex items-center gap-3"> |
|
|
|
|
|
|
|
<span class="text-gray-900 font-medium">{{ $t('activity.enabledPublicViewing') }}</span> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<NcSelect v-model:value="selectedViewId" class="w-48" size="medium"> |
|
|
|
|
|
|
|
<a-select-option v-for="view in viewsInTable" :key="view.id" :value="view.id"> |
|
|
|
|
|
|
|
<div class="flex items-center w-full justify-between w-full gap-2"> |
|
|
|
|
|
|
|
<GeneralViewIcon :meta="view" class="!text-md mt-0.5" /> |
|
|
|
|
|
|
|
<span class="truncate !w-36 flex-1 capitalize">{{ view.title }}</span> |
|
|
|
|
|
|
|
<component |
|
|
|
|
|
|
|
:is="iconMap.check" |
|
|
|
|
|
|
|
v-if="view.id === selectedViewId" |
|
|
|
|
|
|
|
id="nc-selected-item-icon" |
|
|
|
|
|
|
|
class="text-primary w-4 h-4" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</a-select-option> |
|
|
|
|
|
|
|
</NcSelect> |
|
|
|
|
|
|
|
</div> |
|
|
|
<a-switch |
|
|
|
<a-switch |
|
|
|
v-e="['c:share:view:enable:toggle']" |
|
|
|
v-e="['c:share:view:enable:toggle']" |
|
|
|
|
|
|
|
size="small" |
|
|
|
:checked="isPublicShared" |
|
|
|
:checked="isPublicShared" |
|
|
|
:disabled="isLocked" |
|
|
|
:disabled="isLocked" |
|
|
|
:loading="isUpdating.public" |
|
|
|
:loading="isUpdating.public" |
|
|
|
class="share-view-toggle !mt-0.25" |
|
|
|
class="share-view-toggle !mt-0.25" |
|
|
|
data-testid="share-view-toggle" |
|
|
|
data-testid="share-view-toggle" |
|
|
|
@click="toggleShare" |
|
|
|
@change="toggleShare" |
|
|
|
/> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<template v-if="isPublicShared"> |
|
|
|
|
|
|
|
<div class="mt-0.5 border-t-1 border-gray-100 pt-3"> |
|
|
|
<div v-if="isPublicShared" class="space-y-3"> |
|
|
|
<GeneralCopyUrl v-model:url="url" /> |
|
|
|
<GeneralCopyUrl v-model:url="url" class="w-[34.625rem]" /> |
|
|
|
</div> |
|
|
|
<div class="flex items-center gap-3 h-8 justify-between"> |
|
|
|
<div class="flex flex-col justify-between mt-1 py-2 px-3 bg-gray-50 rounded-md"> |
|
|
|
<div class="flex flex-row gap-3 items-center"> |
|
|
|
<div class="flex flex-row items-center justify-between"> |
|
|
|
|
|
|
|
<div class="flex text-black">{{ $t('activity.restrictAccessWithPassword') }}</div> |
|
|
|
|
|
|
|
<a-switch |
|
|
|
<a-switch |
|
|
|
v-e="['c:share:view:password:toggle']" |
|
|
|
v-e="['c:share:view:password:toggle']" |
|
|
|
:checked="passwordProtected" |
|
|
|
:checked="passwordProtected" |
|
|
@ -329,52 +387,42 @@ watchEffect(() => {}) |
|
|
|
class="share-password-toggle !mt-0.25" |
|
|
|
class="share-password-toggle !mt-0.25" |
|
|
|
data-testid="share-password-toggle" |
|
|
|
data-testid="share-password-toggle" |
|
|
|
size="small" |
|
|
|
size="small" |
|
|
|
@click="togglePasswordProtected" |
|
|
|
@change="togglePasswordProtected" |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
<div class="flex text-black">{{ $t('activity.restrictAccessWithPassword') }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<Transition mode="out-in" name="layout"> |
|
|
|
<a-input-password |
|
|
|
<div v-if="passwordProtected" class="flex gap-2 mt-2 w-2/3"> |
|
|
|
v-if="passwordProtected" |
|
|
|
<a-input-password |
|
|
|
v-model:value="password" |
|
|
|
v-model:value="password" |
|
|
|
:placeholder="$t('placeholder.password.enter')" |
|
|
|
:placeholder="$t('placeholder.password.enter')" |
|
|
|
class="!rounded-lg flex-1 !focus:border-brand-500 !w-72 !focus:ring-0 !focus:shadow-none !border-gray-200 !py-1 !bg-white" |
|
|
|
class="!rounded-lg !py-1 !bg-white" |
|
|
|
data-testid="nc-modal-share-view__password" |
|
|
|
data-testid="nc-modal-share-view__password" |
|
|
|
size="small" |
|
|
|
size="small" |
|
|
|
type="password" |
|
|
|
type="password" |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</Transition> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="flex flex-col justify-between gap-y-3 mt-1 py-2 px-3 bg-gray-50 rounded-md"> |
|
|
|
|
|
|
|
<div |
|
|
|
|
|
|
|
v-if=" |
|
|
|
|
|
|
|
activeView && |
|
|
|
|
|
|
|
[ViewTypes.GRID, ViewTypes.KANBAN, ViewTypes.GALLERY, ViewTypes.MAP, ViewTypes.CALENDAR].includes(activeView.type) |
|
|
|
|
|
|
|
" |
|
|
|
|
|
|
|
class="flex flex-row items-center justify-between" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<div class="flex text-black">{{ $t('activity.allowDownload') }}</div> |
|
|
|
|
|
|
|
<a-switch |
|
|
|
|
|
|
|
v-model:checked="allowCSVDownload" |
|
|
|
|
|
|
|
v-e="['c:share:view:allow-csv-download:toggle']" |
|
|
|
|
|
|
|
:loading="isUpdating.download" |
|
|
|
|
|
|
|
class="public-password-toggle !mt-0.25" |
|
|
|
|
|
|
|
data-testid="share-download-toggle" |
|
|
|
|
|
|
|
size="small" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="activeView?.type === ViewTypes.FORM"> |
|
|
|
<div |
|
|
|
<div class="flex flex-row items-center justify-between"> |
|
|
|
v-if=" |
|
|
|
<div class="text-black flex items-center space-x-1"> |
|
|
|
selectedView && |
|
|
|
<div> |
|
|
|
[ViewTypes.GRID, ViewTypes.KANBAN, ViewTypes.GALLERY, ViewTypes.MAP, ViewTypes.CALENDAR].includes(selectedView.type) |
|
|
|
{{ $t('activity.surveyMode') }} |
|
|
|
" |
|
|
|
</div> |
|
|
|
class="flex flex-row items-center gap-3" |
|
|
|
<NcTooltip> |
|
|
|
> |
|
|
|
<template #title> {{ $t('tooltip.surveyFormInfo') }}</template> |
|
|
|
<a-switch |
|
|
|
<GeneralIcon icon="info" class="text-gray-600 cursor-pointer"></GeneralIcon> |
|
|
|
v-model:checked="allowCSVDownload" |
|
|
|
</NcTooltip> |
|
|
|
v-e="['c:share:view:allow-csv-download:toggle']" |
|
|
|
</div> |
|
|
|
:loading="isUpdating.download" |
|
|
|
|
|
|
|
class="public-password-toggle !mt-0.25" |
|
|
|
|
|
|
|
data-testid="share-download-toggle" |
|
|
|
|
|
|
|
size="small" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
<div class="flex text-black">{{ $t('activity.allowDownload') }}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="selectedView?.type === ViewTypes.FORM"> |
|
|
|
|
|
|
|
<div class="flex items-center justify-between"> |
|
|
|
|
|
|
|
<div class="flex items-center gap-3"> |
|
|
|
<a-switch |
|
|
|
<a-switch |
|
|
|
v-model:checked="surveyMode" |
|
|
|
v-model:checked="surveyMode" |
|
|
|
v-e="['c:share:view:surver-mode:toggle']" |
|
|
|
v-e="['c:share:view:surver-mode:toggle']" |
|
|
@ -382,61 +430,77 @@ watchEffect(() => {}) |
|
|
|
size="small" |
|
|
|
size="small" |
|
|
|
> |
|
|
|
> |
|
|
|
</a-switch> |
|
|
|
</a-switch> |
|
|
|
|
|
|
|
{{ $t('activity.surveyMode') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-if="!isEeUI" class="flex flex-row items-center justify-between"> |
|
|
|
<NcTooltip> |
|
|
|
<div class="text-black">{{ $t('activity.rtlOrientation') }}</div> |
|
|
|
<template #title>{{ $t('tooltip.surveyFormInfo') }} </template> |
|
|
|
|
|
|
|
<component :is="iconMap.info" class="text-gray-500" /> |
|
|
|
|
|
|
|
</NcTooltip> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="!isEeUI" class="flex flex-row items-center gap-3"> |
|
|
|
|
|
|
|
<a-switch |
|
|
|
|
|
|
|
v-model:checked="withRTL" |
|
|
|
|
|
|
|
v-e="['c:share:view:rtl-orientation:toggle']" |
|
|
|
|
|
|
|
data-testid="nc-modal-share-view__RTL" |
|
|
|
|
|
|
|
size="small" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
</a-switch> |
|
|
|
|
|
|
|
<div class="text-black">{{ $t('activity.rtlOrientation') }}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="flex items-center h-8 justify-between"> |
|
|
|
|
|
|
|
<div class="flex items-center gap-3"> |
|
|
|
<a-switch |
|
|
|
<a-switch |
|
|
|
v-model:checked="withRTL" |
|
|
|
v-e="['c:share:view:surver-mode:toggle']" |
|
|
|
v-e="['c:share:view:rtl-orientation:toggle']" |
|
|
|
:checked="formPreFill.preFillEnabled" |
|
|
|
data-testid="nc-modal-share-view__RTL" |
|
|
|
data-testid="nc-modal-share-view__preFill" |
|
|
|
size="small" |
|
|
|
size="small" |
|
|
|
|
|
|
|
@update:checked="handleChangeFormPreFill({ preFillEnabled: $event as boolean })" |
|
|
|
> |
|
|
|
> |
|
|
|
</a-switch> |
|
|
|
</a-switch> |
|
|
|
</div> |
|
|
|
{{ $t('activity.preFilledFields.title') }} |
|
|
|
</template> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div |
|
|
|
|
|
|
|
v-if="activeView?.type === ViewTypes.FORM" |
|
|
|
|
|
|
|
class="nc-pre-filled-mode-wrapper flex flex-col justify-between gap-y-3 mt-1 py-2 px-3 bg-gray-50 rounded-md" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<div class="flex flex-row items-center justify-between"> |
|
|
|
|
|
|
|
<div class="text-black flex items-center space-x-1"> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{{ $t('activity.preFilledFields.title') }} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<NcTooltip> |
|
|
|
<NcSelect |
|
|
|
<template #title> |
|
|
|
v-if="formPreFill.preFillEnabled" |
|
|
|
<div class="text-center"> |
|
|
|
v-model:value="formPreFill.preFilledMode" |
|
|
|
{{ $t('tooltip.preFillFormInfo') }} |
|
|
|
class="w-48" |
|
|
|
|
|
|
|
@change="handleChangeFormPreFill" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<a-select-option |
|
|
|
|
|
|
|
v-for="op of Object.values(PreFilledMode).map((v) => { |
|
|
|
|
|
|
|
return { label: $t(`activity.preFilledFields.${v}`), value: v } |
|
|
|
|
|
|
|
})" |
|
|
|
|
|
|
|
:key="op.value" |
|
|
|
|
|
|
|
:value="op.value" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<div class="flex items-center w-full justify-between w-full gap-2"> |
|
|
|
|
|
|
|
<div class="truncate flex-1 capitalize">{{ op.label }}</div> |
|
|
|
|
|
|
|
<component |
|
|
|
|
|
|
|
:is="iconMap.check" |
|
|
|
|
|
|
|
v-if="formPreFill.preFilledMode === op.value" |
|
|
|
|
|
|
|
id="nc-selected-item-icon" |
|
|
|
|
|
|
|
class="text-primary w-4 h-4" |
|
|
|
|
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</a-select-option> |
|
|
|
<GeneralIcon icon="info" class="text-gray-600 cursor-pointer"></GeneralIcon> |
|
|
|
</NcSelect> |
|
|
|
</NcTooltip> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<a-switch |
|
|
|
<NcTooltip> |
|
|
|
v-e="['c:share:view:surver-mode:toggle']" |
|
|
|
<template #title>{{ $t('tooltip.preFillFormInfo') }} </template> |
|
|
|
:checked="formPreFill.preFillEnabled" |
|
|
|
<component :is="iconMap.info" class="text-gray-500" /> |
|
|
|
data-testid="nc-modal-share-view__preFill" |
|
|
|
</NcTooltip> |
|
|
|
size="small" |
|
|
|
|
|
|
|
@update:checked="handleChangeFormPreFill({ preFillEnabled: $event as boolean })" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
</a-switch> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
</template> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<a-radio-group |
|
|
|
<div class="flex gap-2 items-end justify-end"> |
|
|
|
v-if="formPreFill.preFillEnabled" |
|
|
|
<NcButton type="secondary" @click="openManageAccess"> |
|
|
|
:value="formPreFill.preFilledMode" |
|
|
|
{{ $t('activity.manageAccess') }} |
|
|
|
class="nc-modal-share-view-preFillMode" |
|
|
|
</NcButton> |
|
|
|
data-testid="nc-modal-share-view__preFillMode" |
|
|
|
<NcButton type="secondary" @click="showShareModal = false"> |
|
|
|
@update:value="handleChangeFormPreFill({ preFilledMode: $event })" |
|
|
|
{{ $t('general.finish') }} |
|
|
|
> |
|
|
|
</NcButton> |
|
|
|
<a-radio v-for="mode of Object.values(PreFilledMode)" :key="mode" :value="mode"> |
|
|
|
|
|
|
|
<div class="flex-1">{{ $t(`activity.preFilledFields.${mode}`) }}</div> |
|
|
|
|
|
|
|
</a-radio> |
|
|
|
|
|
|
|
</a-radio-group> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</template> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
@ -459,18 +523,4 @@ watchEffect(() => {}) |
|
|
|
line-height: 1rem !important; |
|
|
|
line-height: 1rem !important; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.nc-modal-share-view-preFillMode { |
|
|
|
|
|
|
|
@apply flex flex-col; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.ant-radio-wrapper { |
|
|
|
|
|
|
|
@apply !m-0 !flex !items-center w-full px-2 py-1 rounded-lg hover:bg-gray-100; |
|
|
|
|
|
|
|
.ant-radio { |
|
|
|
|
|
|
|
@apply !top-0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
.ant-radio + span { |
|
|
|
|
|
|
|
@apply !flex !pl-4; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
</style> |
|
|
|
</style> |
|
|
|