Browse Source

feat: add shared view type and show url accordingly

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/636/head
Pranav C 3 years ago
parent
commit
a39e9cbc37
  1. 4
      packages/nc-gui/components/project/spreadsheet/components/sharedViewsList.vue
  2. 7
      packages/nc-gui/components/project/spreadsheet/public/xcForm.vue
  3. 7
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts
  4. 7
      packages/nocodb/src/lib/noco/common/XcMigrationSource.ts
  5. 4
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
  6. 343
      packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts
  7. 38
      packages/nocodb/src/lib/noco/migrations/nc_004_add_view_type_column.ts

4
packages/nc-gui/components/project/spreadsheet/components/sharedViewsList.vue

@ -18,8 +18,8 @@
<tbody>
<tr v-for="link of viewsList" :key="link.id">
<td class="caption">
<nuxt-link :to="`/nc/view/${link.view_id}`">
{{ `${origin}/dashboard#/xc/view/${link.view_id}` }}
<nuxt-link :to="`/nc/${link.view_type || 'view'}/${link.view_id}`">
{{ `${origin}/dashboard#/xc/${link.view_type || 'view'}/${link.view_id}` }}
</nuxt-link>
</td>
<td class="caption">

7
packages/nc-gui/components/project/spreadsheet/public/xcForm.vue

@ -30,20 +30,21 @@
<div class="mt-10 d-flex align-center justify-center flex-column">
<div class="nc-form-banner backgroundColor darken-1 flex-column justify-center d-flex">
<div class="d-flex align-center justify-center flex-grow-1">
<!-- <v-chip small color="backgroundColorDefault caption grey--text">
<!-- <v-chip small color="backgroundColorDefault caption grey--text">
Add cover image
</v-chip>-->
<v-img src="./icon.png" width="50" class="mx-4" /> <span class="display-1 font-weight-bold">NocoDB</span>
</div>
</div>
</div>
<div class="mx-auto nc-form elevation-3 pa-2 mb-10">
<div class="nc-form-logo py-8">
<div class="nc-form-logo py-8" style="display: none">
<!-- <div v-ripple class="nc-form-add-logo text-center caption pointer" @click.stop>-->
<!-- Add a logo-->
<!-- </div>-->
</div>
<h2
class="display-1 font-weight-bold text-left mx-4 mb-3 px-1 text--text text--lighten-1"
class="mt-4 display-1 font-weight-bold text-left mx-4 mb-3 px-1 text--text text--lighten-1"
>
{{ localParams.name }}
</h2>

7
packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts

