Browse Source

Merge branch 'develop' into fix/gui-v2-form-view-email-me

pull/3364/head
Wing-Kam Wong 2 years ago
parent
commit
a06e2b4150
  1. 12
      packages/nc-gui-v2/components/shared-view/Grid.vue
  2. 6
      packages/nc-gui-v2/components/smartsheet-toolbar/ExportSubActions.vue
  3. 5
      packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue
  4. 3
      packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue
  5. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/SharedViewList.vue
  6. 2
      packages/nc-gui-v2/components/smartsheet/Cell.vue
  7. 11
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  8. 2
      packages/nc-gui-v2/components/tabs/auth/UserManagement.vue
  9. 2
      packages/nc-gui-v2/components/tabs/auth/user-management/ShareBase.vue
  10. 2
      packages/nc-gui-v2/components/tabs/auth/user-management/UsersModal.vue
  11. 1
      packages/nc-gui-v2/composables/useUIPermission/rolePermissions.ts
  12. 3
      packages/nc-gui-v2/package-lock.json
  13. 8
      packages/nc-gui-v2/scripts/updateNuxtRouting.js
  14. 2
      packages/nocodb-sdk/package.json
  15. 23
      packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
  16. 2
      packages/nocodb/src/lib/meta/api/projectUserApis.ts
  17. 2
      packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts

12
packages/nc-gui-v2/components/shared-view/Grid.vue

@ -1,10 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { TableType } from 'nocodb-sdk' import type { TableType } from 'nocodb-sdk'
import { message } from 'ant-design-vue'
import { ActiveViewInj, FieldsInj, IsPublicInj, MetaInj, ReadonlyInj, ReloadViewDataHookInj } from '~/context' import { ActiveViewInj, FieldsInj, IsPublicInj, MetaInj, ReadonlyInj, ReloadViewDataHookInj } from '~/context'
const { sharedView, meta, sorts, nestedFilters } = useSharedView() const { sharedView, meta, sorts, nestedFilters } = useSharedView()
const { signedIn } = useGlobal()
const { loadProject } = useProject(meta?.value.project_id)
const reloadEventHook = createEventHook<void>() const reloadEventHook = createEventHook<void>()
provide(ReloadViewDataHookInj, reloadEventHook) provide(ReloadViewDataHookInj, reloadEventHook)
@ -15,6 +18,15 @@ provide(FieldsInj, ref(meta.value.columns as any[]))
provide(IsPublicInj, ref(true)) provide(IsPublicInj, ref(true))
useProvideSmartsheetStore(sharedView as Ref<TableType>, meta, true, sorts, nestedFilters) useProvideSmartsheetStore(sharedView as Ref<TableType>, meta, true, sorts, nestedFilters)
if (signedIn.value) {
try {
await loadProject()
} catch (e: any) {
console.error(e)
message.error(await extractSdkResponseErrorMsg(e))
}
}
</script> </script>
<template> <template>

6
packages/nc-gui-v2/components/smartsheet-toolbar/ExportSubActions.vue

@ -5,6 +5,7 @@ import * as XLSX from 'xlsx'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
const isPublicView = inject(IsPublicInj, ref(false)) const isPublicView = inject(IsPublicInj, ref(false))
const fields = inject(FieldsInj, ref([])) const fields = inject(FieldsInj, ref([]))
const { project } = useProject() const { project } = useProject()
@ -15,6 +16,8 @@ const meta = inject(MetaInj)
const selectedView = inject(ActiveViewInj) const selectedView = inject(ActiveViewInj)
const { sorts, nestedFilters } = useSmartsheetStoreOrThrow()
const exportFile = async (exportType: ExportTypes) => { const exportFile = async (exportType: ExportTypes) => {
let offset = 0 let offset = 0
let c = 1 let c = 1
@ -36,7 +39,10 @@ const exportFile = async (exportType: ExportTypes) => {
{ {
responseType, responseType,
query: { query: {
fields: fields.value.map((field) => field.title),
offset, offset,
sortArrJson: JSON.stringify(sorts.value),
filterArrJson: JSON.stringify(nestedFilters.value),
}, },
} as any, } as any,
) )

5
packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue

@ -33,6 +33,8 @@ const fields = inject(FieldsInj, ref([]))
const selectedView = inject(ActiveViewInj) const selectedView = inject(ActiveViewInj)
const { sorts, nestedFilters } = useSmartsheetStoreOrThrow()
const isLocked = inject(IsLockedInj) const isLocked = inject(IsLockedInj)
const showWebhookDrawer = ref(false) const showWebhookDrawer = ref(false)
@ -62,7 +64,10 @@ const exportFile = async (exportType: ExportTypes) => {
{ {
responseType, responseType,
query: { query: {
fields: fields.value.map((field) => field.title),
offset, offset,
sortArrJson: JSON.stringify(sorts.value),
filterArrJson: JSON.stringify(nestedFilters.value),
}, },
} as any, } as any,
) )

