Browse Source

feat(gui-v2): add all options in toolbar

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2819/head
Pranav C 2 years ago
parent
commit
9f4e789418
  1. 10
      packages/nc-gui-v2/components/smartsheet-toolbar/AddRow.vue
  2. 14
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  3. 9
      packages/nc-gui-v2/components/smartsheet-toolbar/DeleteTable.vue
  4. 14
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  5. 182
      packages/nc-gui-v2/components/smartsheet-toolbar/LockMenu.vue
  6. 276
      packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue
  7. 11
      packages/nc-gui-v2/components/smartsheet-toolbar/Reload.vue
  8. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue
  9. 18
      packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue
  10. 15
      packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue
  11. 14
      packages/nc-gui-v2/components/smartsheet-toolbar/ToggleDrawer.vue
  12. 14
      packages/nc-gui-v2/components/smartsheet/Toolbar.vue
  13. 4
      packages/nc-gui-v2/components/tabs/Smartsheet.vue

10
packages/nc-gui-v2/components/smartsheet-toolbar/AddRow.vue

@ -0,0 +1,10 @@
<script setup lang="ts">
import MdiAddIcon from '~icons/mdi/plus-outline '
const emit = defineEmits(['add-row'])
</script>
<template>
<MdiAddIcon class="text-grey" @click="emit('add-row')" />
</template>
<style scoped></style>

14
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue

@ -18,18 +18,8 @@ const applyChanges = () => {}
<template> <template>
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<v-badge :value="filters.length" color="primary" dot overlap> <v-badge :value="filters.length" color="primary" dot overlap>
<a-button <a-button v-t="['c:filter']" class="nc-filter-menu-btn nc-toolbar-btn" :disabled="isLocked" size="small">
v-t="['c:filter']" <div class="flex align-center gap-1">
class="nc-filter-menu-btn px-2 nc-remove-border border-0"
:disabled="isLocked"
outlined
size="small"
text
:class="{
'primary lighten-5 grey--text text--darken-3': filters.length,
}"
>
<div class="flex align-center gap-1 text-sm">
<MdiFilterIcon class="text-grey" /> <MdiFilterIcon class="text-grey" />
<!-- Filter --> <!-- Filter -->
<span class="text-capitalize">{{ $t('activity.filter') }}</span> <span class="text-capitalize">{{ $t('activity.filter') }}</span>

9
packages/nc-gui-v2/components/smartsheet-toolbar/DeleteTable.vue

@ -0,0 +1,9 @@
<script setup lang="ts">
import MdiDeleteIcon from '~icons/mdi/delete-outline'
</script>
<template>
<MdiDeleteIcon class="text-grey" />
</template>
<style scoped></style>

14
packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue

@ -77,18 +77,8 @@ const onMove = (event) => {
<template> <template>
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<v-badge :value="isAnyFieldHidden" color="primary" dot overlap v-bind="props"> <v-badge :value="isAnyFieldHidden" color="primary" dot overlap v-bind="props">
<a-button <a-button v-t="['c:fields']" class="nc-fields-menu-btn nc-toolbar-btn" :disabled="isLocked" size="small">
v-t="['c:fields']" <div class="flex align-center gap-1">
class="nc-fields-menu-btn px-2 nc-remove-border border-0"
:disabled="isLocked"
outlined
size="small"
text
:class="{
'primary lighten-5 grey--text text--darken-3': isAnyFieldHidden,
}"
>
<div class="flex align-center gap-1 text-sm">
<!-- <v-icon small class="mr-1" color="#777"> mdi-eye-off-outline </v-icon> --> <!-- <v-icon small class="mr-1" color="#777"> mdi-eye-off-outline </v-icon> -->
<MdiEyeIcon class="text-grey"></MdiEyeIcon> <MdiEyeIcon class="text-grey"></MdiEyeIcon>
<!-- Fields --> <!-- Fields -->

182
packages/nc-gui-v2/components/smartsheet-toolbar/LockMenu.vue

