Browse Source

Merge pull request #3130 from nocodb/feat/gui-v2-misc

feat(gui-v2): misc
pull/3153/head
Raju Udava 2 years ago committed by GitHub
parent
commit
dd31a0f40e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui-v2/components.d.ts
  2. 9
      packages/nc-gui-v2/components/dashboard/GithubStarButton.vue
  3. 7
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  4. 73
      packages/nc-gui-v2/components/general/SocialCard.vue
  5. 49
      packages/nc-gui-v2/components/general/Sponsors.vue
  6. 22
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/DeleteCache.vue
  7. 33
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/ExportCache.vue
  8. 29
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue
  9. 24
      packages/nc-gui-v2/layouts/base.vue
  10. 27
      packages/nc-gui-v2/package-lock.json
  11. 1
      packages/nc-gui-v2/package.json
  12. 198
      packages/nc-gui-v2/pages/index/index.vue

2
packages/nc-gui-v2/components.d.ts vendored

@ -102,6 +102,7 @@ declare module '@vue/runtime-core' {
MdiCloseThick: typeof import('~icons/mdi/close-thick')['default']
MdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
MdiContentSave: typeof import('~icons/mdi/content-save')['default']
MdiDelete: typeof import('~icons/mdi/delete')['default']
MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
MdiDiscord: typeof import('~icons/mdi/discord')['default']
MdiDotsHorizontal: typeof import('~icons/mdi/dots-horizontal')['default']
@ -113,6 +114,7 @@ declare module '@vue/runtime-core' {
MdiEmail: typeof import('~icons/mdi/email')['default']
MdiEmailArrowRightOutline: typeof import('~icons/mdi/email-arrow-right-outline')['default']
MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['default']
MdiExport: typeof import('~icons/mdi/export')['default']
MdiEyeOffOutline: typeof import('~icons/mdi/eye-off-outline')['default']
MdiFlag: typeof import('~icons/mdi/flag')['default']
MdiFolder: typeof import('~icons/mdi/folder')['default']

9
packages/nc-gui-v2/components/dashboard/GithubStarButton.vue

@ -0,0 +1,9 @@
<script setup lang="ts">
import GithubButton from 'vue-github-button'
</script>
<template>
<GithubButton href="https://github.com/nocodb/nocodb" data-icon="octicon-star" :data-show-count="true" data-size="large"
>Star</GithubButton
>
</template>

7
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -9,6 +9,7 @@ import MdiView from '~icons/mdi/eye-circle-outline'
import MdiTableLarge from '~icons/mdi/table-large'
import MdiMenuIcon from '~icons/mdi/dots-vertical'
import MdiDrag from '~icons/mdi/drag-vertical'
import GithubStarButton from '~/components/dashboard/GithubStarButton.vue'
const { addTab } = useTabs()
@ -266,6 +267,12 @@ const activeTable = computed(() => {
</template>
</a-dropdown>
<a-divider class="mt-0 mb-2" />
<div class="items-center flex justify-center mb-1">
<GithubStarButton />
</div>
<DlgTableCreate v-if="tableCreateDlg" v-model="tableCreateDlg" />
<DlgTableRename v-if="renameTableMeta" v-model="renameTableDlg" :table-meta="renameTableMeta" />
</div>

73
packages/nc-gui-v2/components/general/SocialCard.vue

@ -0,0 +1,73 @@
<script setup lang="ts">
import { enumColor as colors } from '#imports'
const { lang: currentLang } = useGlobal()
const isRtlLang = $computed(() => ['fa'].includes(currentLang.value))
</script>
<template>
<a-list class="w-[300px] pa-3 elevation-4 rounded-xl mr-10" dense>
<a-list-item class="cursor-pointer">
<nuxt-link class="text-primary" to="https://github.com/nocodb/nocodb" target="_blank">
<div class="flex items-center text-sm">
<mdi-github class="mx-3 text-lg" />
<div v-if="isRtlLang">
<!-- us on Github -->
{{ $t('labels.community.starUs2') }}
<!-- Star -->
{{ $t('labels.community.starUs1') }}
<mdi-star-outline />
</div>
<div v-else class="flex items-center">
<!-- Star -->
{{ $t('labels.community.starUs1') }}
<mdi-star-outline class="mx-1" />
<!-- us on Github -->
{{ $t('labels.community.starUs2') }}
</div>
</div>
</nuxt-link>
</a-list-item>
<a-list-item>
<nuxt-link class="text-primary" to="https://calendly.com/nocodb-meeting" target="_blank">
<div class="flex items-center text-sm">
<mdi-calendar-month class="mx-3 text-lg" :color="colors.dark[3 % colors.dark.length]" />
<!-- Book a Free DEMO -->
<div>
{{ $t('labels.community.bookDemo') }}
</div>
</div>
</nuxt-link>
</a-list-item>
<a-list-item>
<nuxt-link class="text-primary" to="https://discord.gg/5RgZmkW" target="_blank">
<div class="flex items-center text-sm">
<mdi-discord class="mx-3 text-lg" :color="colors.dark[0 % colors.dark.length]" />
<!-- Get your questions answered -->
<div>
{{ $t('labels.community.getAnswered') }}
</div>
</div>
</nuxt-link>
</a-list-item>
<a-list-item>
<nuxt-link class="text-primary" to="https://twitter.com/NocoDB" target="_blank">
<div class="flex items-center text-sm">
<mdi-twitter class="mx-3 text-lg" :color="colors.dark[1 % colors.dark.length]" />
<!-- Follow NocoDB -->
<div>
{{ $t('labels.community.followNocodb') }}
</div>
</div>
</nuxt-link>
</a-list-item>
<a-list-item v-t="['e:hiring']">
<nuxt-link class="text-primary" target="_blank" to="http://careers.nocodb.com">
<div class="flex items-center text-sm">
<div class="ml-3">🚀 <span class="ml-2">We are Hiring!!!</span></div>
</div>
</nuxt-link>
</a-list-item>
</a-list>
</template>

49
packages/nc-gui-v2/components/general/Sponsors.vue

@ -1,37 +1,38 @@
<script lang="ts" setup>
import MdiHeartsCard from '~icons/mdi/cards-heart'
interface Props {
nav?: boolean
img?: boolean
}
const { nav = false, img = true } = defineProps<Props>()
const { nav = false } = defineProps<Props>()
</script>
<template>
<v-card :rounded="0" class="dark:bg-gray-900" href="https://github.com/sponsors/nocodb" target="_blank">
<v-img v-if="img" src="/ants-leaf-cutter.jpeg" :cover="true" :aspect-ratio="1" :height="nav ? 80 : ''" />
<a-card class="w-[300px] ma-10 shadow-lg rounded-lg">
<template #cover>
<img class="max-h-[180px]" alt="cover" src="/ants-leaf-cutter.jpeg" />
</template>
<v-card-title v-if="!nav" class="pb-2">
{{ $t('msg.info.sponsor.header') }}
</v-card-title>
<a-card-meta>
<template #title>
<span v-if="!nav" class="text-xl pb-4">
{{ $t('msg.info.sponsor.header') }}
</span>
</template>
</a-card-meta>
<v-card-text v-if="!nav" class="pb-0">
<div v-if="!nav" class="py-5 text-sm">
{{ $t('msg.info.sponsor.message') }}
</v-card-text>
</div>
<v-card-actions class="justify-center">
<v-btn color="primary" class="dark:(!text-white)">
<MdiHeartsCard class="text-red-500 mr-2" />
{{ $t('activity.sponsorUs') }}
</v-btn>
</v-card-actions>
</v-card>
<div class="flex justify-center">
<nuxt-link href="https://github.com/sponsors/nocodb" target="_blank">
<a-button class="!shadow" size="large">
<div class="flex items-center">
<mdi-cards-heart class="text-red-500 mr-2" />
{{ $t('activity.sponsorUs') }}
</div>
</a-button>
</nuxt-link>
</div>
</a-card>
</template>
<style>
a img {
margin: 0 !important;
}
</style>

22
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/DeleteCache.vue

@ -0,0 +1,22 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
const { api } = useApi()
async function deleteCache() {
try {
await api.utils.cacheDelete()
message.info('Deleted Cache Successfully')
} catch (e: any) {
message.error(e.message)
}
}
</script>
<template>
<a-tooltip>
<template #title>
<span> Delete Cache </span>
</template>
<mdi-delete class="cursor-pointer mx-3" @click="deleteCache" />
</a-tooltip>
</template>

33
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/ExportCache.vue

@ -0,0 +1,33 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import FileSaver from 'file-saver'
const { api } = useApi()
async function exportCache() {
try {
const data = await api.utils.cacheGet()
if (!data) {
message.info('Cache is empty')
return
}
const blob = new Blob([JSON.stringify(data)], {
type: 'text/plain;charset=utf-8',
})
FileSaver.saveAs(blob, 'cache_exported.json')
message.info('Exported Cache Successfully')
} catch (e: any) {
message.error(e.message)
}
}
</script>
<template>
<!-- Export Cache -->
<a-tooltip>
<template #title>
<span> Export Cache </span>
</template>
<mdi-export class="cursor-pointer mx-3" @click="exportCache" />
</a-tooltip>
</template>

29
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue

@ -2,14 +2,41 @@
import AddRow from './AddRow.vue'
import LockMenu from './LockMenu.vue'
import Reload from './Reload.vue'
import ExportCache from './ExportCache.vue'
import DeleteCache from './DeleteCache.vue'
const { isUIAllowed } = useUIPermission()
const debug = $ref(false)
const clickCount = $ref(0)
</script>
<template>
<div class="flex gap-2">
<div
class="flex gap-2"
@click="
() => {
clickCount = clickCount + 1
debug = clickCount >= 4
}
"
>
<slot name="start" />
<template v-if="debug">
<ExportCache />
<div class="dot" />
<DeleteCache />
<div class="dot" />
<!-- TODO: -->
<!-- <debug-metas v-if="debug" class="mr-3" /> -->
</template>
<LockMenu v-if="isUIAllowed('view-type')" />
<div v-if="isUIAllowed('view-type')" class="dot" />

24
packages/nc-gui-v2/layouts/base.vue

@ -10,6 +10,10 @@ const route = useRoute()
const email = computed(() => user.value?.email ?? '---')
const { isUIAllowed } = useUIPermission()
const showUserModal = $ref(false)
const logout = () => {
signOut()
navigateTo('/signin')
@ -43,7 +47,23 @@ const logout = () => {
<div class="flex-1" />
<a-tooltip placement="left">
<div class="flex items-center mr-4">
<a-button
v-if="isUIAllowed('newUser')"
size="middle"
type="primary"
class="!bg-white !text-primary rounded"
@click="showUserModal = true"
>
<div class="flex items-center space-x-1">
<mdi-account-supervisor-outline class="mr-1" />
<div>{{ $t('activity.share') }}</div>
</div>
</a-button>
<TabsAuthUserManagementUsersModal :key="showUserModal" :show="showUserModal" @closed="showUserModal = false" />
</div>
<a-tooltip placement="bottom">
<template #title> Switch language </template>
<div class="flex pr-4 items-center">
@ -83,7 +103,7 @@ const logout = () => {
</a-layout-header>
</Transition>
<a-tooltip>
<a-tooltip placement="bottom">
<template #title> Switch language </template>
<Transition name="layout">

27
packages/nc-gui-v2/package-lock.json generated

@ -23,6 +23,7 @@
"url": "^0.11.0",
"util": "^0.12.4",
"vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.1.10",
"vuedraggable": "^4.1.0",
"vuetify": "^3.0.0-alpha.13",
@ -7596,6 +7597,11 @@
"git-up": "^4.0.0"
}
},
"node_modules/github-buttons": {
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz",
"integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw=="
},
"node_modules/github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@ -14596,6 +14602,14 @@
"node": ">=4.0"
}
},
"node_modules/vue-github-button": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-3.0.3.tgz",
"integrity": "sha512-O2Kv5HxRMn1qqgt2sSy8N7y2C6WGOeICzgGj6y+JFcnLjorTTzNR8vY5abiPOYDiW03WZ/9hUIn7Gm9CG9pIuA==",
"dependencies": {
"github-buttons": "^2.21.1"
}
},
"node_modules/vue-i18n": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",
@ -20865,6 +20879,11 @@
"git-up": "^4.0.0"
}
},
"github-buttons": {
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz",
"integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw=="
},
"github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@ -26088,6 +26107,14 @@
}
}
},
"vue-github-button": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-3.0.3.tgz",
"integrity": "sha512-O2Kv5HxRMn1qqgt2sSy8N7y2C6WGOeICzgGj6y+JFcnLjorTTzNR8vY5abiPOYDiW03WZ/9hUIn7Gm9CG9pIuA==",
"requires": {
"github-buttons": "^2.21.1"
}
},
"vue-i18n": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",

