Browse Source

refactor: shared grid view api corrections

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/1668/head
Pranav C 3 years ago
parent
commit
ae2703e93d
  1. 7
      packages/nc-gui/components/project/appStore.vue
  2. 155
      packages/nc-gui/components/project/spreadsheet/public/xcTable.vue
  3. 27
      packages/nocodb-sdk/src/lib/Api.ts
  4. 5
      packages/nocodb/src/lib/noco/meta/api/dataApis/dataApis.ts
  5. 78
      packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataApis.ts
  6. 2
      packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataExportApis.ts
  7. 10
      packages/nocodb/src/lib/noco/meta/api/publicApis/publicMetaApis.ts
  8. 72
      scripts/sdk/swagger.json

7
packages/nc-gui/components/project/appStore.vue

@ -213,15 +213,8 @@ export default {
}, },
async created() { async created() {
await this.loadPluginList() await this.loadPluginList()
this.readPluginDefaults()
}, },
methods: { methods: {
async readPluginDefaults() {
try {
this.defaultConfig = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcPluginDemoDefaults'])
} catch (e) {
}
},
async confirmResetPlugin() { async confirmResetPlugin() {
try { try {
await this.$api.plugin.update(this.resetPluginRef.id, { await this.$api.plugin.update(this.resetPluginRef.id, {

155
packages/nc-gui/components/project/spreadsheet/public/xcTable.vue

@ -22,74 +22,7 @@
class="nc-table-toolbar elevation-0 xc-toolbar xc-border-bottom" class="nc-table-toolbar elevation-0 xc-toolbar xc-border-bottom"
style="z-index: 7;border-radius: 4px" style="z-index: 7;border-radius: 4px"
> >
<!--
<div class="d-flex xc-border align-center search-box" style="min-width:156px">
<v-menu bottom offset-y>
<template #activator="{on}">
<div style="min-width: 56px" v-on="on">
<v-icon
class="ml-2"
small
color="grey"
>
mdi-magnify
</v-icon>
<v-icon
color="grey"
class="pl-0 pa-1"
small
>
mdi-menu-down
</v-icon>
</div>
</template>
<v-list dense>
<v-list-item
v-for="col in meta.columns"
:key="col.title"
@click="searchField = col.title"
>
<span class="caption">{{ col.title }}</span>
</v-list-item>
</v-list>
</v-menu>
<v-divider
vertical
/>
<v-text-field
v-model="searchQuery"
autocomplete="off"
style="min-width: 100px ; width: 150px"
flat
dense
solo
hide-details
:placeholder="searchField ? `Search '${searchField}' column` : 'Search all columns'"
class="elevation-0 pa-0 flex-grow-1 caption search-field"
@keyup.enter="loadTableData"
@blur="loadTableData"
/>
</div>
<span
v-if="relationType && false"
class="caption grey&#45;&#45;text"
>{{ refTable }}({{
relationPrimaryValue
}}) -> {{ relationType === 'hm' ? ' Has Many ' : ' Belongs To ' }} -> {{ table }}</span>
-->
<div class="d-inline-flex"> <div class="d-inline-flex">
<!-- <v-btn outlined small text @click="reload">
<v-icon small class="mr-1" color="grey darken-3">
mdi-reload
</v-icon>
Reload
</v-btn>-->
<fields-menu <fields-menu
v-model="showFields" v-model="showFields"
:field-list="fieldList" :field-list="fieldList"
@ -123,32 +56,6 @@
/> />
</div> </div>
<v-spacer class="h-100" @dblclick="debug=true" /> <v-spacer class="h-100" @dblclick="debug=true" />
<!-- <v-menu>
<template #activator="{ on, attrs }">
<v-icon
v-bind="attrs"
small
class="mx-2"
color="grey darken-3"
v-on="on"
>
mdi-arrow-collapse-vertical
</v-icon>
</template>
<v-list dense class="caption">
<v-list-item v-for="h in cellHeights" :key="h.size" dense @click.stop="cellHeight = h.size">
<v-list-item-icon class="mr-1">
<v-icon small :color="cellHeight === h.size && 'primary'">
{{ h.icon }}
</v-icon>
</v-list-item-icon>
<v-list-item-title :class="{'primary&#45;&#45;text' : cellHeight === h.size}" style="text-transform: capitalize">
{{ h.size }}
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>-->
</v-toolbar> </v-toolbar>
<div <div
@ -185,9 +92,6 @@
color="primary lighten-2" color="primary lighten-2"
@input="loadTableData" @input="loadTableData"
/> />
<!-- <div v-else class="d-flex justify-center py-4">-->
<!-- <v-alert type="info" dense class="ma-1 flex-shrink-1">Table is empty</v-alert>-->
<!-- </div>-->
</div> </div>
</div> </div>
</template> </template>
@ -223,14 +127,12 @@
import { ErrorMessages } from 'nocodb-sdk' import { ErrorMessages } from 'nocodb-sdk'
import spreadsheet from '../mixins/spreadsheet' import spreadsheet from '../mixins/spreadsheet'
import ApiFactory from '../apis/apiFactory' import ApiFactory from '../apis/apiFactory'
// import EditableCell from "../editableCell";
import FieldsMenu from '../components/fieldsMenu' import FieldsMenu from '../components/fieldsMenu'
import SortListMenu from '../components/sortListMenu' import SortListMenu from '../components/sortListMenu'
import ColumnFilterMenu from '../components/columnFilterMenu' import ColumnFilterMenu from '../components/columnFilterMenu'
import XcGridView from '../views/xcGridView' import XcGridView from '../views/xcGridView'
import { SqlUI } from '@/helpers/sqlUi' import { SqlUI } from '@/helpers/sqlUi'
import CsvExportImport from '~/components/project/spreadsheet/components/moreActions' import CsvExportImport from '~/components/project/spreadsheet/components/moreActions'
// import ExpandedForm from "../expandedForm";
export default { export default {
name: 'XcTable', name: 'XcTable',
@ -369,23 +271,6 @@ export default {
edited() { edited() {
return this.data && this.data.some(r => r.rowMeta && (r.rowMeta.new || r.rowMeta.changed)) return this.data && this.data.some(r => r.rowMeta && (r.rowMeta.new || r.rowMeta.changed))
}, },
// hasMany() {
// return this.meta && this.meta.hasMany
// ? this.meta.hasMany.reduce((hm, o) => {
// hm[o.rcn] = hm[o.rcn] || []
// hm[o.rcn].push(o)
// return hm
// }, {})
// : {}
// },
// belongsTo() {
// return this.meta && this.meta.belongsTo
// ? this.meta.belongsTo.reduce((bt, o) => {
// bt[o.title] = o
// return bt
// }, {})
// : {}
// },
table() { table() {
if (this.relationType === 'hm') { if (this.relationType === 'hm') {
return this.relation.table_name return this.relation.table_name
@ -426,21 +311,6 @@ export default {
this.searchField = this.primaryValueColumn this.searchField = this.primaryValueColumn
}, },
created() { created() {
/* if (this.relationType === 'hm') {
this.filters.push({
field: this.relation.column_name,
op: 'is equal',
value: this.relationIdValue,
readOnly: true
})
} else if (this.relationType === 'bt') {
this.filters.push({
field: this.relation.rcn,
op: 'is equal',
value: this.relationIdValue,
readOnly: true
})
} */
document.addEventListener('keydown', this.onKeyDown) document.addEventListener('keydown', this.onKeyDown)
}, },
beforeDestroy() { beforeDestroy() {
@ -519,7 +389,9 @@ export default {
this.loading = true this.loading = true
try { try {
this.viewMeta = (await this.$api.public.sharedViewMetaGet(this.$route.params.id, { this.viewMeta = (await this.$api.public.sharedViewMetaGet(this.$route.params.id, {
password: this.password headers: {
'xc-password': this.password
}
})) }))
this.meta = this.viewMeta.model this.meta = this.viewMeta.model
this.metas = this.viewMeta.relatedMetas this.metas = this.viewMeta.relatedMetas
@ -547,26 +419,21 @@ export default {
list, list,
pageInfo: { totalRows: count } pageInfo: { totalRows: count }
} }
} = (await this.$api.public.dataList(this.$route.params.id, { } = (await this.$api.public.dataList(this.$route.params.id, {}, {
password: this.password, sortArrJson: JSON.stringify(this.sorts && this.sorts.map(({
sorts: this.sorts && this.sorts.map(({
fk_column_id, fk_column_id,
direction direction
}) => ({ }) => ({
direction, direction,
fk_column_id fk_column_id
})), }))),
filters: this.filters filterArrJson: JSON.stringify(this.filters),
}, this.queryParams ...this.queryParams
}, {
headers: { password: this.password }
}
)) ))
// this.client = client
// this.showFields = queryParams && queryParams.showFields
// this.meta = meta
// eslint-disable-next-line camelcase
// this.modelName = model_name
this.count = count this.count = count
this.data = list.map(row => ({ this.data = list.map(row => ({
row, row,

27
packages/nocodb-sdk/src/lib/Api.ts

@ -2843,16 +2843,10 @@ export class Api<
* @request POST:/api/v1/db/public/shared-view/{sharedViewUuid}/rows * @request POST:/api/v1/db/public/shared-view/{sharedViewUuid}/rows
* @response `200` `any` OK * @response `200` `any` OK
*/ */
sharedViewCreate: ( sharedViewCreate: (sharedViewUuid: string, params: RequestParams = {}) =>
sharedViewUuid: string,
data: { data?: any; password?: string },
params: RequestParams = {}
) =>
this.request<any, any>({ this.request<any, any>({
path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows`, path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows`,
method: 'POST', method: 'POST',
body: data,
type: ContentType.FormData,
format: 'json', format: 'json',
...params, ...params,
}), }),
@ -2941,7 +2935,6 @@ export class Api<
dataRelationList: ( dataRelationList: (
sharedViewUuid: string, sharedViewUuid: string,
columnName: string, columnName: string,
data: { password?: string },
query?: { limit?: string; offset?: string }, query?: { limit?: string; offset?: string },
params: RequestParams = {} params: RequestParams = {}
) => ) =>
@ -2949,8 +2942,6 @@ export class Api<
path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows/nested/${columnName}`, path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows/nested/${columnName}`,
method: 'POST', method: 'POST',
query: query, query: query,
body: data,
type: ContentType.Json,
format: 'json', format: 'json',
...params, ...params,
}), }),
@ -2960,19 +2951,13 @@ export class Api<
* *
* @tags Public * @tags Public
* @name SharedViewMetaGet * @name SharedViewMetaGet
* @request POST:/api/v1/db/public/shared-view/{sharedViewUuid}/meta * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/meta
* @response `200` `object` OK * @response `200` `object` OK
*/ */
sharedViewMetaGet: ( sharedViewMetaGet: (sharedViewUuid: string, params: RequestParams = {}) =>
sharedViewUuid: string,
data: { password?: string },
params: RequestParams = {}
) =>
this.request<object, any>({ this.request<object, any>({
path: `/api/v1/db/public/shared-view/${sharedViewUuid}/meta`, path: `/api/v1/db/public/shared-view/${sharedViewUuid}/meta`,
method: 'POST', method: 'GET',
body: data,
type: ContentType.Json,
format: 'json', format: 'json',
...params, ...params,
}), }),
@ -3066,7 +3051,7 @@ export class Api<
* *
* @tags Utils * @tags Utils
* @name CommentCount * @name CommentCount
* @request GET:/api/v1/db/meta/meta/audits/comments/count * @request GET:/api/v1/db/meta/audits/comments/count
* @response `201` `any` Created * @response `201` `any` Created
*/ */
commentCount: ( commentCount: (
@ -3074,7 +3059,7 @@ export class Api<
params: RequestParams = {} params: RequestParams = {}
) => ) =>
this.request<any, any>({ this.request<any, any>({
path: `/api/v1/db/meta/meta/audits/comments/count`, path: `/api/v1/db/meta/audits/comments/count`,
method: 'GET', method: 'GET',
query: query, query: query,
format: 'json', format: 'json',

5
packages/nocodb/src/lib/noco/meta/api/dataApis/dataApis.ts

@ -20,11 +20,6 @@ export async function dataList(req: Request, res: Response, next) {
res.json(await getDataList(model, view, req)); res.json(await getDataList(model, view, req));
} }
// async function dataListNew(req: Request, res: Response) {
// const { model, view } = await getViewAndModelFromRequest(req);
// res.json(await getDataList(model, view, req));
// }
export async function mmList(req: Request, res: Response, next) { export async function mmList(req: Request, res: Response, next) {
const view = await View.get(req.params.viewId); const view = await View.get(req.params.viewId);

78
packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataApis.ts

@ -18,12 +18,12 @@ import slash from 'slash';
export async function dataList(req: Request, res: Response) { export async function dataList(req: Request, res: Response) {
try { try {
const view = await View.getByUUID(req.params.publicDataUuid); const view = await View.getByUUID(req.params.sharedViewUuid);
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -39,37 +39,22 @@ export async function dataList(req: Request, res: Response) {
dbDriver: NcConnectionMgrv2.get(base) dbDriver: NcConnectionMgrv2.get(base)
}); });
const key = `${model.title}List`; const listArgs: any = { ...req.query };
const requestObj = { try {
[key]: await baseModel.defaultResolverReq(req.query) listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
}; } catch (e) {}
try {
const data = ( listArgs.sortArr = JSON.parse(listArgs.sortArrJson);
await nocoExecute( } catch (e) {}
requestObj,
{ const data = await nocoExecute(
[key]: async args => { await baseModel.defaultResolverReq(req.query),
return await baseModel.list(args); await baseModel.list(listArgs),
} {},
}, listArgs
{}, );
{
nested: {
[key]: {
...req.query,
sortArr: req.body?.sorts,
filterArr: req.body?.filters
}
}
}
)
)?.[key];
const count = await baseModel.count({ const count = await baseModel.count(listArgs);
...req.query,
filterArr: req.body?.filters
});
res.json({ res.json({
data: new PagedResponseImpl(data, { ...req.query, count }) data: new PagedResponseImpl(data, { ...req.query, count })
@ -85,12 +70,12 @@ async function dataInsert(
res: Response, res: Response,
next next
) { ) {
const view = await View.getByUUID(req.params.publicDataUuid); const view = await View.getByUUID(req.params.sharedViewUuid);
if (!view) return next(new Error('Not found')); if (!view) return next(new Error('Not found'));
if (view.type !== ViewTypes.FORM) return next(new Error('Not found')); if (view.type !== ViewTypes.FORM) return next(new Error('Not found'));
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
return res.status(403).json(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); return res.status(403).json(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -169,12 +154,12 @@ async function dataInsert(
} }
async function relDataList(req, res) { async function relDataList(req, res) {
const view = await View.getByUUID(req.params.publicDataUuid); const view = await View.getByUUID(req.params.sharedViewUuid);
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.FORM) NcError.notFound('Not found'); if (view.type !== ViewTypes.FORM) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -215,12 +200,12 @@ async function relDataList(req, res) {
} }
export async function publicMmList(req: Request, res: Response) { export async function publicMmList(req: Request, res: Response) {
const view = await View.getByUUID(req.params.publicDataUuid); const view = await View.getByUUID(req.params.sharedViewUuid);
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -271,12 +256,12 @@ export async function publicMmList(req: Request, res: Response) {
} }
export async function publicHmList(req: Request, res: Response) { export async function publicHmList(req: Request, res: Response) {
const view = await View.getByUUID(req.params.publicDataUuid); const view = await View.getByUUID(req.params.sharedViewUuid);
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -330,13 +315,16 @@ export async function publicHmList(req: Request, res: Response) {
} }
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });
router.post('/public/data/:publicDataUuid/list', catchError(dataList)); router.get(
'/api/v1/db/public/shared-view/:sharedViewUuid/rows',
catchError(dataList)
);
router.post( router.post(
'/public/data/:publicDataUuid/nested/:columnId', '/api/v1/db/public/shared-view/:sharedViewUuid/nested/:columnId',
catchError(relDataList) catchError(relDataList)
); );
router.post( router.post(
'/public/data/:publicDataUuid/create', '/api/v1/db/public/shared-view/:sharedViewUuid/create',
multer({ multer({
storage: multer.diskStorage({}) storage: multer.diskStorage({})
}).any(), }).any(),
@ -344,11 +332,11 @@ router.post(
); );
router.get( router.get(
'/public/data/:publicDataUuid/:rowId/mm/:colId', '/api/v1/db/public/shared-view/:sharedViewUuid/:rowId/mm/:colId',
catchError(publicMmList) catchError(publicMmList)
); );
router.get( router.get(
'/public/data/:publicDataUuid/:rowId/hm/:colId', '/api/v1/db/public/shared-view/:sharedViewUuid/:rowId/hm/:colId',
catchError(publicHmList) catchError(publicHmList)
); );

2
packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataExportApis.ts

@ -17,7 +17,7 @@ async function exportCsv(req: Request, res: Response) {
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }

10
packages/nocodb/src/lib/noco/meta/api/publicApis/publicMetaApis.ts

@ -12,11 +12,11 @@ export async function viewMetaGet(req: Request, res: Response) {
const view: View & { const view: View & {
relatedMetas?: { [ket: string]: Model }; relatedMetas?: { [ket: string]: Model };
client?: string; client?: string;
} = await View.getByUUID(req.params.sharedViewUuids); } = await View.getByUUID(req.params.sharedViewUuid);
if (!view) NcError.notFound('Not found'); if (!view) NcError.notFound('Not found');
if (view.password && view.password !== req.body?.password) { if (view.password && view.password !== req.headers?.['xc-password']) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
@ -78,13 +78,13 @@ async function publicSharedBaseGet(req, res): Promise<any> {
} }
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });
router.post( router.get(
'/api/v1/db/meta/public/shared-view/:sharedViewUuid/meta', '/api/v1/db/public/shared-view/:sharedViewUuid/meta',
catchError(viewMetaGet) catchError(viewMetaGet)
); );
router.get( router.get(
'/api/v1/db/meta/public/shared-base/:sharedBaseUuid/meta', '/api/v1/db/public/shared-base/:sharedBaseUuid/meta',
catchError(publicSharedBaseGet) catchError(publicSharedBaseGet)
); );
export default router; export default router;

72
scripts/sdk/swagger.json

@ -3395,6 +3395,14 @@
"name": "sharedViewUuid", "name": "sharedViewUuid",
"in": "path", "in": "path",
"required": true "required": true
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "xc-password",
"description": "Shared view password"
} }
], ],
"get": { "get": {
@ -3473,22 +3481,6 @@
"tags": [ "tags": [
"Public" "Public"
], ],
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"data": {},
"password": {
"type": "string"
}
}
}
}
},
"description": ""
},
"parameters": [ "parameters": [
{ {
"schema": { "schema": {
@ -3738,6 +3730,14 @@
"name": "columnName", "name": "columnName",
"in": "path", "in": "path",
"required": true "required": true
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "xc-password",
"description": "Shared view password"
} }
], ],
"post": { "post": {
@ -3769,20 +3769,6 @@
"name": "offset" "name": "offset"
} }
], ],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"password": {
"type": "string"
}
}
}
}
}
},
"tags": [ "tags": [
"Public" "Public"
], ],
@ -3798,9 +3784,17 @@
"name": "sharedViewUuid", "name": "sharedViewUuid",
"in": "path", "in": "path",
"required": true "required": true
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "xc-password",
"description": "Shared view password"
} }
], ],
"post": { "get": {
"summary": "", "summary": "",
"operationId": "public-shared-view-meta-get", "operationId": "public-shared-view-meta-get",
"responses": { "responses": {
@ -3823,21 +3817,7 @@
"Public" "Public"
], ],
"description": "", "description": "",
"parameters": [], "parameters": []
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"password": {
"type": "string"
}
}
}
}
}
}
} }
}, },
"/api/v1/db/public/shared-base/{sharedBaseUuid}/meta": { "/api/v1/db/public/shared-base/{sharedBaseUuid}/meta": {

Loading…
Cancel
Save