Browse Source

feat: add shared base option with editor role

re #518

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/764/head
Pranav C 3 years ago
parent
commit
1e1add1074
  1. 97
      packages/nc-gui/components/base/shareBase.vue
  2. 6
      packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue
  3. 1
      packages/nc-gui/layouts/shared.vue
  4. 9
      packages/nc-gui/pages/nc/base/_shared_base_id.vue
  5. 21
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

97
packages/nc-gui/components/base/shareBase.vue

@ -5,28 +5,47 @@
</v-icon> </v-icon>
<span class="grey--text caption">Shared base link</span> <span class="grey--text caption">Shared base link</span>
<div class="nc-container"> <div class="nc-container">
<v-menu> <v-chip v-if="base.enabled" :color="colors[4]" style="" class="rounded pl-1 pr-0 d-100 nc-url-chip pr-3">
<div class="nc-url-wrapper d-flex mx-1 align-center d-100">
<span class="nc-url flex-grow-1 caption ">{{ url }}</span>
<v-spacer />
<v-divider vertical />
<x-icon tooltip="reload" @click="recreate">
mdi-reload
</x-icon>
<x-icon tooltip="copy URL" @click="copyUrl">
mdi-content-copy
</x-icon>
<x-icon tooltip="open new tab" @click="navigateToSharedBase">
mdi-open-in-new
</x-icon>
<x-icon tooltip="copy embeddable HTML code" @click="generateEmbeddableIframe">
mdi-xml
</x-icon>
</div>
</v-chip>
<div class="d-flex align-center px-2">
<div>
<v-menu offset-x>
<template #activator="{on}"> <template #activator="{on}">
<div class="my-2" v-on="on"> <div class="my-2" v-on="on">
<template v-if="base.enabled"> <div class="font-weight-bold">
Anyone with following link can view base in a readonly mode <span v-if="base.enabled">Anyone with the link</span>
</template> <span v-else>Disabled shared base</span>
<template v-else>
Generate publicly shareable readonly base
</template>
<v-icon small> <v-icon small>
mdi-menu-down-outline mdi-menu-down-outline
</v-icon> </v-icon>
</div> </div>
</div>
</template> </template>
<v-list dense> <v-list dense>
<v-list-item dense @click="createSharedBase"> <v-list-item dense @click="createSharedBase('viewer')">
<v-list-item-title> <v-list-item-title>
<v-icon small class="mr-1"> <v-icon small class="mr-1">
mdi-link-variant mdi-link-variant
</v-icon> </v-icon>
<span class="caption">Readonly link</span> <span class="caption">Anyone with the link</span>
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item dense @click="disableSharedBase"> <v-list-item dense @click="disableSharedBase">
@ -39,25 +58,44 @@
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
<div class=" caption">
<template v-if="base.enabled">
<span v-if="base.roles === 'editor'">Anyone on the internet with this link can edit</span>
<span v-else-if="base.roles === 'viewer'">Anyone on the internet with this link can view</span>
</template>
<template v-else>
Generate publicly shareable readonly base
</template>
</div>
</div>
<v-spacer />
<div class="d-flex justify-center" style="width:120px">
<v-menu v-if="base.enabled" offset-y>
<template #activator="{on}">
<div class="text-capitalize my-2 font-weight-bold backgroundColorDefault py-2 px-4 rounded" v-on="on">
{{ base.roles || 'Viewer' }}
<v-chip v-if="base.enabled" :color="colors[4]"> <v-icon small>
<div class="nc-url-wrapper d-flex mx-1 align-center d-100"> mdi-menu-down-outline
<span class="nc-url flex-grow-1">{{ url }}</span> </v-icon>
<v-divider vertical /> </div>
<x-icon tooltip="reload" @click="recreate"> </template>
mdi-reload
</x-icon> <v-list dense>
<x-icon tooltip="copy URL" @click="copyUrl"> <v-list-item @click="createSharedBase('editor')">
mdi-content-copy <v-list-item-title>
</x-icon> Editor
<x-icon tooltip="open new tab" @click="navigateToSharedBase"> </v-list-item-title>
mdi-open-in-new </v-list-item>
</x-icon> <v-list-item @click="createSharedBase('viewer')">
<x-icon tooltip="copy embeddable HTML code" @click="generateEmbeddableIframe"> <v-list-item-title>
mdi-xml Viewer
</x-icon> </v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</div> </div>
</v-chip>
</div> </div>
</div> </div>
</template> </template>
@ -92,9 +130,9 @@ export default {
console.log(e) console.log(e)
} }
}, },
async createSharedBase() { async createSharedBase(roles = 'viewer') {
try { try {
const sharedBase = await this.$store.dispatch('sqlMgr/ActSqlOp', [{ dbAlias: 'db' }, 'createSharedBaseLink']) const sharedBase = await this.$store.dispatch('sqlMgr/ActSqlOp', [{ dbAlias: 'db' }, 'createSharedBaseLink', { roles }])
this.base = sharedBase || {} this.base = sharedBase || {}
} catch (e) { } catch (e) {
this.$toast.error(e.message).goAway(3000) this.$toast.error(e.message).goAway(3000)
@ -157,4 +195,5 @@ style="background: transparent; border: 1px solid #ddd"></iframe>`)
background: var(--v-backgroundColor-base); background: var(--v-backgroundColor-base);
padding: 20px 20px; padding: 20px 20px;
} }
/deep/ .nc-url-chip .v-chip__content{width: 100%}
</style> </style>

6
packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue

@ -871,6 +871,7 @@ export default {
const { row: rowObj, rowMeta } = this.data[row] const { row: rowObj, rowMeta } = this.data[row]
if (rowMeta.new) { if (rowMeta.new) {
try { try {
this.$set(this.data[row], 'saving', true)
const pks = this.meta.columns.filter((col) => { const pks = this.meta.columns.filter((col) => {
return col.pk return col.pk
}) })
@ -910,6 +911,8 @@ export default {
this.$toast.error(`Failed to save row : ${e.message}`).goAway(3000) this.$toast.error(`Failed to save row : ${e.message}`).goAway(3000)
} }
} }
this.$set(this.data[row], 'saving', false)
} }
} }
}, },
@ -943,6 +946,7 @@ export default {
if (!id) { if (!id) {
return this.$toast.info('Update not allowed for table which doesn\'t have primary Key').goAway(3000) return this.$toast.info('Update not allowed for table which doesn\'t have primary Key').goAway(3000)
} }
this.$set(this.data[row], 'saving', true)
const newData = await this.api.update(id, { const newData = await this.api.update(id, {
[column._cn]: rowObj[column._cn] [column._cn]: rowObj[column._cn]
@ -961,6 +965,8 @@ export default {
this.$toast.error(`Failed to update row : ${e.message}`).goAway(3000) this.$toast.error(`Failed to update row : ${e.message}`).goAway(3000)
} }
} }
this.$set(this.data[row], 'saving', false)
} }
}, },
async deleteRow() { async deleteRow() {

1
packages/nc-gui/layouts/shared.vue

@ -1,7 +1,6 @@
<template> <template>
<v-app> <v-app>
<v-main> <v-main>
<v-app-bar v-show="false" dark />
<div> <div>
<nuxt /> <nuxt />
</div> </div>

9
packages/nc-gui/pages/nc/base/_shared_base_id.vue

@ -27,11 +27,12 @@
</pane> </pane>
</splitpanes> </splitpanes>
<div class="nc-embedded-options d-flex align-center px-3"> <div class="nc-embedded-options d-flex align-center px-3">
<a href="https://github.com/nocodb/nocodb" target="_blank" class="text-decoration-none d-inline-flex align-center textColor--text">
<img src="favicon-32.png" height="15" class="mr-2">
<span class="body-1 font-weight-bold">NocoDB</span></a>
<v-spacer /> <v-spacer />
<span v-if="embed" class="caption pointer" @click="showLargerVersion"><v-icon small>mdi-arrow-expand</v-icon> View larger version</span> <a href="https://github.com/nocodb/nocodb" target="_blank" class=" d-inline-flex align-center caption">
<img src="favicon-32.png" height="15" class="mr-2">
<span>Built with </span> &nbsp;
<span class=""><span class="font-weight-bold"> NocoDB</span> </span></a>
<span v-if="embed" class="caption pointer ml-4" @click="showLargerVersion"><v-icon small>mdi-arrow-expand</v-icon> Expand</span>
</div> </div>
</div> </div>
</template> </template>

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

@ -3447,12 +3447,18 @@ export default class NcMetaMgr {
} }
); );
let roles = args?.args?.roles;
if (!roles || (roles !== 'editor' && roles !== 'viewer')) {
roles = 'viewer';
}
if (!sharedBase) { if (!sharedBase) {
const insertData = { const insertData = {
project_id: args.project_id, project_id: args.project_id,
db_alias: this.getDbAlias(args), db_alias: this.getDbAlias(args),
shared_base_id: uuidv4(), shared_base_id: uuidv4(),
password: args?.args?.password password: args?.args?.password,
roles
}; };
await this.xcMeta.metaInsert( await this.xcMeta.metaInsert(
@ -3466,8 +3472,19 @@ export default class NcMetaMgr {
this.getDbAlias(args), this.getDbAlias(args),
'nc_shared_bases', 'nc_shared_bases',
{}, {},
['id', 'shared_base_id', 'enabled'] ['id', 'shared_base_id', 'enabled', 'roles']
);
} else {
await this.xcMeta.metaUpdate(
this.getProjectId(args),
this.getDbAlias(args),
'nc_shared_bases',
{ roles },
{
project_id: this.getProjectId(args)
}
); );
sharedBase.roles = roles;
} }
sharedBase.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/base/${sharedBase.shared_base_id}`; sharedBase.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/base/${sharedBase.shared_base_id}`;

Loading…
Cancel
Save