1
packages/nc-gui-v2/package.json

@ -30,6 +30,7 @@
"url": "^0.11.0",
"util": "^0.12.4",
"vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.1.10",
"vuedraggable": "^4.1.0",
"vuetify": "^3.0.0-alpha.13",

198
packages/nc-gui-v2/pages/index/index.vue

@ -61,97 +61,113 @@ onMounted(() => {
<template>
<NuxtLayout>
<a-card class="mx-auto mt-10 !max-w-[600px] shadow-lg">
<h1 class="text-center text-4xl pa-2 nc-project-page-title flex align-center justify-center gap-2 text-gray-600">
<!-- My Projects -->
<b>{{ $t('title.myProject') }}</b>
<MdiRefresh
v-t="['a:project:refresh']"
class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer"
@click="loadProjects"
></MdiRefresh>
</h1>
<div class="flex mb-6">
<a-input-search
v-model:value="filterQuery"
class="max-w-[200px] nc-project-page-search"
:placeholder="$t('activity.searchProject')"
></a-input-search>
<div class="flex-grow"></div>
<a-dropdown v-if="isUIAllowed('projectCreate', true)" @click.stop>
<a-button class="nc-new-project-menu !shadow">
<div class="flex align-center">
{{ $t('title.newProj') }}
<MdiMenuDown class="menu-icon" />
</div>
</a-button>
<template #overlay>
<a-menu>
<div
v-t="['c:project:create:xcdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-xc-db-project"
@click="navigateTo('/project/create')"
>
<MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div>
<div
v-t="['c:project:create:extdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project"
@click="navigateTo('/project/create-external')"
>
<MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div>
</a-menu>
</template>
</a-dropdown>
</div>
<div v-if="isLoading">
<a-skeleton />
</div>
<a-table
v-else
:custom-row="
(record) => ({
onClick: () => {
$e('a:project:open')
navigateTo(`/nc/${record.id}`)
},
})
"
:data-source="filteredProjects"
:pagination="{ position: ['bottomCenter'] }"
>
<!-- Title -->
<a-table-column key="title" :title="$t('general.title')" data-index="title">
<template #default="{ text }">
<div class="capitalize !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap nc-project-row" :title="text">
{{ text }}
</div>
</template>
</a-table-column>
<!-- Actions -->
<a-table-column key="id" :title="$t('labels.actions')" data-index="id">
<template #default="{ text, record }">
<div class="flex align-center">
<MdiEditOutline
v-t="['c:project:edit:rename']"
class="nc-action-btn"
@click.stop="navigateTo(`/project/${text}`)"
/>
<MdiDeleteOutline class="nc-action-btn" @click.stop="deleteProject(record)" />
</div>
</template>
</a-table-column>
</a-table>
</a-card>
<a-row>
<a-col :span="8"></a-col>
<a-col :span="8" class="!bg-red">
<a-card class="mx-auto mt-10 !max-w-[600px] shadow-lg">
<h1 class="text-center text-4xl pa-2 nc-project-page-title flex align-center justify-center gap-2 text-gray-600">
<!-- My Projects -->
<b>{{ $t('title.myProject') }}</b>
<MdiRefresh
v-t="['a:project:refresh']"
class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer"
@click="loadProjects"
></MdiRefresh>
</h1>
<div class="flex mb-6">
<a-input-search
v-model:value="filterQuery"
class="max-w-[200px] nc-project-page-search"
:placeholder="$t('activity.searchProject')"
></a-input-search>
<div class="flex-grow"></div>
<a-dropdown v-if="isUIAllowed('projectCreate', true)" @click.stop>
<a-button class="nc-new-project-menu !shadow">
<div class="flex align-center">
{{ $t('title.newProj') }}
<MdiMenuDown class="menu-icon" />
</div>
</a-button>
<template #overlay>
<a-menu>
<div
v-t="['c:project:create:xcdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-xc-db-project"
@click="navigateTo('/project/create')"
>
<MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div>
<div
v-t="['c:project:create:extdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project"
@click="navigateTo('/project/create-external')"
>
<MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div>
</a-menu>
</template>
</a-dropdown>
</div>
<div v-if="isLoading">
<a-skeleton />
</div>
<a-table
v-else
:custom-row="
(record) => ({
onClick: () => {
$e('a:project:open')
navigateTo(`/nc/${record.id}`)
},
})
"
:data-source="filteredProjects"
:pagination="{ position: ['bottomCenter'] }"
>
<!-- Title -->
<a-table-column key="title" :title="$t('general.title')" data-index="title">
<template #default="{ text }">
<div
class="capitalize !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap nc-project-row"
:title="text"
>
{{ text }}
</div>
</template>
</a-table-column>
<!-- Actions -->
<a-table-column key="id" :title="$t('labels.actions')" data-index="id">
<template #default="{ text, record }">
<div class="flex align-center">
<MdiEditOutline
v-t="['c:project:edit:rename']"
class="nc-action-btn"
@click.stop="navigateTo(`/project/${text}`)"
/>
<MdiDeleteOutline class="nc-action-btn" @click.stop="deleteProject(record)" />
</div>
</template>
</a-table-column>
</a-table>
</a-card>
</a-col>
<a-col :span="8" class="">
<div class="justify-end flex">
<GeneralSponsors />
</div>
<div class="justify-end flex">
<GeneralSocialCard />
</div>
</a-col>
</a-row>
</NuxtLayout>
</template>

Loading…
Cancel
Save