3
packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue

@ -60,8 +60,7 @@ const sharedViewUrl = computed(() => {
viewType = 'view' viewType = 'view'
} }
// todo: get dashboard url return `${dashboardUrl?.value}#/nc/${viewType}/${shared.value.uuid}`
return `${dashboardUrl?.value}/nc/${viewType}/${shared.value.uuid}`
}) })
async function saveAllowCSVDownload() { async function saveAllowCSVDownload() {

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

@ -103,7 +103,7 @@ const deleteLink = async (id: string) => {
<a-table-column key="title" :title="$t('labels.viewLink')" data-index="title"> <a-table-column key="title" :title="$t('labels.viewLink')" data-index="title">
<template #default="{ record }"> <template #default="{ record }">
<nuxt-link :to="sharedViewUrl(record)" class="text-xs"> <nuxt-link :to="sharedViewUrl(record)" class="text-xs">
{{ `${dashboardUrl}/${sharedViewUrl(record)}` }} {{ `${dashboardUrl}#${sharedViewUrl(record)}` }}
</nuxt-link> </nuxt-link>
</template> </template>
</a-table-column> </a-table-column>

2
packages/nc-gui-v2/components/smartsheet/Cell.vue

@ -170,6 +170,6 @@ const syncAndNavigate = (dir: NavigateDir) => {
<CellText v-else-if="isString" v-model="vModel" /> <CellText v-else-if="isString" v-model="vModel" />
<CellJson v-else-if="isJSON" v-model="vModel" /> <CellJson v-else-if="isJSON" v-model="vModel" />
<CellText v-else v-model="vModel" /> <CellText v-else v-model="vModel" />
<div v-if="(isLocked || (isPublic && !isForm)) && !isAttachment" class="nc-locked-overlay" @click.stop.prevent /> <div v-if="(isLocked || (isPublic && readOnly && !isForm)) && !isAttachment" class="nc-locked-overlay" @click.stop.prevent />
</div> </div>
</template> </template>

11
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -49,6 +49,7 @@ const reloadViewDataHook = inject(ReloadViewDataHookInj, createEventHook())
const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook()) const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook())
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
const hasEditPermission = isUIAllowed('xcDatatableEditable')
// todo: get from parent ( inject or use prop ) // todo: get from parent ( inject or use prop )
const isView = false const isView = false
@ -65,7 +66,7 @@ const _contextMenu = ref(false)
const contextMenu = computed({ const contextMenu = computed({
get: () => _contextMenu.value, get: () => _contextMenu.value,
set: (val) => { set: (val) => {
if (!readOnly) { if (hasEditPermission) {
_contextMenu.value = val _contextMenu.value = val
} }
}, },
@ -103,7 +104,7 @@ provide(PaginationDataInj, paginationData)
provide(ChangePageInj, changePage) provide(ChangePageInj, changePage)
provide(ReadonlyInj, !isUIAllowed('xcDatatableEditable')) provide(ReadonlyInj, !hasEditPermission)
reloadViewDataHook?.on(async () => { reloadViewDataHook?.on(async () => {
await loadData() await loadData()
@ -171,7 +172,7 @@ const clearCell = async (ctx: { row: number; col: number }) => {
const { copy } = useClipboard() const { copy } = useClipboard()
const makeEditable = (row: Row, col: ColumnType) => { const makeEditable = (row: Row, col: ColumnType) => {
if (isPublicView.value || editEnabled || isView) { if (!hasEditPermission || editEnabled || isView) {
return return
} }
if (!isPkAvail.value && !row.rowMeta.new) { if (!isPkAvail.value && !row.rowMeta.new) {
@ -430,7 +431,7 @@ const onNavigate = (dir: NavigateDir) => {
:key="columnObj.id" :key="columnObj.id"
class="cell relative cursor-pointer nc-grid-cell" class="cell relative cursor-pointer nc-grid-cell"
:class="{ :class="{
active: !isPublicView && selected.col === colIndex && selected.row === rowIndex, active: isUIAllowed('xcDatatableEditable') && selected.col === colIndex && selected.row === rowIndex,
}" }"
:data-key="rowIndex + columnObj.id" :data-key="rowIndex + columnObj.id"
:data-col="columnObj.id" :data-col="columnObj.id"
@ -476,7 +477,7 @@ const onNavigate = (dir: NavigateDir) => {
TODO: add relationType !== 'bt' ? TODO: add relationType !== 'bt' ?
v1: <tr v-if="!isView && !isLocked && !isPublicView && isEditable && relationType !== 'bt'"> v1: <tr v-if="!isView && !isLocked && !isPublicView && isEditable && relationType !== 'bt'">
--> -->
<tr v-if="!isView && !isLocked && !isPublicView && isUIAllowed('xcDatatableEditable')"> <tr v-if="!isView && !isLocked && isUIAllowed('xcDatatableEditable')">
<td <td
v-t="['c:row:add:grid-bottom']" v-t="['c:row:add:grid-bottom']"
:colspan="visibleColLength + 1" :colspan="visibleColLength + 1"

2
packages/nc-gui-v2/components/tabs/auth/UserManagement.vue

@ -137,7 +137,7 @@ const resendInvite = async (user: User) => {
const copyInviteUrl = (user: User) => { const copyInviteUrl = (user: User) => {
if (!user.invite_token) return if (!user.invite_token) return
copy(`${dashboardUrl}/signup/${user.invite_token}`) copy(`${dashboardUrl}#/signup/${user.invite_token}`)
message.success('Invite url copied to clipboard') message.success('Invite url copied to clipboard')
} }

2
packages/nc-gui-v2/components/tabs/auth/user-management/ShareBase.vue

@ -26,7 +26,7 @@ const { project } = useProject()
const { copy } = useClipboard() const { copy } = useClipboard()
const url = $computed(() => (base && base.uuid ? `${dashboardUrl}/base/${base.uuid}` : null)) const url = $computed(() => (base && base.uuid ? `${dashboardUrl}#/base/${base.uuid}` : null))
const loadBase = async () => { const loadBase = async () => {
try { try {

2
packages/nc-gui-v2/components/tabs/auth/user-management/UsersModal.vue

@ -103,7 +103,7 @@ const saveUser = async () => {
} }
} }
const inviteUrl = $computed(() => (usersData.invitationToken ? `${dashboardUrl}/signup/${usersData.invitationToken}` : null)) const inviteUrl = $computed(() => (usersData.invitationToken ? `${dashboardUrl}#/signup/${usersData.invitationToken}` : null))
const copyUrl = async () => { const copyUrl = async () => {
if (!inviteUrl) return if (!inviteUrl) return

1
packages/nc-gui-v2/composables/useUIPermission/rolePermissions.ts

@ -1,4 +1,5 @@
const rolePermissions = { const rolePermissions = {
super: '*',
creator: '*', creator: '*',
owner: '*', owner: '*',
guest: {}, guest: {},

3
packages/nc-gui-v2/package-lock.json generated

@ -78,6 +78,7 @@
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.92.4", "version": "0.92.4",
"hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -104,6 +105,7 @@
"open-cli": "^6.0.1", "open-cli": "^6.0.1",
"prettier": "^2.1.1", "prettier": "^2.1.1",
"standard-version": "^9.0.0", "standard-version": "^9.0.0",
"swagger-typescript-api": "^10.0.1",
"ts-node": "^9.0.0", "ts-node": "^9.0.0",
"typedoc": "^0.22.17", "typedoc": "^0.22.17",
"typescript": "^4.0.2" "typescript": "^4.0.2"
@ -22961,6 +22963,7 @@
"open-cli": "^6.0.1", "open-cli": "^6.0.1",
"prettier": "^2.1.1", "prettier": "^2.1.1",
"standard-version": "^9.0.0", "standard-version": "^9.0.0",
"swagger-typescript-api": "^10.0.1",
"ts-node": "^9.0.0", "ts-node": "^9.0.0",
"typedoc": "^0.22.17", "typedoc": "^0.22.17",
"typescript": "^4.0.2" "typescript": "^4.0.2"

8
packages/nc-gui-v2/scripts/updateNuxtRouting.js

@ -11,10 +11,16 @@ const filePath = path.join(__dirname, '..', 'node_modules', 'nuxt', 'dist', 'pag
const content = fs.readFileSync(filePath, 'utf8') const content = fs.readFileSync(filePath, 'utf8')
/** Replace `createWebHistory` with `createWebHashHistory` */ /** Replace `createWebHistory` with `createWebHashHistory` */
const updatedContent = content.replace( const updatedContent = content
.replace(
/createRouter(\s*,\s*)createWebHistory(\s*,\s*)createMemoryHistory/, /createRouter(\s*,\s*)createWebHistory(\s*,\s*)createMemoryHistory/,
`createRouter$1createWebHashHistory as createWebHistory$2createMemoryHistory`, `createRouter$1createWebHashHistory as createWebHistory$2createMemoryHistory`,
) )
/** Replace initial Handle initial routing based on hash path */
.replace(
`const { pathname, search, hash } = location;`,
`const { pathname, search, hash } = new URL((location.hash || '').replace(/^#/, ''), location.origin);`,
)
/** Update file content with updated code */ /** Update file content with updated code */
fs.writeFileSync(filePath, updatedContent, 'utf8') fs.writeFileSync(filePath, updatedContent, 'utf8')

2
packages/nocodb-sdk/package.json

@ -9,7 +9,7 @@
"license": "MIT", "license": "MIT",
"keywords": [], "keywords": [],
"scripts": { "scripts": {
"preinstall": "npx npm-force-resolutions", "preinstall": "npm install --package-lock-only --ignore-scripts && npx npm-force-resolutions",
"build": "npm run generate:sdk && run-p build:*", "build": "npm run generate:sdk && run-p build:*",
"build:main": "tsc -p tsconfig.json", "build:main": "tsc -p tsconfig.json",
"build:module": "tsc -p tsconfig.module.json", "build:module": "tsc -p tsconfig.module.json",

23
packages/nocodb/src/lib/meta/api/dataApis/helpers.ts

@ -65,6 +65,7 @@ export async function extractXlsxData(view: View, req: Request) {
export async function extractCsvData(view: View, req: Request) { export async function extractCsvData(view: View, req: Request) {
const base = await Base.get(view.base_id); const base = await Base.get(view.base_id);
const fields = req.query.fields;
await view.getModelWithInfo(); await view.getModelWithInfo();
await view.getColumns(); await view.getColumns();
@ -87,7 +88,17 @@ export async function extractCsvData(view: View, req: Request) {
const data = papaparse.unparse( const data = papaparse.unparse(
{ {
fields: view.model.columns.map((c) => c.title), fields: view.model.columns
.sort((c1, c2) =>
Array.isArray(fields)
? fields.indexOf(c1.title as any) - fields.indexOf(c2.title as any)
: 0
)
.filter(
(c) =>
!fields || !Array.isArray(fields) || fields.includes(c.title as any)
)
.map((c) => c.title),
data: dbRows, data: dbRows,
}, },
{ {
@ -107,6 +118,14 @@ async function getDbRows(baseModel, view: View, req: Request) {
const startTime = process.hrtime(); const startTime = process.hrtime();
let elapsed, temp; let elapsed, temp;
const listArgs: any = { ...req.query };
try {
listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
} catch (e) {}
try {
listArgs.sortArr = JSON.parse(listArgs.sortArrJson);
} catch (e) {}
for ( for (
elapsed = 0; elapsed = 0;
elapsed < timeout; elapsed < timeout;
@ -121,7 +140,7 @@ async function getDbRows(baseModel, view: View, req: Request) {
model: view.model, model: view.model,
view, view,
}), }),
await baseModel.list({ ...req.query, offset, limit }), await baseModel.list({ ...listArgs, offset, limit }),
{}, {},
req.query req.query
); );

2
packages/nocodb/src/lib/meta/api/projectUserApis.ts

@ -285,7 +285,7 @@ async function sendInviteEmail(
html: ejs.render(template, { html: ejs.render(template, {
signupLink: `${req.ncSiteUrl}${ signupLink: `${req.ncSiteUrl}${
Noco.getConfig()?.dashboardPath Noco.getConfig()?.dashboardPath
}#/user/authentication/signup/${token}`, }#/signup/${token}`,
projectName: req.body?.projectName, projectName: req.body?.projectName,
roles: (req.body?.roles || '') roles: (req.body?.roles || '')
.split(',') .split(',')

2
packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts

@ -1497,7 +1497,7 @@ export default class RestAuthCtrl {
to: email, to: email,
subject: 'Verify email', subject: 'Verify email',
html: ejs.render(template, { html: ejs.render(template, {
signupLink: `${req.ncSiteUrl}${this.config?.dashboardPath}#/user/authentication/signup/${token}`, signupLink: `${req.ncSiteUrl}${this.config?.dashboardPath}#/signup/${token}`,
projectName: req.body?.projectName, projectName: req.body?.projectName,
roles: (req.body?.roles || '') roles: (req.body?.roles || '')
.split(',') .split(',')

Loading…
Cancel
Save