@ -1,5 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from '@vue/reactivity'
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
import MdiLockOutlineIcon from '~icons/mdi/lock-outline'
import MdiAccountIcon from '~icons/mdi/account'
import MdiAccountGroupIcon from '~icons/mdi/account-group'
import MdiCheckIcon from '~icons/mdi/check-bold'
interface Props { interface Props {
modelValue?: LockType modelValue?: LockType
@ -32,6 +37,18 @@ function changeLockType(type: LockType) {
toast.success(`Successfully Switched to ${type} view`, { timeout: 3000 }) toast.success(`Successfully Switched to ${type} view`, { timeout: 3000 })
} }
const Icon = computed(() => {
switch (vModel.value) {
case LockType.Personal:
return MdiAccountIcon
case LockType.Locked:
return MdiLockOutlineIcon
case LockType.Collaborative:
default:
return MdiAccountGroupIcon
}
})
</script> </script>
<script lang="ts"> <script lang="ts">
@ -41,68 +58,109 @@ export default {
</script> </script>
<template> <template>
<v-menu offset-y max-width="350"> <a-dropdown max-width="350" :trigger="['click']">
<template #activator="{ props: menuProps }"> <Icon class="mx-1 nc-view-lock-menu text-grey"> mdi-lock-outline </Icon>
<v-icon v-if="vModel === LockType.Locked" small class="mx-1 nc-view-lock-menu" v-bind="menuProps.onClick"> <template #overlay>
mdi-lock-outline <div class="min-w-[350px] max-w-[500px] shadow bg-white">
</v-icon> <div>
<v-icon v-else-if="vModel === LockType.Personal" small class="mx-1 nc-view-lock-menu" v-bind="menuProps.onClick"> <div class="nc-menu-option">
mdi-account <MdiCheckIcon v-if="!vModel || vModel === LockType.Collaborative" />
</v-icon> <span v-else />
<v-icon v-else small class="mx-1 nc-view-lock-menu" v-bind="menuProps.onClick"> mdi-account-group-outline </v-icon>
<div>
<MdiAccountGroupIcon />
Collaborative view
<div class="nc-subtitle">Collaborators with edit permissions or higher can change the view configuration.</div>
</div>
</div>
<div class="nc-menu-option">
<MdiCheckIcon v-if="vModel === LockType.Locked" />
<span v-else />
<div>
<MdiLockOutlineIcon />
Locked View
<div class="nc-subtitle">No one can edit the view configuration until it is unlocked.</div>
</div>
</div>
<div class="nc-menu-option">
<MdiCheckIcon v-if="vModel === LockType.Personal" />
<span v-else />
<div>
<MdiAccountIcon />
Personal view
<div class="nc-subtitle">
Only you can edit the view configuration. Other collaborators personal views are hidden by default.
</div>
</div>
</div>
</div>
</div>
</template> </template>
<v-list maxc-width="350">
<v-list-item two-line class="pb-4" @click="changeLockType(LockType.Collaborative)"> <!-- <v-list maxc-width="350">
<v-list-item-icon class="mr-1 align-self-center"> <v-list-item two-line class="pb-4" @click="changeLockType(LockType.Collaborative)">
<v-icon v-if="!vModel || vModel === LockType.Collaborative" small> mdi-check-bold </v-icon> <v-list-item-icon class="mr-1 align-self-center">
</v-list-item-icon> <v-icon v-if="!vModel || vModel === LockType.Collaborative" small> mdi-check-bold </v-icon>
<v-list-item-content class="pb-1"> </v-list-item-icon>
<v-list-item-title> <v-list-item-content class="pb-1">
<v-icon small class="mt-n1" color="primary"> mdi-account-group </v-icon> <v-list-item-title>
Collaborative view <v-icon small class="mt-n1" color="primary"> mdi-account-group </v-icon>
</v-list-item-title> Collaborative view
</v-list-item-title>
<v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
Collaborators with edit permissions or higher can change the view configuration. <v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
</v-list-item-subtitle> Collaborators with edit permissions or higher can change the view configuration.
</v-list-item-content> </v-list-item-subtitle>
</v-list-item> </v-list-item-content>
<v-list-item two-line class="pb-4" @click="changeLockType(LockType.Locked)"> </v-list-item>
<v-list-item-icon class="mr-1 align-self-center"> <v-list-item two-line class="pb-4" @click="changeLockType(LockType.Locked)">
<v-icon v-if="vModel === LockType.Locked" small> mdi-check-bold </v-icon> <v-list-item-icon class="mr-1 align-self-center">
</v-list-item-icon> <v-icon v-if="vModel === LockType.Locked" small> mdi-check-bold </v-icon>
</v-list-item-icon>
<v-list-item-content class="pb-1">
<v-list-item-title> <v-list-item-content class="pb-1">
<v-icon small class="mt-n1" color="primary"> mdi-lock </v-icon> <v-list-item-title>
Locked View <v-icon small class="mt-n1" color="primary"> mdi-lock </v-icon>
</v-list-item-title> Locked View
</v-list-item-title>
<v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
No one can edit the view configuration until it is unlocked. <v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
</v-list-item-subtitle> No one can edit the view configuration until it is unlocked.
<span class="caption mt-3"><v-icon class="mr-1 mt-n1" x-small color="#fcb401"> mdi-star</v-icon>Locked view.</span> </v-list-item-subtitle>
</v-list-item-content> <span class="caption mt-3"><v-icon class="mr-1 mt-n1" x-small color="#fcb401"> mdi-star</v-icon>Locked view.</span>
</v-list-item> </v-list-item-content>
<v-list-item three-line @click="changeLockType(LockType.Personal)"> </v-list-item>
<v-list-item-icon class="mr-1 align-self-center"> <v-list-item three-line @click="changeLockType(LockType.Personal)">
<v-icon v-if="vModel === LockType.Personal" small> mdi-check-bold </v-icon> <v-list-item-icon class="mr-1 align-self-center">
</v-list-item-icon> <v-icon v-if="vModel === LockType.Personal" small> mdi-check-bold </v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title> <v-list-item-content>
<v-icon small class="mt-n1" color="primary"> mdi-account </v-icon> <v-list-item-title>
Personal view <v-icon small class="mt-n1" color="primary"> mdi-account </v-icon>
</v-list-item-title> Personal view
</v-list-item-title>
<v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
Only you can edit the view configuration. Other collaborators personal views are hidden by default. <v-list-item-subtitle class="pt-2 pl- font-weight-light" style="white-space: normal">
</v-list-item-subtitle> Only you can edit the view configuration. Other collaborators personal views are hidden by default.
<span class="caption mt-3"><v-icon class="mr-1 mt-n1" x-small color="#fcb401"> mdi-star</v-icon>Coming soon.</span> </v-list-item-subtitle>
</v-list-item-content> <span class="caption mt-3"><v-icon class="mr-1 mt-n1" x-small color="#fcb401"> mdi-star</v-icon>Coming soon.</span>
</v-list-item> </v-list-item-content>
</v-list> </v-list-item>
</v-menu> </v-list> -->
</a-dropdown>
</template> </template>
<style scoped></style> <style scoped>
.nc-menu-option {
@apply grid grid-cols-[30px,auto] gap-2 p-4;
}
.nc-menu-option > :first-child {
@apply align-self-center;
}
.nc-subtitle {
@apply font-size-sm font-weight-light;
}
</style>

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

@ -1,251 +1,23 @@
<script> <script lang="ts" setup>
import FileSaver from 'file-saver' import MdiFlashIcon from '~icons/mdi/flash-outline'
import { ExportTypes } from 'nocodb-sdk' import MdiMenuDownIcon from '~icons/mdi/menu-down'
import { NOCO } from '~/lib/constants'
import DropOrSelectFileModal from '~/components/import/DropOrSelectFileModal'
import ColumnMappingModal from '~/components/project/spreadsheet/components/importExport/ColumnMappingModal'
import CSVTemplateAdapter from '~/components/import/templateParsers/CSVTemplateAdapter'
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
import WebhookModal from '~/components/project/tableTabs/webhook/WebhookModal'
import WebhookSlider from '~/components/project/tableTabs/webhook/WebhookSlider'
export default {
name: 'ExportImport',
components: {
WebhookSlider,
ColumnMappingModal,
DropOrSelectFileModal,
},
props: {
meta: Object,
nodes: Object,
selectedView: Object,
publicViewId: String,
queryParams: Object,
isView: Boolean,
reqPayload: Object,
},
emits: ['reload', 'showAdditionalFeatOverlay'],
data() {
return {
importModal: false,
columnMappingModal: false,
parsedCsv: {},
webhookModal: false,
}
},
methods: {
async onCsvFileSelection(file) {
const reader = new FileReader()
reader.onload = async (e) => {
const templateGenerator = new CSVTemplateAdapter(file.name, e.target.result)
await templateGenerator.init()
templateGenerator.parseData()
this.parsedCsv.columns = templateGenerator.getColumns()
this.parsedCsv.data = templateGenerator.getData()
this.columnMappingModal = true
this.importModal = false
}
reader.readAsText(file)
},
async extractCsvData() {
return Promise.all(
this.data.map(async (r) => {
const row = {}
for (const col of this.availableColumns) {
if (col.virtual) {
let prop, cn
if (col.mm || (col.lk && col.lk.type === 'mm')) {
const tn = col.mm ? col.mm.rtn : col.lk.ltn
const title = col.mm ? col.mm._rtn : col.lk._ltn
await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env,
dbAlias: this.nodes.dbAlias,
tn,
})
prop = `${title}MMList`
cn = col.lk
? col.lk._lcn
: (
this.$store.state.meta.metas[tn].columns.find((c) => c.pv) ||
this.$store.state.meta.metas[tn].columns.find((c) => c.pk) ||
{}
).title
row[col.title] = r.row[prop] && r.row[prop].map((r) => cn && r[cn])
} else if (col.hm || (col.lk && col.lk.type === 'hm')) {
const tn = col.hm ? col.hm.table_name : col.lk.ltn
const title = col.hm ? col.hm.title : col.lk._ltn
await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env,
dbAlias: this.nodes.dbAlias,
tn,
})
prop = `${title}List`
cn = col.lk
? col.lk._lcn
: (
this.$store.state.meta.metas[tn].columns.find((c) => c.pv) ||
this.$store.state.meta.metas[tn].columns.find((c) => c.pk)
).title
row[col.title] = r.row[prop] && r.row[prop].map((r) => cn && r[cn])
} else if (col.bt || (col.lk && col.lk.type === 'bt')) {
const tn = col.bt ? col.bt.rtn : col.lk.ltn
const title = col.bt ? col.bt._rtn : col.lk._ltn
await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env,
dbAlias: this.nodes.dbAlias,
tn,
})
prop = `${title}Read`
cn = col.lk
? col.lk._lcn
: (
this.$store.state.meta.metas[tn].columns.find((c) => c.pv) ||
this.$store.state.meta.metas[tn].columns.find((c) => c.pk) ||
{}
).title
row[col.title] = r.row[prop] && r.row[prop] && cn && r.row[prop][cn]
} else {
row[col.title] = r.row[col.title]
}
} else if (col.uidt === 'Attachment') {
let data = []
try {
if (typeof r.row[col.title] === 'string') {
data = JSON.parse(r.row[col.title])
} else if (r.row[col.title]) {
data = r.row[col.title]
}
} catch {}
row[col.title] = (data || []).map((a) => `${a.title}(${a.url})`)
} else {
row[col.title] = r.row[col.title]
}
}
return row
}),
)
},
async exportCsv() {
let offset = 0
let c = 1
try {
while (!isNaN(offset) && offset > -1) {
let res
if (this.publicViewId) {
res = await this.$api.public.csvExport(this.publicViewId, ExportTypes.CSV, {
responseType: 'blob',
query: {
fields:
this.queryParams &&
this.queryParams.fieldsOrder &&
this.queryParams.fieldsOrder.filter((c) => this.queryParams.showFields[c]),
offset,
sortArrJson: JSON.stringify(
this.reqPayload &&
this.reqPayload.sorts &&
this.reqPayload.sorts.map(({ fk_column_id, direction }) => ({
direction,
fk_column_id,
})),
),
filterArrJson: JSON.stringify(this.reqPayload && this.reqPayload.filters),
},
headers: {
'xc-password': this.reqPayload && this.reqPayload.password,
},
})
} else {
res = await this.$api.dbViewRow.export(
NOCO,
this.projectName,
this.meta.title,
this.selectedView.title,
ExportTypes.CSV,
{
responseType: 'blob',
query: {
offset,
},
},
)
}
const { data } = res
offset = +res.headers['nc-export-offset']
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
FileSaver.saveAs(blob, `${this.meta.title}_exported_${c++}.csv`)
if (offset > -1) {
this.$toast.info('Downloading more files').goAway(3000)
} else {
this.$toast.success('Successfully exported all table data').goAway(3000)
}
}
} catch (e) {
console.log(e)
this.$toast.error(e.message).goAway(3000)
}
},
async importData(columnMappings) {
try {
const data = this.parsedCsv.data
for (let i = 0, progress = 0; i < data.length; i += 500) {
const batchData = data.slice(i, i + 500).map((row) =>
columnMappings.reduce((res, col) => {
// todo: parse data
if (col.enabled && col.destCn) {
const v = this.meta && this.meta.columns.find((c) => c.title === col.destCn)
let input = row[col.sourceCn]
// parse potential boolean values
if (v.uidt === UITypes.Checkbox) {
input = input.replace(/["']/g, '').toLowerCase().trim()
if (input === 'false' || input === 'no' || input === 'n') {
input = '0'
} else if (input === 'true' || input === 'yes' || input === 'y') {
input = '1'
}
} else if (v.uidt === UITypes.Number) {
if (input === '') {
input = null
}
} else if (v.uidt === UITypes.SingleSelect || v.uidt === UITypes.MultiSelect) {
if (input === '') {
input = null
}
}
res[col.destCn] = input
}
return res
}, {}),
)
await this.$api.dbTableRow.bulkCreate(NOCO, this.projectName, this.meta.title, batchData)
progress += batchData.length
this.$store.commit('loader/MutMessage', `Importing data : ${progress}/${data.length}`)
this.$store.commit('loader/MutProgress', Math.round((100 * progress) / data.length))
}
this.columnMappingModal = false
this.$store.commit('loader/MutClear')
this.$emit('reload')
this.$toast.success('Successfully imported table data').goAway(3000)
} catch (e) {
this.$toast.error(e.message).goAway(3000)
}
},
},
}
</script> </script>
<template> <template>
<div> <v-dropdown>
<a-button v-t="['c:actions']" class="nc-actions-menu-btn nc-toolbar-btn">
<div class="flex gap-1 align-center">
<MdiFlashIcon class="text-grey" />
<!-- More -->
{{ $t('general.more') }}
<MdiMenuDownIcon class="text-grey" />
</div>
</a-button>
<template #overlay>
<div></div>
</template>
</v-dropdown>
<!-- <div>
<v-menu open-on-hover bottom offset-y transition="slide-y-transition"> <v-menu open-on-hover bottom offset-y transition="slide-y-transition">
<template #activator="{ on }"> <template #activator="{ on }">
<v-btn <v-btn
@ -257,7 +29,7 @@ export default {
v-on="on" v-on="on"
> >
<v-icon small color="#777"> mdi-flash-outline </v-icon> <v-icon small color="#777"> mdi-flash-outline </v-icon>
<!-- More --> &lt;!&ndash; More &ndash;&gt;
{{ $t('general.more') }} {{ $t('general.more') }}
<v-icon small color="#777"> mdi-menu-down </v-icon> <v-icon small color="#777"> mdi-menu-down </v-icon>
@ -269,7 +41,7 @@ export default {
<v-list-item-title> <v-list-item-title>
<v-icon small class="mr-1"> mdi-download-outline </v-icon> <v-icon small class="mr-1"> mdi-download-outline </v-icon>
<span class="caption"> <span class="caption">
<!-- Download as CSV --> &lt;!&ndash; Download as CSV &ndash;&gt;
{{ $t('activity.downloadCSV') }} {{ $t('activity.downloadCSV') }}
</span> </span>
</v-list-item-title> </v-list-item-title>
@ -278,11 +50,11 @@ export default {
<v-list-item-title> <v-list-item-title>
<v-icon small class="mr-1" color=""> mdi-upload-outline </v-icon> <v-icon small class="mr-1" color=""> mdi-upload-outline </v-icon>
<span class="caption"> <span class="caption">
<!-- Upload CSV --> &lt;!&ndash; Upload CSV &ndash;&gt;
{{ $t('activity.uploadCSV') }} {{ $t('activity.uploadCSV') }}
</span> </span>
<span class="caption grey--text">(<x-icon small color="grey lighten-2"> mdi-alpha </x-icon> version)</span> <span class="caption grey&#45;&#45;text">(<x-icon small color="grey lighten-2"> mdi-alpha </x-icon> version)</span>
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item <v-list-item
@ -294,7 +66,7 @@ export default {
<v-list-item-title> <v-list-item-title>
<v-icon small class="mr-1" color=""> mdi-view-list-outline </v-icon> <v-icon small class="mr-1" color=""> mdi-view-list-outline </v-icon>
<span class="caption"> <span class="caption">
<!-- Shared View List --> &lt;!&ndash; Shared View List &ndash;&gt;
{{ $t('activity.listSharedView') }} {{ $t('activity.listSharedView') }}
</span> </span>
</v-list-item-title> </v-list-item-title>
@ -316,9 +88,9 @@ export default {
:parsed-csv="parsedCsv" :parsed-csv="parsedCsv"
@import="importData" @import="importData"
/> />
<!-- <webhook-modal v-if="webhookModal" v-model="webhookModal" :meta="meta" /> --> &lt;!&ndash; <webhook-modal v-if="webhookModal" v-model="webhookModal" :meta="meta" /> &ndash;&gt;
<WebhookSlider v-model="webhookModal" :meta="meta" /> <WebhookSlider v-model="webhookModal" :meta="meta" />
</div> </div> -->
</template> </template>
<style scoped></style> <style scoped></style>

11
packages/nc-gui-v2/components/smartsheet-toolbar/Reload.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
import { ReloadViewDataHookInj } from '~/context'
import MdiReloadIcon from '~icons/mdi/reload'
const reloadTri = inject(ReloadViewDataHookInj)
</script>
<template>
<MdiReloadIcon class="text-grey" @click="reloadTri.trigger()" />
</template>
<style scoped></style>

4
packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue

@ -27,9 +27,9 @@ const columns = computed(() =>
</script> </script>
<template> <template>
<a-input-search v-model:value="localValue" class="max-w-[250px]"> <a-input-search size="small" v-model:value="localValue" class="max-w-[250px]">
<template #addonBefore> <template #addonBefore>
<a-select v-model:value="localField" :options="columns" style="width: 100px" class="!text-xs" /> <a-select v-model:value="localField" :options="columns" style="width: 100px" class="!text-xs " size="small" />
</template> </template>
</a-input-search> </a-input-search>
</template> </template>

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

@ -0,0 +1,18 @@
<script lang="ts" setup>
import MdiOpenInNew from '~icons/mdi/open-in-new'
const { isUIAllowed } = useUIPermission()
</script>
<template>
<div>
<a-button v-t="['c:view:share']" outlined class="nc-btn-share-view nc-toolbar-btn" size="small" @click="$emit('share')">
<div class="flex align-center gap-1">
<MdiOpenInNew class="text-grey" />
<!-- Share View -->
{{ $t('activity.shareView') }}
</div>
</a-button>
</div>
</template>
<style scoped />

15
packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue

@ -29,19 +29,8 @@ watch(
<template> <template>
<a-dropdown offset-y class="" :trigger="['click']"> <a-dropdown offset-y class="" :trigger="['click']">
<v-badge :value="sorts && sorts.length" color="primary" dot overlap> <v-badge :value="sorts && sorts.length" color="primary" dot overlap>
<a-button <a-button v-t="['c:sort']" size="small" class="nc-sort-menu-btn nc-toolbar-btn" :disabled="isLocked"
v-t="['c:sort']" ><div class="flex align-center gap-1">
size="small"
class="nc-sort-menu-btn px-2 nc-remove-border border-0"
:disabled="isLocked"
small
text
outlined
:class="{
'primary lighten-5 grey&#45;&#45;text text&#45;&#45;darken-3': sorts && sorts.length,
}"
v-bind="props"
><div class="flex align-center gap-1 text-sm">
<MdiSortIcon class="text-grey" /> <MdiSortIcon class="text-grey" />
<!-- Sort --> <!-- Sort -->
<span class="text-capitalize">{{ $t('activity.sort') }}</span> <span class="text-capitalize">{{ $t('activity.sort') }}</span>

14
packages/nc-gui-v2/components/smartsheet-toolbar/ToggleDrawer.vue

@ -0,0 +1,14 @@
<script setup lang="ts">
import { ReloadViewDataHookInj } from '~/context'
import MdiDoorOpenIcon from '~icons/mdi/door-open'
import MdiDoorClosedIcon from '~icons/mdi/door-closed'
const navDrawerOpened = ref(false)
const Icon = computed(()=> navDrawerOpened.value ? MdiDoorOpenIcon : MdiDoorClosedIcon)
</script>
<template>
<Icon class="text-grey" @click="navDrawerOpened = !navDrawerOpened" />
</template>
<style scoped></style>

14
packages/nc-gui-v2/components/smartsheet/Toolbar.vue

@ -6,7 +6,19 @@
<SmartsheetToolbarFieldsMenu :show-system-fields="false" /> <SmartsheetToolbarFieldsMenu :show-system-fields="false" />
<SmartsheetToolbarColumnFilterMenu /> <SmartsheetToolbarColumnFilterMenu />
<SmartsheetToolbarSortListMenu /> <SmartsheetToolbarSortListMenu />
<SmartsheetToolbarShareView />
<SmartsheetToolbarMoreActions />
<div class="flex-1" />
<SmartsheetToolbarLockMenu />
<SmartsheetToolbarReload />
<SmartsheetToolbarAddRow />
<SmartsheetToolbarDeleteTable />
<SmartsheetToolbarToggleDrawer />
</div> </div>
</template> </template>
<style scoped></style> <style scoped>
:deep(.nc-toolbar-btn) {
@apply border-0 !text-xs font-semibold px-2;
}
</style>

4
packages/nc-gui-v2/components/tabs/Smartsheet.vue

@ -47,11 +47,9 @@ watch(
<SmartsheetGallery v-else-if="activeView.type === ViewTypes.GALLERY" /> <SmartsheetGallery v-else-if="activeView.type === ViewTypes.GALLERY" />
<SmartsheetForm v-else-if="activeView.type === ViewTypes.FORM" /> <SmartsheetForm v-else-if="activeView.type === ViewTypes.FORM" />
</div> </div>
<SmartsheetSidebar />
</div> </div>
</template> </template>
</div> </div>
<template v-if="meta">
<SmartsheetSidebar />
</template>
</div> </div>
</template> </template>

Loading…
Cancel
Save