Browse Source

Merge branch 'develop' into feat/main-section

pull/2819/head
Pranav C 2 years ago committed by GitHub
parent
commit
eb9fc1514a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  2. 2
      packages/nc-gui-v2/components/dashboard/settings/AuditTab.vue
  3. 112
      packages/nc-gui-v2/components/dashboard/settings/Metadata.vue
  4. 6
      packages/nc-gui-v2/components/dashboard/settings/SettingsModal.vue
  5. 140
      packages/nc-gui-v2/components/dashboard/settings/UIAcl.vue
  6. 2
      packages/nc-gui-v2/components/dlg/AirtableImport.vue
  7. 2
      packages/nc-gui-v2/components/dlg/QuickImport.vue
  8. 2
      packages/nc-gui-v2/components/dlg/TableCreate.vue
  9. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  10. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  11. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue

2
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -218,7 +218,7 @@ const addTableTab = (table: TableType) => {
<span class="flex-grow text-bold nc-project-tree"
>{{ $t('objects.tables') }} <template v-if="tables?.length">({{ tables.length }})</template></span
>
<MdiPlus v-t="['c:table:create:navdraw']" class="text-gray-500" @click.stop="tableCreateDlg = true" />
<MdiPlus v-t="['c:table:create:navdraw']" class="text-gray-500 nc-btn-tbl-add" @click.stop="tableCreateDlg = true" />
<MdiMenuDown
class="transition-transform !duration-100 text-gray-500"
:class="{ 'transform rotate-180': showTableList }"

2
packages/nc-gui-v2/components/dashboard/settings/AuditTab.vue

@ -96,6 +96,6 @@ const columns = [
/>
</div>
<a-table class="w-full" :data-source="audits ?? []" :columns="columns" :pagination="false" :loading="isLoading" />
<a-table class="w-full" size="small" :data-source="audits ?? []" :columns="columns" :pagination="false" :loading="isLoading" />
</div>
</template>

112
packages/nc-gui-v2/components/dashboard/settings/Metadata.vue

@ -0,0 +1,112 @@
<script setup lang="ts">
import { useToast } from 'vue-toastification'
import { h, useNuxtApp, useProject } from '#imports'
import MdiReload from '~icons/mdi/reload'
import MdiDatabaseSync from '~icons/mdi/database-sync'
const { $api } = useNuxtApp()
const { project } = useProject()
const toast = useToast()
let isLoading = $ref(false)
let isDifferent = $ref(false)
let metadiff = $ref<any[]>([])
async function loadMetaDiff() {
try {
if (!project.value?.id) return
isLoading = true
isDifferent = false
metadiff = await $api.project.metaDiffGet(project.value?.id)
for (const model of metadiff) {
if (model.detectedChanges?.length > 0) {
model.syncState = model.detectedChanges.map((el: any) => el?.msg).join(', ')
isDifferent = true
}
}
} catch (e) {
console.error(e)
} finally {
isLoading = false
}
}
async function syncMetaDiff() {
try {
if (!project.value?.id || !isDifferent) return
isLoading = true
await $api.project.metaDiffSync(project.value.id)
toast.info(`Table metadata recreated successfully`)
await loadMetaDiff()
} catch (e: any) {
if (e.response?.status === 402) {
toast.info(e.message)
} else {
toast.error(e.message)
}
} finally {
isLoading = false
}
}
onMounted(async () => {
if (metadiff.length === 0) {
await loadMetaDiff()
}
})
const tableHeaderRenderer = (label: string) => () => h('div', { class: 'text-gray-500' }, label)
const columns = [
{
title: tableHeaderRenderer('Models'),
dataIndex: 'title',
key: 'title',
},
{
title: tableHeaderRenderer('Sync State'),
dataIndex: 'syncState',
key: 'syncState',
customRender: (value: { text: string }) =>
h('div', { style: { color: value.text ? 'red' : 'gray' } }, value.text || 'No change identified'),
},
]
</script>
<template>
<div class="flex flex-row w-full">
<div class="flex flex-column w-3/5">
<div class="flex flex-row justify-end items-center w-full mb-4">
<a-button class="self-start" @click="loadMetaDiff">
<div class="flex items-center gap-2 text-gray-600 font-light">
<MdiReload :class="{ 'animate-infinite animate-spin !text-success': isLoading }" />
Reload
</div>
</a-button>
</div>
<a-table
class="w-full"
:data-source="metadiff ?? []"
:columns="columns"
:pagination="false"
:loading="isLoading"
bordered
/>
</div>
<div class="flex place-content-center w-2/5">
<div v-if="isDifferent">
<a-button v-t="['a:proj-meta:meta-data:sync']" type="primary" @click="syncMetaDiff">
<div class="flex items-center gap-2">
<MdiDatabaseSync />
Sync Now
</div>
</a-button>
</div>
<div v-else>
<span><a-alert message="Tables metadata is in sync" type="success" show-icon /></span>
</div>
</div>
</div>
</template>

6
packages/nc-gui-v2/components/dashboard/settings/SettingsModal.vue

@ -2,6 +2,8 @@
import type { FunctionalComponent, SVGAttributes } from 'vue'
import AuditTab from './AuditTab.vue'
import AppStore from './AppStore.vue'
import Metadata from './Metadata.vue'
import UIAcl from './UIAcl.vue'
import StoreFrontOutline from '~icons/mdi/storefront-outline'
import TeamFillIcon from '~icons/ri/team-fill'
import MultipleTableIcon from '~icons/mdi/table-multiple'
@ -61,11 +63,11 @@ const tabsInfo: TabGroup = {
subTabs: {
metaData: {
title: 'Metadata',
body: () => AuditTab,
body: () => Metadata,
},
acl: {
title: 'UI Access Control',
body: () => AuditTab,
body: () => UIAcl,
},
},
},

140
packages/nc-gui-v2/components/dashboard/settings/UIAcl.vue

@ -0,0 +1,140 @@
<script setup lang="ts">
import { useToast } from 'vue-toastification'
import { viewIcons } from '~/utils/viewUtils'
import { h, useNuxtApp, useProject } from '#imports'
import MdiReload from '~icons/mdi/reload'
import MdiContentSave from '~icons/mdi/content-save'
import MdiMagnify from '~icons/mdi/magnify'
const { $api, $e } = useNuxtApp()
const { project } = useProject()
const toast = useToast()
const roles = $ref<string[]>(['editor', 'commenter', 'viewer'])
let isLoading = $ref(false)
let tables = $ref<any[]>([])
let searchInput = $ref('')
const filteredTables = computed(() =>
tables.filter(
(el) =>
(typeof el?._ptn === 'string' && el._ptn.toLowerCase().includes(searchInput.toLowerCase())) ||
(typeof el?.title === 'string' && el.title.toLowerCase().includes(searchInput.toLowerCase())),
),
)
async function loadTableList() {
try {
if (!project.value?.id) return
isLoading = true
// TODO includeM2M
tables = await $api.project.modelVisibilityList(project.value?.id, {
includeM2M: '',
})
} catch (e) {
console.error(e)
} finally {
isLoading = false
}
}
async function saveUIAcl() {
try {
if (!project.value?.id) return
await $api.project.modelVisibilitySet(
project.value.id,
tables.filter((t) => t.edited),
)
toast.success('Updated UI ACL for tables successfully')
} catch (e: any) {
toast.error(e?.message)
}
$e('a:proj-meta:ui-acl')
}
const onRoleCheck = (record: any, role: string) => {
record.disabled[role] = !record.disabled[role]
record.edited = true
}
onMounted(async () => {
if (tables.length === 0) {
await loadTableList()
}
})
const tableHeaderRenderer = (label: string) => () => h('div', { class: 'text-gray-500' }, label)
const columns = [
{
title: tableHeaderRenderer('Table name'),
name: 'table_name',
},
{
title: tableHeaderRenderer('View name'),
name: 'view_name',
},
{
title: tableHeaderRenderer('Editor'),
name: 'editor',
width: 150,
},
{
title: tableHeaderRenderer('Commenter'),
name: 'commenter',
width: 150,
},
{
title: tableHeaderRenderer('Viewer'),
name: 'viewer',
width: 150,
},
]
</script>
<template>
<div class="flex flex-row w-full">
<div class="flex flex-column w-full">
<div class="flex flex-row items-center w-full mb-4 gap-2">
<a-input v-model:value="searchInput" placeholder="Search models">
<template #prefix>
<MdiMagnify />
</template>
</a-input>
<a-button class="self-start" @click="loadTableList">
<div class="flex items-center gap-2 text-gray-600 font-light">
<MdiReload :class="{ 'animate-infinite animate-spin !text-success': isLoading }" />
Reload
</div>
</a-button>
<a-button class="self-start" @click="saveUIAcl">
<div class="flex items-center gap-2 text-gray-600 font-light">
<MdiContentSave />
Save
</div>
</a-button>
</div>
<a-table class="w-full" :data-source="filteredTables" :columns="columns" :pagination="false" :loading="isLoading" bordered>
<template #bodyCell="{ record, column }">
<div v-if="column.name === 'table_name'">{{ record._ptn }}</div>
<div v-if="column.name === 'view_name'">
<div class="flex align-center">
<component :is="viewIcons[record.type].icon" :class="`text-${viewIcons[record.type].color} mr-1`" />
{{ record.title }}
</div>
</div>
<div v-for="role in roles" :key="role">
<div v-if="column.name === role">
<a-tooltip>
<template #title>Click to hide '{{ record.title }}' for role:{{ role }} in UI dashboard</template>
<a-checkbox :checked="!record.disabled[role]" @change="onRoleCheck(record, role)"></a-checkbox>
</a-tooltip>
</div>
</div>
</template>
</a-table>
</div>
</div>
</template>

2
packages/nc-gui-v2/components/dlg/AirtableImport.vue

@ -210,7 +210,7 @@ onBeforeUnmount(() => {
</script>
<template>
<a-modal v-model:visible="dialogShow" width="max(90vw, 600px)" @keydown.esc="dialogShow = false">
<a-modal v-model:visible="dialogShow" width="max(30vw, 600px)" @keydown.esc="dialogShow = false">
<template #footer>
<div v-if="step === 1">
<a-button key="back" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>

2
packages/nc-gui-v2/components/dlg/QuickImport.vue

@ -228,7 +228,7 @@ function getAdapter(name: string, val: any) {
</script>
<template>
<a-modal v-model:visible="dialogShow" width="max(90vw, 600px)" @keydown.esc="dialogShow = false">
<a-modal v-model:visible="dialogShow" width="max(60vw, 600px)" @keydown.esc="dialogShow = false">
<a-typography-title class="ml-5 mt-5 mb-5" type="secondary" :level="5">{{ importMeta.header }}</a-typography-title>
<template #footer>
<a-button v-if="templateEditorModal" key="back" @click="templateEditorModal = false">Back</a-button>

2
packages/nc-gui-v2/components/dlg/TableCreate.vue

@ -85,7 +85,7 @@ onMounted(() => {
<template>
<a-modal
v-model:visible="dialogShow"
width="max(90vw, 600px)"
width="max(30vw, 600px)"
@keydown.esc="dialogShow = false"
@keydown.enter="$emit('create', table)"
>

2
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue

@ -22,7 +22,7 @@ const applyChanges = () => {}
<div class="flex align-center gap-1">
<MdiFilterIcon class="text-grey" />
<!-- Filter -->
<span class="text-capitalize">{{ $t('activity.filter') }}</span>
<span class="text-capitalize nc-filter-menu-btn">{{ $t('activity.filter') }}</span>
<MdiMenuDownIcon class="text-grey" />
</div>
</a-button>

2
packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue

@ -82,7 +82,7 @@ const onMove = (event) => {
<!-- <v-icon small class="mr-1" color="#777"> mdi-eye-off-outline </v-icon> -->
<MdiEyeIcon class="text-grey"></MdiEyeIcon>
<!-- Fields -->
<span class="text-capitalize">{{ $t('objects.fields') }}</span>
<span class="text-sm text-capitalize nc-fields-menu-btn">{{ $t('objects.fields') }}</span>
<MdiMenuDownIcon class="text-grey"></MdiMenuDownIcon>
</div>
</a-button>

2
packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue

@ -33,7 +33,7 @@ watch(
><div class="flex align-center gap-1">
<MdiSortIcon class="text-grey" />
<!-- Sort -->
<span class="text-capitalize">{{ $t('activity.sort') }}</span>
<span class="text-capitalize nc-sort-menu-btn">{{ $t('activity.sort') }}</span>
<MdiMenuDownIcon class="text-grey" />
</div>
</a-button>

Loading…
Cancel
Save