mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
932 lines
30 KiB
932 lines
30 KiB
<template> |
|
<v-navigation-drawer |
|
permanent |
|
class="views-navigation-drawer" |
|
:style="{ |
|
maxWidth: toggleDrawer ? '0' : '220px', |
|
minWidth: toggleDrawer ? '0' : '220px', |
|
}" |
|
> |
|
<v-container fluid class="h-100 py-0"> |
|
<div class="d-flex flex-column h-100"> |
|
<div class="flex-grow-1" style="overflow: auto; min-height: 350px"> |
|
<v-list v-if="views && views.length" dense> |
|
<v-list-item dense> |
|
<!-- Views --> |
|
<span class="body-2 font-weight-medium">{{ $t('objects.views') }}</span> |
|
</v-list-item> |
|
<v-list-item-group v-model="selectedViewIdLocal" mandatory color="primary"> |
|
<draggable |
|
:is="_isUIAllowed('viewlist-drag-n-drop') ? 'draggable' : 'div'" |
|
v-model="viewsList" |
|
draggable="div" |
|
v-bind="dragOptions" |
|
@change="onMove($event)" |
|
> |
|
<transition-group type="transition" :name="!drag ? 'flip-list' : null"> |
|
<v-list-item |
|
v-for="(view, i) in viewsList" |
|
:key="view.id" |
|
v-t="['a:view:open', { view: view.type }]" |
|
dense |
|
:value="view.id" |
|
active-class="x-active--text" |
|
:class="`body-2 view nc-view-item nc-draggable-child nc-${viewTypeAlias[view.type]}-view-item`" |
|
@click="$emit('rerender')" |
|
> |
|
<v-icon |
|
v-if="_isUIAllowed('viewlist-drag-n-drop')" |
|
small |
|
:class="`nc-child-draggable-icon nc-child-draggable-icon-${view.title}`" |
|
@click.stop |
|
> |
|
mdi-drag-vertical |
|
</v-icon> |
|
<v-list-item-icon class="mr-n1"> |
|
<v-icon v-if="viewIcons[view.type]" x-small :color="viewIcons[view.type].color"> |
|
{{ viewIcons[view.type].icon }} |
|
</v-icon> |
|
<v-icon v-else color="primary" small> mdi-table </v-icon> |
|
</v-list-item-icon> |
|
<v-list-item-title> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<div class="font-weight-regular" style="overflow: hidden; text-overflow: ellipsis"> |
|
<input |
|
v-if="view.edit" |
|
:ref="`input${i}`" |
|
v-model="view.title_temp" |
|
@click.stop |
|
@keydown.enter.stop="updateViewName(view, i)" |
|
@blur="updateViewName(view, i)" |
|
/> |
|
<template v-else> |
|
<span v-on="on">{{ view.alias || view.title }}</span> |
|
</template> |
|
</div> |
|
</template> |
|
{{ view.alias || view.title }} |
|
</v-tooltip> |
|
</v-list-item-title> |
|
<v-spacer /> |
|
<template v-if="_isUIAllowed('virtualViewsCreateOrEdit')"> |
|
<!-- Copy view --> |
|
<x-icon |
|
v-if="!view.edit" |
|
:tooltip="$t('activity.copyView')" |
|
x-small |
|
color="primary" |
|
icon-class="view-icon nc-view-copy-icon" |
|
@click.stop="copyView(view, i)" |
|
> |
|
mdi-content-copy |
|
</x-icon> |
|
<!-- Rename view --> |
|
<x-icon |
|
v-if="!view.edit" |
|
:tooltip="$t('activity.renameView')" |
|
x-small |
|
color="primary" |
|
icon-class="view-icon nc-view-edit-icon" |
|
@click.stop="showRenameTextBox(view, i)" |
|
> |
|
mdi-pencil |
|
</x-icon> |
|
<!-- Delete view" --> |
|
<x-icon |
|
v-if="!view.is_default" |
|
:tooltip="$t('activity.deleteView')" |
|
small |
|
color="error" |
|
icon-class="view-icon nc-view-delete-icon" |
|
@click.stop="deleteView(view)" |
|
> |
|
mdi-delete-outline |
|
</x-icon> |
|
</template> |
|
<v-icon v-if="view.id === selectedViewId" small class="check-icon"> mdi-check-bold </v-icon> |
|
</v-list-item> |
|
</transition-group> |
|
</draggable> |
|
</v-list-item-group> |
|
</v-list> |
|
<template v-if="hideViews && _isUIAllowed('virtualViewsCreateOrEdit')"> |
|
<v-divider class="advance-menu-divider" /> |
|
|
|
<v-list |
|
dense |
|
:class="{ |
|
'advanced-border': overShieldIcon, |
|
}" |
|
> |
|
<v-list-item dense> |
|
<!-- Create a View --> |
|
<span class="body-2 font-weight-medium" @dblclick="enableDummyFeat = true"> |
|
{{ $t('activity.createView') }} |
|
</span> |
|
<v-tooltip top> |
|
<template #activator="{ on }"> |
|
<x-icon |
|
color="pink textColor" |
|
icon-class="ml-2" |
|
small |
|
v-on="on" |
|
@mouseenter="overShieldIcon = true" |
|
@mouseleave="overShieldIcon = false" |
|
> |
|
mdi-shield-lock-outline |
|
</x-icon> |
|
</template> |
|
<!-- Only visible to Creator --> |
|
<span class="caption"> |
|
{{ $t('msg.info.onlyCreator') }} |
|
</span> |
|
</v-tooltip> |
|
</v-list-item> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-list-item |
|
dense |
|
class="body-2 nc-create-grid-view" |
|
v-on="on" |
|
@click="openCreateViewDlg(viewTypes.GRID)" |
|
> |
|
<v-list-item-icon class="mr-n1"> |
|
<v-icon color="blue" x-small> mdi-grid-large </v-icon> |
|
</v-list-item-icon> |
|
<v-list-item-title> |
|
<span class="font-weight-regular"> |
|
<!-- Grid --> |
|
{{ $t('objects.viewType.grid') }} |
|
</span> |
|
</v-list-item-title> |
|
<v-spacer /> |
|
<v-icon class="mr-1" small> mdi-plus </v-icon> |
|
</v-list-item> |
|
</template> |
|
<!-- Add Grid View --> |
|
{{ $t('msg.info.addView.grid') }} |
|
</v-tooltip> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-list-item |
|
dense |
|
class="body-2 nc-create-gallery-view" |
|
v-on="on" |
|
@click="openCreateViewDlg(viewTypes.GALLERY)" |
|
> |
|
<v-list-item-icon class="mr-n1"> |
|
<v-icon color="orange" x-small> mdi-camera-image </v-icon> |
|
</v-list-item-icon> |
|
<v-list-item-title> |
|
<span class="font-weight-regular"> |
|
<!-- Gallery --> |
|
{{ $t('objects.viewType.gallery') }} |
|
</span> |
|
</v-list-item-title> |
|
|
|
<v-spacer /> |
|
<v-icon class="mr-1" small> mdi-plus </v-icon> |
|
</v-list-item> |
|
</template> |
|
<!-- Add Gallery View --> |
|
{{ $t('msg.info.addView.gallery') }} |
|
</v-tooltip> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-list-item |
|
v-if="!isView" |
|
dense |
|
class="body-2 nc-create-form-view" |
|
v-on="on" |
|
@click="openCreateViewDlg(viewTypes.FORM)" |
|
> |
|
<v-list-item-icon class="mr-n1"> |
|
<v-icon x-small :color="viewIcons[viewTypes.FORM].color" class="mt-n1"> mdi-form-select </v-icon> |
|
</v-list-item-icon> |
|
<v-list-item-title> |
|
<span class="font-weight-regular"> |
|
<!-- Form --> |
|
|
|
{{ $t('objects.viewType.form') }} |
|
</span> |
|
</v-list-item-title> |
|
|
|
<v-spacer /> |
|
<v-icon class="mr-1" small> mdi-plus </v-icon> |
|
</v-list-item> |
|
</template> |
|
<!-- Add Form View --> |
|
{{ $t('msg.info.addView.form') }} |
|
</v-tooltip> |
|
</v-list> |
|
</template> |
|
</div> |
|
|
|
<div v-if="!isSharedBase"> |
|
<v-btn v-t="['c:snippet:open']" color="primary" class="caption d-100" @click="codeSnippetModal = true"> |
|
<v-icon small class="mr-2"> mdi-xml </v-icon> Get API Snippet |
|
</v-btn> |
|
<code-snippet v-model="codeSnippetModal" :query-params="queryParams" :meta="meta" :view="selectedView" /> |
|
</div> |
|
<div v-if="_isUIAllowed('webhook')" class="mb-2"> |
|
<v-btn |
|
v-t="['c:actions:webhook']" |
|
color="primary" |
|
outlined |
|
class="caption d-100 mt-2" |
|
@click="webhookSliderModal = true" |
|
> |
|
<v-icon small class="mr-2 nc-btn-webhook"> mdi-hook </v-icon> Webhooks |
|
</v-btn> |
|
<webhook-slider v-model="webhookSliderModal" :meta="meta" /> |
|
</div> |
|
|
|
<div |
|
v-if="!isSharedBase && time - $store.state.settings.miniSponsorCard > 15 * 60 * 1000" |
|
class="py-2 sponsor-wrapper" |
|
> |
|
<v-icon small class="close-icon" @click="hideMiniSponsorCard"> mdi-close-circle-outline </v-icon> |
|
<v-divider class="mb-2" /> |
|
<flip-card width="100%" height="100px" :on-time="30 * 1000" :on-hover="false"> |
|
<template #front> |
|
<extras class="pl-1 mt-1" /> |
|
<v-btn |
|
v-t="['e:hiring']" |
|
color="primary" |
|
outlined |
|
class="caption d-100 mt-4" |
|
href="https://angel.co/company/nocodb" |
|
target="_blank" |
|
> |
|
🚀 We are Hiring! 🚀 |
|
</v-btn> |
|
</template> |
|
<template #back> |
|
<span class="caption text-left body-1 textColor--text text--lighten-1">{{ supportCost }}</span> |
|
<v-btn |
|
color="primary" |
|
class="caption d-100 my-2" |
|
outlined |
|
href="https://github.com/sponsors/nocodb" |
|
target="_blank" |
|
> |
|
<v-icon small color="red" class="mr-2"> mdi-cards-heart </v-icon> |
|
{{ $t('activity.sponsorUs') }} |
|
</v-btn> |
|
</template> |
|
</flip-card> |
|
</div> |
|
</div> |
|
</v-container> |
|
|
|
<create-view-dialog |
|
v-if="showCreateView" |
|
v-model="showCreateView" |
|
:nodes="nodes" |
|
:table="table" |
|
:show_as="createViewType" |
|
:views-count="views.length" |
|
:primary-value-column="primaryValueColumn" |
|
:meta="meta" |
|
:copy-view="copyViewRef" |
|
:alias="meta.title" |
|
:views-list="views" |
|
:selected-view-id="selectedViewId" |
|
@created="onViewCreate" |
|
/> |
|
|
|
<v-dialog v-model="showShareModel" max-width="650px"> |
|
<v-card class="pa-3 backgroundColor"> |
|
<v-container @click.stop> |
|
<h3 class="title mb-3"> |
|
<!-- This view is shared via a private link --> |
|
{{ $t('msg.info.privateLink') }} |
|
</h3> |
|
<p class="grey--text body-2"> |
|
<!-- People with private link can only see cells visible in this view --> |
|
</p> |
|
<div style="border-radius: 4px" class="share-link-box body-2 pa-2 d-flex align-center"> |
|
{{ sharedViewUrl }} |
|
<v-spacer /> |
|
<a v-t="['c:view:share:open-url']" :href="`${sharedViewUrl}`" style="text-decoration: none" target="_blank"> |
|
<v-icon small class="mx-2">mdi-open-in-new</v-icon> |
|
</a> |
|
<v-icon small class="pointer" @click="copyShareUrlToClipboard"> mdi-content-copy </v-icon> |
|
</div> |
|
|
|
<v-expansion-panels v-model="advanceOptionsPanel" class="mx-auto" flat> |
|
<v-expansion-panel> |
|
<v-expansion-panel-header hide-actions> |
|
<v-spacer /> |
|
<span class="grey--text caption" |
|
>More Options |
|
<v-icon color="grey" small> |
|
mdi-chevron-{{ advanceOptionsPanel === 0 ? 'up' : 'down' }} |
|
</v-icon></span |
|
> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content> |
|
<v-checkbox |
|
v-model="passwordProtect" |
|
class="caption" |
|
:label="$t('msg.info.beforeEnablePwd')" |
|
hide-details |
|
dense |
|
@change="onPasswordProtectChange" |
|
/> |
|
<div v-if="passwordProtect" class="d-flex flex-column align-center justify-center"> |
|
<v-text-field |
|
v-model="shareLink.password" |
|
autocomplete="new-password" |
|
browser-autocomplete="new-password" |
|
class="password-field mr-2 caption" |
|
style="max-width: 230px" |
|
:type="showShareLinkPassword ? 'text' : 'password'" |
|
:hint="$t('placeholder.password.enter')" |
|
persistent-hint |
|
dense |
|
solo |
|
flat |
|
> |
|
<template #append> |
|
<v-icon small @click="showShareLinkPassword = !showShareLinkPassword"> |
|
{{ showShareLinkPassword ? 'visibility_off' : 'visibility' }} |
|
</v-icon> |
|
</template> |
|
</v-text-field> |
|
<v-btn color="primary" class="caption" small @click="saveShareLinkPassword"> |
|
<!-- Save password --> |
|
{{ $t('placeholder.password.save') }} |
|
</v-btn> |
|
</div> |
|
<v-checkbox |
|
v-if="selectedView && selectedView.type === viewTypes.GRID" |
|
v-model="allowCSVDownload" |
|
class="caption" |
|
label="Allow Download" |
|
hide-details |
|
dense |
|
@change="onAllowCSVDownloadChange" |
|
/> |
|
</v-expansion-panel-content> |
|
</v-expansion-panel> |
|
</v-expansion-panels> |
|
</v-container> |
|
</v-card> |
|
</v-dialog> |
|
</v-navigation-drawer> |
|
</template> |
|
|
|
<script> |
|
import draggable from 'vuedraggable'; |
|
import { ViewTypes } from 'nocodb-sdk'; |
|
import CreateViewDialog from '~/components/project/spreadsheet/dialog/CreateViewDialog'; |
|
import Extras from '~/components/project/spreadsheet/components/Extras'; |
|
import viewIcons from '~/helpers/viewIcons'; |
|
import { copyTextToClipboard } from '~/helpers/xutils'; |
|
import SponsorMini from '~/components/SponsorMini'; |
|
import CodeSnippet from '~/components/project/spreadsheet/components/CodeSnippet'; |
|
import WebhookSlider from '~/components/project/tableTabs/webhook/WebhookSlider'; |
|
import FlipCard from '~/components/project/spreadsheet/components/FlipCard'; |
|
|
|
export default { |
|
name: 'SpreadsheetNavDrawer', |
|
components: { WebhookSlider, CodeSnippet, SponsorMini, Extras, CreateViewDialog, draggable, FlipCard }, |
|
props: { |
|
extraViewParams: Object, |
|
showAdvanceOptions: Boolean, |
|
isView: Boolean, |
|
hideViews: Boolean, |
|
primaryValueColumn: [Number, String], |
|
toggleDrawer: { |
|
type: Boolean, |
|
default: false, |
|
}, |
|
nodes: Object, |
|
table: String, |
|
selectedViewId: [String, Number], |
|
selectedView: Object, |
|
meta: [Object, Array], |
|
concatenatedXWhere: String, |
|
sort: String, |
|
showFields: Object, |
|
filters: [Object, Array], |
|
sortList: [Object, Array], |
|
load: { |
|
default: true, |
|
type: Boolean, |
|
}, |
|
currentApiUrl: String, |
|
fieldsOrder: Array, |
|
viewStatus: Object, |
|
// columnsWidth: Object, |
|
// coverImageField: String, |
|
groupingField: String, |
|
// showSystemFields: Boolean, |
|
views: Array, |
|
queryParams: Object, |
|
}, |
|
data: () => ({ |
|
advanceOptionsPanel: false, |
|
webhookSliderModal: false, |
|
codeSnippetModal: false, |
|
drag: false, |
|
dragOptions: { |
|
animation: 200, |
|
group: 'description', |
|
disabled: false, |
|
ghostClass: 'ghost', |
|
}, |
|
time: Date.now(), |
|
sponsorMiniVisible: true, |
|
enableDummyFeat: false, |
|
searchQueryVal: '', |
|
showShareLinkPassword: false, |
|
passwordProtect: false, |
|
allowCSVDownload: true, |
|
sharedViewPassword: '', |
|
overAdvShieldIcon: false, |
|
overShieldIcon: false, |
|
viewIcons, |
|
copyViewRef: null, |
|
shareLink: {}, |
|
showShareModel: false, |
|
showCreateView: false, |
|
loading: false, |
|
viewTypeAlias: { |
|
[ViewTypes.GRID]: 'grid', |
|
[ViewTypes.FORM]: 'form', |
|
[ViewTypes.GALLERY]: 'gallery', |
|
}, |
|
}), |
|
computed: { |
|
isSharedBase() { |
|
return this.$route.params && this.$route.params.shared_base_id; |
|
}, |
|
viewsList: { |
|
set(v) { |
|
this.$emit('update:views', v); |
|
}, |
|
get() { |
|
return this.views; |
|
}, |
|
}, |
|
viewTypes() { |
|
return ViewTypes; |
|
}, |
|
newViewParams() { |
|
if (!this.showFields) { |
|
return {}; |
|
} |
|
const showFields = { ...this.showFields }; |
|
Object.keys(showFields).forEach(k => { |
|
showFields[k] = true; |
|
}); |
|
return { showFields }; |
|
}, |
|
selectedViewIdLocal: { |
|
set(val) { |
|
const view = (this.views || []).find(v => v.id === val); |
|
this.$router.push({ |
|
query: { |
|
...this.$route.query, |
|
view: view && view.id, |
|
}, |
|
}); |
|
}, |
|
get() { |
|
let id; |
|
if (this.views) { |
|
const view = this.views.find(v => v.id === this.$route.query.view); |
|
id = (view && view.id) || ((this.views && this.views[0]) || {}).id; |
|
} |
|
return id; |
|
}, |
|
}, |
|
sharedViewUrl() { |
|
let viewType; |
|
|
|
switch (this.shareLink.type) { |
|
case this.viewTypes.FORM: |
|
viewType = 'form'; |
|
break; |
|
case this.viewTypes.KANBAN: |
|
viewType = 'kanban'; |
|
break; |
|
default: |
|
viewType = 'view'; |
|
} |
|
return `${this.dashboardUrl}#/nc/${viewType}/${this.shareLink.uuid}`; |
|
}, |
|
supportCost() { |
|
const cost = parseInt(this.$store.getters['project/GtrProjectCost']); |
|
if (cost > 0) { |
|
return `This costs ~$${cost}/year in non-open source products.`; |
|
} |
|
return 'Your donations will help us to make this product better.'; |
|
}, |
|
}, |
|
watch: { |
|
async load(v) { |
|
if (v) { |
|
await this.loadViews(); |
|
this.onViewIdChange(this.selectedViewIdLocal); |
|
} |
|
}, |
|
selectedViewIdLocal(id) { |
|
this.onViewIdChange(id); |
|
}, |
|
}, |
|
async created() { |
|
if (this.load) { |
|
await this.loadViews(); |
|
} |
|
this.onViewIdChange(this.selectedViewIdLocal); |
|
}, |
|
methods: { |
|
async onMove(event) { |
|
if (this.viewsList.length - 1 === event.moved.newIndex) { |
|
this.$set(this.viewsList[event.moved.newIndex], 'order', this.viewsList[event.moved.newIndex - 1].order + 1); |
|
} else if (event.moved.newIndex === 0) { |
|
this.$set(this.viewsList[event.moved.newIndex], 'order', this.viewsList[1].order / 2); |
|
} else { |
|
this.$set( |
|
this.viewsList[event.moved.newIndex], |
|
'order', |
|
(this.viewsList[event.moved.newIndex - 1].order + this.viewsList[event.moved.newIndex + 1].order) / 2 |
|
); |
|
} |
|
await this.$api.dbView.update(this.viewsList[event.moved.newIndex].id, { |
|
title: this.viewsList[event.moved.newIndex].title, |
|
order: this.viewsList[event.moved.newIndex].order, |
|
}); |
|
|
|
this.$e('a:view:reorder'); |
|
}, |
|
onViewIdChange(id) { |
|
const selectedView = this.views && this.views.find(v => v.id === id); |
|
// const queryParams = {} |
|
this.$emit('update:selectedViewId', id); |
|
this.$emit('update:selectedView', selectedView); |
|
// if (selectedView.type === 'table') { |
|
// return; |
|
// } |
|
// try { |
|
// queryParams = JSON.parse(selectedView.query_params) || {} |
|
// } catch (e) { |
|
// // console.log(e) |
|
// } |
|
// this.$emit('update:filters', queryParams.filters || []) |
|
// this.$emit('update:sortList', queryParams.sortList || []) |
|
// this.$emit('update:fieldsOrder', queryParams.fieldsOrder || []) |
|
// this.$emit('update:viewStatus', queryParams.viewStatus || {}) |
|
// this.$emit('update:columnsWidth', queryParams.columnsWidth || {}) |
|
// this.$emit('update:extraViewParams', queryParams.extraViewParams || {}) |
|
// this.$emit('update:coverImageField', queryParams.coverImageField) |
|
// this.$emit('update:groupingField', queryParams.groupingField) |
|
// this.$emit('update:showSystemFields', queryParams.showSystemFields) |
|
// if (queryParams.showFields) { |
|
// this.$emit('update:showFields', queryParams.showFields) |
|
// } else { |
|
// this.$emit('mapFieldsAndShowFields') |
|
// } |
|
this.$emit('loadTableData'); |
|
}, |
|
hideMiniSponsorCard() { |
|
this.$store.commit('settings/MutMiniSponsorCard', Date.now()); |
|
}, |
|
openCreateViewDlg(type) { |
|
const mainView = this.viewsList.find(v => v.type === 'table' || v.type === 'view'); |
|
try { |
|
this.copyViewRef = this.copyViewRef || { |
|
query_params: JSON.stringify({ |
|
...this.newViewParams, |
|
fieldsOrder: JSON.parse(mainView.query_params).fieldsOrder, |
|
}), |
|
}; |
|
} catch {} |
|
this.createViewType = type; |
|
this.showCreateView = true; |
|
this.$e('c:view:create', { view: type }); |
|
}, |
|
isCentrallyAligned(col) { |
|
return ![ |
|
'SingleLineText', |
|
'LongText', |
|
'Attachment', |
|
'Date', |
|
'Time', |
|
'Email', |
|
'URL', |
|
'DateTime', |
|
'CreateTime', |
|
'LastModifiedTime', |
|
'Currency', |
|
].includes(col.uidt); |
|
}, |
|
onPasswordProtectChange() { |
|
if (!this.passwordProtect) { |
|
this.shareLink.password = null; |
|
this.saveShareLinkPassword(); |
|
} |
|
}, |
|
onAllowCSVDownloadChange() { |
|
this.saveAllowCSVDownload(); |
|
}, |
|
async saveShareLinkPassword() { |
|
try { |
|
await this.$api.dbViewShare.update(this.shareLink.id, { |
|
password: this.shareLink.password, |
|
}); |
|
|
|
// await this.$store.dispatch('sqlMgr/ActSqlOp', [ |
|
// { dbAlias: this.nodes.dbAlias }, |
|
// 'updateSharedViewLinkPassword', |
|
// { |
|
// id: this.shareLink.id, |
|
// password: this.shareLink.password |
|
// } |
|
// ]) |
|
this.$toast.success('Successfully updated').goAway(3000); |
|
} catch (e) { |
|
this.$toast.error(await this._extractSdkResponseErrorMsg(e)).goAway(3000); |
|
} |
|
|
|
this.$e('a:view:share:enable-pwd'); |
|
}, |
|
async saveAllowCSVDownload() { |
|
try { |
|
const meta = |
|
this.shareLink.meta && typeof this.shareLink.meta === 'string' |
|
? JSON.parse(this.shareLink.meta) |
|
: this.shareLink.meta; |
|
|
|
meta.allowCSVDownload = this.allowCSVDownload; |
|
await this.$api.dbViewShare.update(this.shareLink.id, { |
|
meta, |
|
}); |
|
this.$toast.success('Successfully updated').goAway(3000); |
|
} catch (e) { |
|
this.$toast.error(await this._extractSdkResponseErrorMsg(e)).goAway(3000); |
|
} |
|
if (this.allowCSVDownload) { |
|
this.$e('a:view:share:enable-csv-download'); |
|
} else { |
|
this.$e('a:view:share:disable-csv-download'); |
|
} |
|
}, |
|
async loadViews() { |
|
// this.viewsList = await this.sqlOp( |
|
// { |
|
// dbAlias: this.nodes.dbAlias |
|
// }, |
|
// 'xcVirtualTableList', |
|
// { |
|
// tn: this.table |
|
// } |
|
// ) |
|
// this.selectedViewIdLocal = this.viewsList && this.viewsList[0] && this.viewsList[0].id |
|
|
|
// this.viewsList = [] |
|
|
|
const views = (await this.$api.dbView.list(this.meta.id)).list; |
|
this.$emit('update:views', views); |
|
}, |
|
// async onViewChange() { |
|
// let query_params = {} |
|
// try { |
|
// console.log(this.selectedView) |
|
// query_params = JSON.parse(this.selectedView.query_params); |
|
// } catch (e) { |
|
// console.log(e) |
|
// } |
|
// this.$emit('update:filters', query_params.filters || []); |
|
// this.$emit('update:sortList', query_params.sortList || []); |
|
// if (query_params.showFields) { |
|
// this.$emit('update:showFields', query_params.showFields); |
|
// } else { |
|
// this.$emit('mapFieldsAndShowFields'); |
|
// } |
|
// this.$emit('loadTableData'); |
|
// }, |
|
copyapiUrlToClipboard() { |
|
copyTextToClipboard(this.currentApiUrl); |
|
this.clipboardSuccessHandler(); |
|
}, |
|
async updateViewName(view, index) { |
|
if (!view.edit) { |
|
return; |
|
} |
|
|
|
// const oldTitle = view.title |
|
|
|
this.$set(view, 'edit', false); |
|
if (view.title_temp === view.title) { |
|
return; |
|
} |
|
if (this.viewsList.some((v, i) => i !== index && (v.alias || v.title) === view.title_temp)) { |
|
this.$toast.info('View name should be unique').goAway(3000); |
|
return; |
|
} |
|
try { |
|
// if (this.selectedViewIdLocal === view.id) { |
|
// await this.$router.push({ |
|
// query: { |
|
// ...this.$route.query, |
|
// view: view.title_temp |
|
// } |
|
// }) |
|
// } |
|
this.$set(view, 'title', view.title_temp); |
|
await this.$api.dbView.update(view.id, { |
|
title: view.title, |
|
order: view.order, |
|
}); |
|
this.$toast.success('View renamed successfully').goAway(3000); |
|
} catch (e) { |
|
this.$toast.error(await this._extractSdkResponseErrorMsg(e)).goAway(3000); |
|
} |
|
}, |
|
showRenameTextBox(view, i) { |
|
this.$set(view, 'edit', true); |
|
this.$set(view, 'title_temp', view.title); |
|
this.$nextTick(() => { |
|
const input = this.$refs[`input${i}`][0]; |
|
input.focus(); |
|
input.setSelectionRange(0, input.value.length); |
|
}); |
|
this.$e('c:view:rename', { view: view.type }); |
|
}, |
|
async deleteView(view) { |
|
try { |
|
await this.$api.dbView.delete(view.id); |
|
this.$toast.success('View deleted successfully').goAway(3000); |
|
await this.loadViews(); |
|
} catch (e) { |
|
this.$toast.error(await this._extractSdkResponseErrorMsg(e)).goAway(3000); |
|
} |
|
this.$e('a:view:delete', { view: view.type }); |
|
}, |
|
async genShareLink() { |
|
const shared = await this.$api.dbViewShare.create(this.selectedViewId); |
|
shared.meta = shared.meta && typeof shared.meta === 'string' ? JSON.parse(shared.meta) : shared.meta; |
|
// todo: url |
|
this.shareLink = shared; |
|
this.passwordProtect = shared.password !== null; |
|
this.allowCSVDownload = shared.meta.allowCSVDownload; |
|
this.showShareModel = true; |
|
}, |
|
copyView(view, i) { |
|
this.createViewType = view.type; |
|
this.showCreateView = true; |
|
this.copyViewRef = view; |
|
this.$e('c:view:copy', { view: view.type }); |
|
}, |
|
async onViewCreate(viewMeta) { |
|
this.copyViewRef = null; |
|
await this.loadViews(); |
|
this.selectedViewIdLocal = viewMeta.id; |
|
// await this.onViewChange(); |
|
this.$e('a:view:create', { view: viewMeta.type }); |
|
}, |
|
clipboard(str) { |
|
const el = document.createElement('textarea'); |
|
el.addEventListener('focusin', e => e.stopPropagation()); |
|
el.value = str; |
|
document.body.appendChild(el); |
|
el.select(); |
|
document.execCommand('copy'); |
|
document.body.removeChild(el); |
|
}, |
|
clipboardSuccessHandler() { |
|
this.$toast.info('Copied to clipboard').goAway(1000); |
|
}, |
|
copyShareUrlToClipboard() { |
|
this.clipboard(this.sharedViewUrl); |
|
this.clipboardSuccessHandler(); |
|
this.$e('c:view:share:copy-url'); |
|
}, |
|
}, |
|
}; |
|
</script> |
|
|
|
<style scoped lang="scss"> |
|
::v-deep { |
|
.v-list-item--dense .v-list-item__icon, |
|
.v-list--dense .v-list-item .v-list-item__icon { |
|
margin-top: 4px; |
|
margin-bottom: 4px; |
|
} |
|
|
|
.v-list-item--dense, |
|
.v-list--dense .v-list-item { |
|
min-height: 32px; |
|
} |
|
|
|
.advance-menu-divider { |
|
width: calc(100% - 26px); |
|
margin-left: 13px; |
|
border-style: dashed; |
|
margin-top: 5px; |
|
margin-bottom: 5px; |
|
} |
|
|
|
.view .view-icon { |
|
display: none; |
|
transition: 0.3s display; |
|
} |
|
|
|
.view:hover .view-icon { |
|
display: inline-block; |
|
} |
|
|
|
.view:hover .check-icon { |
|
display: none; |
|
} |
|
|
|
.password-field.v-text-field.v-text-field--solo { |
|
.v-text-field__details { |
|
padding: 0 2px !important; |
|
|
|
.v-messages__message { |
|
color: grey; |
|
font-size: 0.65rem; |
|
} |
|
} |
|
|
|
.v-input__control { |
|
min-height: 28px !important; |
|
} |
|
} |
|
} |
|
|
|
.share-link-box { |
|
position: relative; |
|
z-index: 2; |
|
} |
|
|
|
.share-link-box::before { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
bottom: 0; |
|
right: 0; |
|
background: var(--v-primary-base); |
|
opacity: 0.2; |
|
content: ''; |
|
z-index: 1; |
|
pointer-events: none; |
|
} |
|
|
|
.views-navigation-drawer { |
|
border-left: 1px solid #80808033; |
|
} |
|
|
|
.sponsor-wrapper { |
|
position: relative; |
|
|
|
.close-icon { |
|
position: absolute; |
|
right: 4px; |
|
top: 12px; |
|
z-index: 9; |
|
opacity: 0; |
|
transition: 0.4s opacity; |
|
} |
|
|
|
&:hover .close-icon { |
|
opacity: 1; |
|
} |
|
} |
|
|
|
.nc-draggable-child .nc-child-draggable-icon { |
|
opacity: 0; |
|
transition: 0.3s opacity; |
|
position: absolute; |
|
left: 0; |
|
} |
|
|
|
.nc-draggable-child:hover .nc-child-draggable-icon { |
|
opacity: 1; |
|
} |
|
|
|
.nc-draggable-child:hover .nc-child-draggable-icon { |
|
opacity: 1; |
|
} |
|
|
|
.flip-list-move { |
|
transition: transform 0.5s; |
|
} |
|
.no-move { |
|
transition: transform 0s; |
|
} |
|
.ghost { |
|
opacity: 0.5; |
|
background: grey; |
|
} |
|
.mx-auto .v-expansion-panel { |
|
background: var(--v-backgroundColor-base); |
|
} |
|
</style>
|
|
|