@ -1681,7 +1681,7 @@ class BaseModelSql extends BaseModel {
response = data;
}
} else if (ai) {
rowId = Array.isArray(response)
rowId = Array.isArray(response)
? response?.[0]?.[ai._cn]
: response?.[ai._cn];
// response = await this.nestedRead(
@ -1697,12 +1697,11 @@ class BaseModelSql extends BaseModel {
response = response[0];
}
rowId = this._extractPksValues(response);
if (response) rowId = this._extractPksValues(response);
await Promise.all(postInsertOps.map(f => f()));
if(rowId){
if (rowId) {
response = await this.nestedRead(
rowId,
this.defaultNestedBtQueryParams,

7
packages/nocodb/src/lib/noco/common/XcMigrationSource.ts

@ -1,15 +1,16 @@
import * as project from '../migrations/nc_001_init';
import * as m2m from '../migrations/nc_002_add_m2m';
import * as fkn from '../migrations/nc_003_add_fkn_column';
import * as viewType from '../migrations/nc_004_add_view_type_column';
// Create a custom migration source class
export default class XcMigrationSource{
export default class XcMigrationSource {
// Must return a Promise containing a list of migrations.
// Migrations can be whatever you want, they will be passed as
// arguments to getMigrationName and getMigration
public getMigrations(): Promise<any> {
// In this example we are just returning migration names
return Promise.resolve(['project','m2m', 'fkn'])
return Promise.resolve(['project', 'm2m', 'fkn', 'viewType']);
}
public getMigrationName(migration): string {
@ -24,6 +25,8 @@ export default class XcMigrationSource{
return m2m;
case 'fkn':
return fkn;
case 'viewType':
return viewType;
}
}
}

4
packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

@ -3380,7 +3380,7 @@ export default class NcMetaMgr {
condition: {
model_name: args.args.model_name
},
fields: ['id', 'view_id', 'password', 'model_name']
fields: ['id', 'view_id', 'password', 'model_name', 'view_type']
}
);
}
@ -3474,7 +3474,7 @@ export default class NcMetaMgr {
limit: args.args.limit,
offset: args.args.offset
}),
count: await model?.countByPk({})
count: (await model?.countByPk({}))?.count
};
} catch (e) {
console.log(e);

343
packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts

@ -1,10 +1,9 @@
import {Tele} from 'nc-help';
import {v4 as uuidv4} from 'uuid';
import { Tele } from 'nc-help';
import { v4 as uuidv4 } from 'uuid';
import NcMetaMgr from "./NcMetaMgr";
import NcMetaMgr from './NcMetaMgr';
export default class NcMetaMgrEE extends NcMetaMgr {
/* protected async handlePublicRequest(req, res, next) {
const args = req.body;
// let result;
@ -63,68 +62,77 @@ export default class NcMetaMgrEE extends NcMetaMgr {
}
}*/
protected async xcTableList(req, args): Promise<any> {
const roles = req.session?.passport?.user?.roles;
let tables = (await this.xcVisibilityMetaGet({...args, args: {type: 'table', ...args.args}}));
let tables = await this.xcVisibilityMetaGet({
...args,
args: { type: 'table', ...args.args }
});
tables = tables.filter((table: any) => {
return Object.keys(roles).some(role => roles[role] && !table.disabled[role])
return Object.keys(roles).some(
role => roles[role] && !table.disabled[role]
);
});
return {data: {list: tables}};
return { data: { list: tables } };
}
// NOTE: updated
protected async xcAclSave(args, req): Promise<any> {
try {
const dbAlias = await this.getDbAlias(args);
const projectId = await this.getProjectId(args);
const res = await this.xcMeta.metaUpdate(projectId, dbAlias, 'nc_acl', {
acl: JSON.stringify(args.args.acl)
}, {
tn: args.args.tn || args.args.name
});
const res = await this.xcMeta.metaUpdate(
projectId,
dbAlias,
'nc_acl',
{
acl: JSON.stringify(args.args.acl)
},
{
tn: args.args.tn || args.args.name
}
);
this.app.ncMeta.audit(projectId, dbAlias, 'nc_audit', {
op_type: 'TABLE_ACL',
op_sub_type: 'UPDATED',
user: req.user.email,
description: `updated table ${args.args.tn || args.args.name} acl `, ip: req.clientIp
description: `updated table ${args.args.tn || args.args.name} acl `,
ip: req.clientIp
});
Tele.emit('evt', {evt_type: 'acl:updated'})
Tele.emit('evt', { evt_type: 'acl:updated' });
return res;
} catch (e) {
throw(e);
throw e;
}
}
protected async getSharedViewData(req, args: any): Promise<any> {
try {
console.log(args)
const viewMeta = await this.xcMeta.knex('nc_shared_views').where({
view_id: args.args.view_id
}).first();
if (viewMeta && viewMeta.password && viewMeta.password !== args.args.password) {
throw new Error('Invalid password')
console.log(args);
const viewMeta = await this.xcMeta
.knex('nc_shared_views')
.where({
view_id: args.args.view_id
})
.first();
if (
viewMeta &&
viewMeta.password &&
viewMeta.password !== args.args.password
) {
throw new Error('Invalid password');
}
const apiBuilder = this.app
?.projectBuilders
const apiBuilder = this.app?.projectBuilders
?.find(pb => pb.id === viewMeta.project_id)
?.apiBuilders
?.find(ab => ab.dbAlias === viewMeta.db_alias);
?.apiBuilders?.find(ab => ab.dbAlias === viewMeta.db_alias);
const model = apiBuilder?.xcModels?.[viewMeta.model_name];
if (model) {
@ -149,20 +157,17 @@ export default class NcMetaMgrEE extends NcMetaMgr {
where,
fields
}),
...await model.countByPk({
...(await model.countByPk({
...req.query,
where,
fields
}),
})),
client: apiBuilder?.client
}
};
}
} catch (e) {
throw e;
}
}
protected async createSharedViewLink(req, args: any): Promise<any> {
@ -170,10 +175,11 @@ export default class NcMetaMgrEE extends NcMetaMgr {
// todo: keep belongs to column if belongs to virtual column present
if (args.args.query_params?.fields && args.args.show_as !== 'form') {
const fields = args.args.query_params?.fields.split(',');
args.args.meta.columns = args.args.meta.columns.filter(c => fields.includes(c._cn))
args.args.meta.columns = args.args.meta.columns.filter(c =>
fields.includes(c._cn)
);
}
const insertData = {
project_id: args.project_id,
db_alias: this.getDbAlias(args),
@ -181,11 +187,23 @@ export default class NcMetaMgrEE extends NcMetaMgr {
meta: JSON.stringify(args.args.meta),
query_params: JSON.stringify(args.args.query_params),
view_id: uuidv4(),
password: args.args.password
}
await this.xcMeta.metaInsert(args.project_id, this.getDbAlias(args), 'nc_shared_views', insertData);
const res = await this.xcMeta.metaGet(this.getProjectId(args), this.getDbAlias(args), 'nc_shared_views', insertData, ['id', 'view_id']);
password: args.args.password,
view_type: args.args.show_as
};
await this.xcMeta.metaInsert(
args.project_id,
this.getDbAlias(args),
'nc_shared_views',
insertData
);
const res = await this.xcMeta.metaGet(
this.getProjectId(args),
this.getDbAlias(args),
'nc_shared_views',
insertData,
['id', 'view_id']
);
if (args.args.show_as === 'form') {
res.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/form/${res.view_id}`;
} else if (args.args.show_as === 'gallery') {
@ -193,28 +211,31 @@ export default class NcMetaMgrEE extends NcMetaMgr {
} else {
res.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/view/${res.view_id}`;
}
Tele.emit('evt', {evt_type: 'sharedView:generated-link'})
Tele.emit('evt', { evt_type: 'sharedView:generated-link' });
return res;
} catch (e) {
console.log(e)
console.log(e);
}
}
protected async updateSharedViewLinkPassword(args: any): Promise<any> {
try {
await this.xcMeta.metaUpdate(this.getProjectId(args), this.getDbAlias(args), 'nc_shared_views', {
password: args.args?.password
}, args.args.id);
Tele.emit('evt', {evt_type: 'sharedView:password-updated'})
return {msg: 'Success'};
await this.xcMeta.metaUpdate(
this.getProjectId(args),
this.getDbAlias(args),
'nc_shared_views',
{
password: args.args?.password
},
args.args.id
);
Tele.emit('evt', { evt_type: 'sharedView:password-updated' });
return { msg: 'Success' };
} catch (e) {
console.log(e)
console.log(e);
}
}
protected async xcVisibilityMetaSet(args) {
try {
let field = '';
@ -245,148 +266,201 @@ export default class NcMetaMgrEE extends NcMetaMgr {
cn: d.cn,
rcn: d.rcn,
relation_type: d.relationType
})
});
}
for (const role of Object.keys(d.disabled)) {
const dataInDb = await this.xcMeta.metaGet(this.getProjectId(args), this.getDbAlias(args), 'nc_disabled_models_for_role', {
type: args.args.type,
title: d[field],
role,
...props
});
const dataInDb = await this.xcMeta.metaGet(
this.getProjectId(args),
this.getDbAlias(args),
'nc_disabled_models_for_role',
{
type: args.args.type,
title: d[field],
role,
...props
}
);
if (dataInDb) {
if (d.disabled[role]) {
if (!dataInDb.disabled) {
await this.xcMeta.metaUpdate(this.getProjectId(args), this.getDbAlias(args), 'nc_disabled_models_for_role', {
disabled: d.disabled[role]
}, {
type: args.args.type,
title: d[field],
role, ...props
})
await this.xcMeta.metaUpdate(
this.getProjectId(args),
this.getDbAlias(args),
'nc_disabled_models_for_role',
{
disabled: d.disabled[role]
},
{
type: args.args.type,
title: d[field],
role,
...props
}
);
}
} else {
await this.xcMeta.metaDelete(this.getProjectId(args), this.getDbAlias(args), 'nc_disabled_models_for_role', {
type: args.args.type,
title: d[field],
role, ...props
})
await this.xcMeta.metaDelete(
this.getProjectId(args),
this.getDbAlias(args),
'nc_disabled_models_for_role',
{
type: args.args.type,
title: d[field],
role,
...props
}
);
}
} else if (d.disabled[role]) {
await this.xcMeta.metaInsert(this.getProjectId(args), this.getDbAlias(args), 'nc_disabled_models_for_role', {
disabled: d.disabled[role],
type: args.args.type,
title: d[field],
role, ...props
})
await this.xcMeta.metaInsert(
this.getProjectId(args),
this.getDbAlias(args),
'nc_disabled_models_for_role',
{
disabled: d.disabled[role],
type: args.args.type,
title: d[field],
role,
...props
}
);
}
}
}
} catch (e) {
throw e;
}
}
protected async xcAuditList(args): Promise<any> {
return this.xcMeta.metaPaginatedList(this.getProjectId(args), null, 'nc_audit', {
limit: args.args.limit,
offset: args.args.offset,
sort: {
field: 'created_at',
desc: true
return this.xcMeta.metaPaginatedList(
this.getProjectId(args),
null,
'nc_audit',
{
limit: args.args.limit,
offset: args.args.offset,
sort: {
field: 'created_at',
desc: true
}
}
});
);
}
protected async xcTableModelsEnable(args): Promise<any> {
const dbAlias = this.getDbAlias(args);
await this.xcMeta.metaUpdate(args.project_id, dbAlias, 'nc_models', {
enabled: true
}, null, {
'title': {
in: args.args
await this.xcMeta.metaUpdate(
args.project_id,
dbAlias,
'nc_models',
{
enabled: true
},
type: {
eq: 'table'
null,
{
title: {
in: args.args
},
type: {
eq: 'table'
}
}
});
await this.xcMeta.metaUpdate(args.project_id, dbAlias, 'nc_models', {
enabled: false
}, null, {
'title': {
nin: args.args,
);
await this.xcMeta.metaUpdate(
args.project_id,
dbAlias,
'nc_models',
{
enabled: false
},
type: {
eq: 'table'
null,
{
title: {
nin: args.args
},
type: {
eq: 'table'
}
}
});
);
}
// NOTE: updated
protected async xcRelationsSet(args): Promise<any> {
// const client = await this.projectGetSqlClient(args);
const dbAlias = await this.getDbAlias(args);
// filter out model names which toggled
const metaTableNames = [...new Set(args.args.map(rel => {
return rel.relationType === 'hm' ? rel.rtn : rel.tn
}))]
const metaTableNames = [
...new Set(
args.args.map(rel => {
return rel.relationType === 'hm' ? rel.rtn : rel.tn;
})
)
];
// get current meta from db
// const metas = await client.knex('nc_models').select('meta', 'id', 'title').whereIn('title', metaTableNames);
const metas = await this.xcMeta.metaList(args.project_id, dbAlias, 'nc_models', {
xcCondition: {
'title': {
in: metaTableNames
const metas = await this.xcMeta.metaList(
args.project_id,
dbAlias,
'nc_models',
{
xcCondition: {
title: {
in: metaTableNames
}
}
}
});
);
const metaMap: {
[key: string]: any
[key: string]: any;
} = {};
for (const {meta, id, title} of metas) {
for (const { meta, id, title } of metas) {
metaMap[title] = {
id,
meta: JSON.parse(meta)
}
};
}
// todo: handle if there is multiple relations between same tables(by comparing column names)
for (const rel of args.args) {
if (rel.relationType === 'hm') {
const relation = metaMap[rel.rtn].meta.hasMany.find(hmRel => hmRel.tn === rel.tn);
const relation = metaMap[rel.rtn].meta.hasMany.find(
hmRel => hmRel.tn === rel.tn
);
relation.enabled = rel.enabled;
} else {
const relation = metaMap[rel.tn].meta.belongsTo.find(btRel => btRel.rtn === rel.rtn);
const relation = metaMap[rel.tn].meta.belongsTo.find(
btRel => btRel.rtn === rel.rtn
);
relation.enabled = rel.enabled;
}
}
try {
await this.xcMeta.startTransaction();
for (const {id, meta} of Object.values(metaMap)) {
await this.xcMeta.metaUpdate(args.project_id, dbAlias, 'nc_models', {
meta: JSON.stringify(meta)
}, id)
for (const { id, meta } of Object.values(metaMap)) {
await this.xcMeta.metaUpdate(
args.project_id,
dbAlias,
'nc_models',
{
meta: JSON.stringify(meta)
},
id
);
}
await this.xcMeta.commit();
} catch (e) {
this.xcMeta.rollback(e)
this.xcMeta.rollback(e);
throw e;
}
}
}
@ -412,4 +486,3 @@ export default class NcMetaMgrEE extends NcMetaMgr {
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

38
packages/nocodb/src/lib/noco/migrations/nc_004_add_view_type_column.ts

@ -0,0 +1,38 @@
import Knex from 'knex';
const up = async (knex: Knex) => {
await knex.schema.alterTable('nc_shared_views', table => {
table.string('view_type');
});
};
const down = async knex => {
await knex.schema.alterTable('nc_shared_views', table => {
table.dropColumns('view_type');
});
};
export { up, down };
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
Loading…
Cancel
Save