Browse Source

fix: review comments

pull/8708/head
Pranav C 5 months ago
parent
commit
212488b1c1
  1. 42
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  2. 18
      packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue
  3. 2
      packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue
  4. 2
      packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue
  5. 9
      packages/nc-gui/components/smartsheet/grid/Table.vue
  6. 16
      packages/nc-gui/components/smartsheet/header/Menu.vue
  7. 5
      packages/nc-gui/lang/en.json
  8. 13
      tests/playwright/pages/Dashboard/TreeView.ts
  9. 10
      tests/playwright/tests/db/general/sourceRestrictions.spec.ts

42
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -72,9 +72,20 @@ const customFormState = ref<ProjectCreateForm>({
extraParameters: [], extraParameters: [],
}) })
const easterEgg = ref(false)
const easterEggCount = ref(0)
const onEasterEgg = () => {
easterEggCount.value += 1
if (easterEggCount.value >= 2) {
easterEgg.value = true
}
}
const clientTypes = computed(() => { const clientTypes = computed(() => {
return _clientTypes.filter((type) => { return _clientTypes.filter((type) => {
return ![ClientType.SNOWFLAKE, ClientType.DATABRICKS].includes(type.value) return ![ClientType.SNOWFLAKE, ClientType.DATABRICKS, ...(easterEgg.value ? [ClientType.MSSQL] : [])].includes(type.value)
}) })
}) })
@ -404,7 +415,11 @@ const allowMetaWrite = computed({
get: () => !formState.value.is_schema_readonly, get: () => !formState.value.is_schema_readonly,
set: (v) => { set: (v) => {
formState.value.is_schema_readonly = !v formState.value.is_schema_readonly = !v
$e('c:source:schema-write-toggle', {allowed: !v}) // if schema write is allowed, data write should be allowed too
if (v) {
formState.value.is_data_readonly = false
}
$e('c:source:schema-write-toggle', { allowed: !v, edit: true })
}, },
}) })
@ -550,18 +565,30 @@ const allowDataWrite = computed({
<a-form-item> <a-form-item>
<template #label> <template #label>
<div class="flex gap-1 justify-end"> <div class="flex gap-1 justify-end">
<span> <span>
{{ $t('labels.allowDataWrite') }} {{ $t('labels.allowDataWrite') }}
</span> </span>
<NcTooltip> <NcTooltip>
<template #title> <template #title>
<span>{{ $t('tooltip.allowDataWrite') }}</span> <span>{{ $t('tooltip.allowDataWrite') }}</span>
</template> </template>
<GeneralIcon class="text-gray-500" icon="info"/> <GeneralIcon class="text-gray-500" icon="info" />
</NcTooltip> </NcTooltip>
</div> </div>
</template> </template>
<a-switch v-model:checked="allowDataWrite" data-testid="nc-allow-data-write" size="small"></a-switch> <div class="flex justify-start">
<NcTooltip :disabled="!allowMetaWrite" placement="topLeft">
<template #title>
{{ $t('tooltip.dataWriteOptionDisabled') }}
</template>
<a-switch
v-model:checked="allowDataWrite"
:disabled="allowMetaWrite"
data-testid="nc-allow-data-write"
size="small"
></a-switch>
</NcTooltip>
</div>
</a-form-item> </a-form-item>
<div class="flex items-right justify-end gap-2"> <div class="flex items-right justify-end gap-2">
@ -730,6 +757,7 @@ const allowDataWrite = computed({
<a-form-item class="flex justify-end !mt-5"> <a-form-item class="flex justify-end !mt-5">
<div class="flex justify-end gap-2"> <div class="flex justify-end gap-2">
<div class="w-[15px] h-[15px] cursor-pointer" @dblclick="onEasterEgg"></div>
<NcButton <NcButton
:type="testSuccess ? 'ghost' : 'primary'" :type="testSuccess ? 'ghost' : 'primary'"
size="small" size="small"

18
packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue

@ -369,6 +369,10 @@ const allowMetaWrite = computed({
get: () => !formState.value.is_schema_readonly, get: () => !formState.value.is_schema_readonly,
set: (v) => { set: (v) => {
formState.value.is_schema_readonly = !v formState.value.is_schema_readonly = !v
// if schema write is allowed, data write should be allowed too
if (v) {
formState.value.is_data_readonly = false
}
$e('c:source:schema-write-toggle', { allowed: !v, edit: true }) $e('c:source:schema-write-toggle', { allowed: !v, edit: true })
}, },
}) })
@ -579,7 +583,19 @@ const allowDataWrite = computed({
</NcTooltip> </NcTooltip>
</div> </div>
</template> </template>
<a-switch v-model:checked="allowDataWrite" data-testid="nc-allow-data-write" size="small"></a-switch> <div class="flex justify-start">
<NcTooltip :disabled="!allowMetaWrite" placement="topLeft">
<template #title>
{{ $t('tooltip.dataWriteOptionDisabled') }}
</template>
<a-switch
v-model:checked="allowDataWrite"
:disabled="allowMetaWrite"
data-testid="nc-allow-data-write"
size="small"
></a-switch>
</NcTooltip>
</div>
</a-form-item> </a-form-item>
<!-- Use Connection URL --> <!-- Use Connection URL -->
<div class="flex justify-end gap-2"> <div class="flex justify-end gap-2">

2
packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue

@ -996,7 +996,7 @@ watch(
</template> </template>
</NcDropdown> </NcDropdown>
<NcButton <NcButton
v-else-if="!isPublic" v-else-if="!isPublic && isUIAllowed('dataEdit')"
:class="{ :class="{
'!block': hour.isSame(selectedTime), '!block': hour.isSame(selectedTime),
'!hidden': !hour.isSame(selectedTime), '!hidden': !hour.isSame(selectedTime),

2
packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue

@ -27,7 +27,7 @@ const inputRef = ref()
const activeFieldIndex = ref(-1) const activeFieldIndex = ref(-1)
const onClick = (uidt: UITypes) => { const onClick = (uidt: UITypes) => {
if (!uidt) return if (!uidt || isDisabledUIType(uidt)) return
emits('selected', uidt) emits('selected', uidt)
} }

9
packages/nc-gui/components/smartsheet/grid/Table.vue

@ -209,7 +209,10 @@ const isGridCellMouseDown = ref(false)
// #Context Menu // #Context Menu
const _contextMenu = ref(false) const _contextMenu = ref(false)
const contextMenu = computed({ const contextMenu = computed({
get: () => _contextMenu.value, get: () => {
if (props.data?.some((r) => r.rowMeta.selected) && isDataReadOnly.value) return false
return _contextMenu.value
},
set: (val) => { set: (val) => {
_contextMenu.value = val _contextMenu.value = val
}, },
@ -2172,7 +2175,9 @@ onKeyStroke('ArrowDown', onDown)
<template #overlay> <template #overlay>
<NcMenu class="!rounded !py-0" @click="contextMenu = false"> <NcMenu class="!rounded !py-0" @click="contextMenu = false">
<NcMenuItem <NcMenuItem
v-if="isEeUI && !contextMenuClosing && !contextMenuTarget && data.some((r) => r.rowMeta.selected)" v-if="
isEeUI && !contextMenuClosing && !contextMenuTarget && data.some((r) => r.rowMeta.selected) && !isDataReadOnly
"
@click="emits('bulkUpdateDlg')" @click="emits('bulkUpdateDlg')"
> >
<div v-e="['a:row:update-bulk']" class="flex gap-2 items-center"> <div v-e="['a:row:update-bulk']" class="flex gap-2 items-center">

16
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -43,7 +43,7 @@ const { gridViewCols } = useViewColumnsOrThrow()
const { fieldsToGroupBy, groupByLimit } = useViewGroupByOrThrow(view) const { fieldsToGroupBy, groupByLimit } = useViewGroupByOrThrow(view)
const { isUIAllowed, isMetaReadOnly } = useRoles() const { isUIAllowed, isMetaReadOnly, isDataReadOnly } = useRoles()
const isLoading = ref<'' | 'hideOrShow' | 'setDisplay'>('') const isLoading = ref<'' | 'hideOrShow' | 'setDisplay'>('')
@ -325,7 +325,11 @@ const isDeleteAllowed = computed(() => {
return column?.value && !column.value.system return column?.value && !column.value.system
}) })
const isDuplicateAllowed = computed(() => { const isDuplicateAllowed = computed(() => {
return column?.value && !column.value.system return (
column?.value &&
!column.value.system &&
((!isMetaReadOnly.value && !isDataReadOnly.value) || readonlyMetaAllowedTypes.includes(column.value?.uidt))
)
}) })
const isFilterSupported = computed( const isFilterSupported = computed(
() => () =>
@ -394,7 +398,7 @@ const isColumnUpdateAllowed = computed(() => {
</NcMenuItem> </NcMenuItem>
<NcMenuItem <NcMenuItem
v-if="isUIAllowed('duplicateColumn') && isExpandedForm && !column?.pk" v-if="isUIAllowed('duplicateColumn') && isExpandedForm && !column?.pk"
:disabled="!isDuplicateAllowed || !isColumnUpdateAllowed" :disabled="!isDuplicateAllowed"
@click="openDuplicateDlg" @click="openDuplicateDlg"
> >
<div v-e="['a:field:duplicate']" class="nc-column-duplicate nc-header-menu-item"> <div v-e="['a:field:duplicate']" class="nc-column-duplicate nc-header-menu-item">
@ -530,14 +534,16 @@ const isColumnUpdateAllowed = computed(() => {
</NcMenuItem> </NcMenuItem>
</template> </template>
<a-divider v-if="!column?.pv" class="!my-0" /> <a-divider v-if="!column?.pv" class="!my-0" />
<NcMenuItem <NcMenuItem
v-if="!column?.pv && isUIAllowed('fieldDelete')" v-if="!column?.pv && isUIAllowed('fieldDelete')"
:disabled="!isDeleteAllowed || !isColumnUpdateAllowed" :disabled="!isDeleteAllowed || !isColumnUpdateAllowed"
class="!hover:bg-red-50" class="!hover:bg-red-50"
@click="handleDelete" @click="handleDelete"
> >
<div class="nc-column-delete nc-header-menu-item text-red-600"> <div
class="nc-column-delete nc-header-menu-item"
:class="{ ' text-red-600': isDeleteAllowed && isColumnUpdateAllowed }"
>
<component :is="iconMap.delete" /> <component :is="iconMap.delete" />
<!-- Delete --> <!-- Delete -->
{{ $t('general.delete') }} {{ $t('general.delete') }}

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

@ -456,8 +456,8 @@
"looksLikeThisStackIsEmpty": "Looks like this stack does not have any records" "looksLikeThisStackIsEmpty": "Looks like this stack does not have any records"
}, },
"labels": { "labels": {
"allowMetaWrite" : "Allow Schema Change", "allowMetaWrite" : "Allow Schema Edit",
"allowDataWrite" : "Allow Data Write/Edit", "allowDataWrite" : "Allow Data Edit",
"selectView": "Select a View", "selectView": "Select a View",
"connectionDetails": "Connection Details", "connectionDetails": "Connection Details",
"metaSync": "Meta Sync", "metaSync": "Meta Sync",
@ -1040,6 +1040,7 @@
"group": "Group" "group": "Group"
}, },
"tooltip": { "tooltip": {
"dataWriteOptionDisabled": "Data editing can disable only when ‘Schema edit’ is disabled and becomes enabled otherwise",
"allowMetaWrite": "Enable this option to allow modifications to the database schema, including adding, altering, or deleting tables and columns. Use with caution, as changes may affect application functionality.", "allowMetaWrite": "Enable this option to allow modifications to the database schema, including adding, altering, or deleting tables and columns. Use with caution, as changes may affect application functionality.",
"allowDataWrite": "Enable this option to allow updating, deleting, or inserting data within the database tables. Ideal for administrative users who need to manage data directly.", "allowDataWrite": "Enable this option to allow updating, deleting, or inserting data within the database tables. Ideal for administrative users who need to manage data directly.",
"reachedSourceLimit": "Limited to only one data source for the moment", "reachedSourceLimit": "Limited to only one data source for the moment",

13
tests/playwright/pages/Dashboard/TreeView.ts

@ -366,6 +366,19 @@ export class TreeViewPage extends BasePage {
await this.rootPage.locator('div.ant-modal-content').locator(`button.ant-btn:has-text("Delete")`).click(); await this.rootPage.locator('div.ant-modal-content').locator(`button.ant-btn:has-text("Delete")`).click();
} }
async duplicateProject(param: { title: string; context: NcContext }) {
param.title = this.scopedProjectTitle({ title: param.title, context: param.context });
await this.openProjectContextMenu({ baseTitle: param.title });
const contextMenu = this.dashboard.get().locator('.ant-dropdown-menu.nc-scrollbar-md:visible');
await contextMenu.waitFor();
await contextMenu.locator(`.ant-dropdown-menu-item:has-text("Duplicate")`).click();
await this.rootPage.locator('div.ant-modal-content').locator(`button.ant-btn:has-text("Confirm")`).click();
await this.rootPage.waitForTimeout(10000);
}
async openProjectSourceSettings(param: { title: string; context: NcContext }) { async openProjectSourceSettings(param: { title: string; context: NcContext }) {
param.title = this.scopedProjectTitle({ title: param.title, context: param.context }); param.title = this.scopedProjectTitle({ title: param.title, context: param.context });

10
tests/playwright/tests/db/general/sourceRestrictions.spec.ts

@ -34,6 +34,7 @@ test.describe('Source Restrictions', () => {
await settingsPage.selectTab({ tab: 'dataSources' }); await settingsPage.selectTab({ tab: 'dataSources' });
await dashboard.rootPage.waitForTimeout(300); await dashboard.rootPage.waitForTimeout(300);
await settingsPage.source.updateSchemaReadOnly({ sourceName: 'Default', readOnly: true });
await settingsPage.source.updateDataReadOnly({ sourceName: 'Default', readOnly: true }); await settingsPage.source.updateDataReadOnly({ sourceName: 'Default', readOnly: true });
await settingsPage.close(); await settingsPage.close();
@ -78,6 +79,13 @@ test.describe('Source Restrictions', () => {
.locator('.nc-ui-dt-dropdown') .locator('.nc-ui-dt-dropdown')
.scrollIntoViewIfNeeded(); .scrollIntoViewIfNeeded();
await dashboard.grid.get().locator(`th[data-title="LastName"]`).first().locator('.nc-ui-dt-dropdown').click(); await dashboard.grid.get().locator(`th[data-title="LastName"]`).first().locator('.nc-ui-dt-dropdown').click();
await expect(await dashboard.rootPage.locator('li[role="menuitem"]:has-text("Edit"):visible').last()).toBeVisible(); for (const item of ['Edit', 'Delete', 'Duplicate']) {
await expect(
await dashboard.rootPage.locator(`li[role="menuitem"]:has-text("${item}"):visible`).last()
).toBeVisible();
await expect(
await dashboard.rootPage.locator(`li[role="menuitem"]:has-text("${item}"):visible`).last()
).toHaveClass(/ant-dropdown-menu-item-disabled/);
}
}); });
}); });

Loading…
Cancel
Save