mirror of https://github.com/nocodb/nocodb
Braks
2 years ago
committed by
GitHub
19 changed files with 323 additions and 316 deletions
@ -1,149 +0,0 @@ |
|||||||
<script setup lang="ts"> |
|
||||||
import useTabs from '~/composables/useTabs' |
|
||||||
import MdiPlusIcon from '~icons/mdi/plus' |
|
||||||
import MdiTableIcon from '~icons/mdi/table' |
|
||||||
import MdiCsvIcon from '~icons/mdi/file-document-outline' |
|
||||||
import MdiExcelIcon from '~icons/mdi/file-excel' |
|
||||||
import MdiJSONIcon from '~icons/mdi/code-json' |
|
||||||
import MdiAirTableIcon from '~icons/mdi/table-large' |
|
||||||
import MdiRequestDataSourceIcon from '~icons/mdi/open-in-new' |
|
||||||
import MdiAccountGroupIcon from '~icons/mdi/account-group' |
|
||||||
|
|
||||||
const { tabs, activeTab, closeTab } = useTabs() |
|
||||||
const { isUIAllowed } = useUIPermission() |
|
||||||
const tableCreateDialog = ref(false) |
|
||||||
const airtableImportDialog = ref(false) |
|
||||||
const quickImportDialog = ref(false) |
|
||||||
const importType = ref('') |
|
||||||
const currentMenu = ref<string[]>(['addORImport']) |
|
||||||
|
|
||||||
function onEdit(targetKey: number, action: string) { |
|
||||||
if (action !== 'add') { |
|
||||||
closeTab(targetKey) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function openQuickImportDialog(type: string) { |
|
||||||
quickImportDialog.value = true |
|
||||||
importType.value = type |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<a-tabs v-model:activeKey="activeTab" hide-add type="editable-card" :tab-position="top" @edit="onEdit"> |
|
||||||
<a-tab-pane v-for="(tab, i) in tabs" :key="i" :value="i" class="text-capitalize" :closable="true"> |
|
||||||
<template #tab> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiAccountGroupIcon v-if="tab.type === 'auth'" class="text-primary" /> |
|
||||||
<MdiTableIcon v-else class="text-primary" /> |
|
||||||
{{ tab.title }} |
|
||||||
</span> |
|
||||||
</template> |
|
||||||
</a-tab-pane> |
|
||||||
<template #leftExtra> |
|
||||||
<a-menu v-model:selectedKeys="currentMenu" mode="horizontal"> |
|
||||||
<a-sub-menu key="addORImport"> |
|
||||||
<template #title> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiPlusIcon /> |
|
||||||
Add / Import |
|
||||||
</span> |
|
||||||
</template> |
|
||||||
<a-menu-item-group v-if="isUIAllowed('addTable')"> |
|
||||||
<a-menu-item key="add-new-table" v-t="['a:actions:create-table']" @click="tableCreateDialog = true"> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiTableIcon class="text-primary" /> |
|
||||||
<!-- Add new table --> |
|
||||||
{{ $t('tooltip.addTable') }} |
|
||||||
</span> |
|
||||||
</a-menu-item> |
|
||||||
</a-menu-item-group> |
|
||||||
<a-menu-item-group title="QUICK IMPORT FROM"> |
|
||||||
<a-menu-item |
|
||||||
v-if="isUIAllowed('airtableImport')" |
|
||||||
key="quick-import-airtable" |
|
||||||
v-t="['a:actions:import-airtable']" |
|
||||||
@click="airtableImportDialog = true" |
|
||||||
> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiAirTableIcon class="text-primary" /> |
|
||||||
<!-- TODO: i18n --> |
|
||||||
Airtable |
|
||||||
</span> |
|
||||||
</a-menu-item> |
|
||||||
<a-menu-item |
|
||||||
v-if="isUIAllowed('csvImport')" |
|
||||||
key="quick-import-csv" |
|
||||||
v-t="['a:actions:import-csv']" |
|
||||||
@click="openQuickImportDialog('csv')" |
|
||||||
> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiCsvIcon class="text-primary" /> |
|
||||||
<!-- TODO: i18n --> |
|
||||||
CSV file |
|
||||||
</span> |
|
||||||
</a-menu-item> |
|
||||||
<a-menu-item |
|
||||||
v-if="isUIAllowed('jsonImport')" |
|
||||||
key="quick-import-json" |
|
||||||
v-t="['a:actions:import-json']" |
|
||||||
@click="openQuickImportDialog('json')" |
|
||||||
> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiJSONIcon class="text-primary" /> |
|
||||||
<!-- TODO: i18n --> |
|
||||||
JSON file |
|
||||||
</span> |
|
||||||
</a-menu-item> |
|
||||||
<a-menu-item |
|
||||||
v-if="isUIAllowed('excelImport')" |
|
||||||
key="quick-import-excel" |
|
||||||
v-t="['a:actions:import-excel']" |
|
||||||
@click="openQuickImportDialog('excel')" |
|
||||||
> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiExcelIcon class="text-primary" /> |
|
||||||
<!-- TODO: i18n --> |
|
||||||
Microsoft Excel |
|
||||||
</span> |
|
||||||
</a-menu-item> |
|
||||||
</a-menu-item-group> |
|
||||||
<a-divider class="ma-0 mb-2" /> |
|
||||||
<a-menu-item |
|
||||||
v-if="isUIAllowed('importRequest')" |
|
||||||
key="add-new-table" |
|
||||||
v-t="['e:datasource:import-request']" |
|
||||||
class="ma-0 mt-3" |
|
||||||
> |
|
||||||
<a href="https://github.com/nocodb/nocodb/issues/2052" target="_blank" class="prose-sm pa-0"> |
|
||||||
<span class="flex items-center gap-2"> |
|
||||||
<MdiRequestDataSourceIcon class="text-primary" /> |
|
||||||
<!-- TODO: i18n --> |
|
||||||
Request a data source you need? |
|
||||||
</span> |
|
||||||
</a> |
|
||||||
</a-menu-item> |
|
||||||
</a-sub-menu> |
|
||||||
</a-menu> |
|
||||||
</template> |
|
||||||
</a-tabs> |
|
||||||
|
|
||||||
<DlgTableCreate v-if="tableCreateDialog" v-model="tableCreateDialog" /> |
|
||||||
<DlgQuickImport v-if="quickImportDialog" v-model="quickImportDialog" :import-type="importType" /> |
|
||||||
<DlgAirtableImport v-if="airtableImportDialog" v-model="airtableImportDialog" /> |
|
||||||
|
|
||||||
<v-window v-model="activeTab"> |
|
||||||
<v-window-item v-for="(tab, i) in tabs" :key="i" :value="i"> |
|
||||||
<TabsAuth v-if="tab.type === 'auth'" :tab-meta="tab" /> |
|
||||||
<TabsSmartsheet v-else :tab-meta="tab" /> |
|
||||||
</v-window-item> |
|
||||||
</v-window> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<style scoped lang="scss"> |
|
||||||
:deep(.ant-menu-item-group-list) .ant-menu-item { |
|
||||||
@apply m-0 pa-0 pl-4 pr-16; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,10 +1,15 @@ |
|||||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||||
import MdiAddIcon from '~icons/mdi/plus-outline' |
import MdiAddIcon from '~icons/mdi/plus-outline' |
||||||
const emit = defineEmits(['add-row']) |
|
||||||
|
const emits = defineEmits(['addRow']) |
||||||
</script> |
</script> |
||||||
|
|
||||||
<template> |
<template> |
||||||
<MdiAddIcon class="text-grey" @click="emit('add-row')" /> |
<a-tooltip placement="left"> |
||||||
</template> |
<template #title> {{ $t('activity.addRow') }} </template> |
||||||
|
|
||||||
<style scoped></style> |
<div class="nc-sidebar-right-item hover:after:bg-primary/75 group"> |
||||||
|
<MdiAddIcon class="group-hover:(!text-white)" @click="emits('addRow')" /> |
||||||
|
</div> |
||||||
|
</a-tooltip> |
||||||
|
</template> |
||||||
|
@ -1,11 +1,18 @@ |
|||||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||||
import { ReloadViewDataHookInj } from '~/context' |
import { ReloadViewDataHookInj } from '~/context' |
||||||
import MdiReloadIcon from '~icons/mdi/reload' |
import MdiReloadIcon from '~icons/mdi/reload' |
||||||
|
|
||||||
const reloadTri = inject(ReloadViewDataHookInj) |
const reloadTri = inject(ReloadViewDataHookInj) |
||||||
</script> |
</script> |
||||||
|
|
||||||
<template> |
<template> |
||||||
<MdiReloadIcon class="text-grey" @click="reloadTri.trigger()" /> |
<a-tooltip placement="left"> |
||||||
|
<template #title> {{ $t('general.reload') }} </template> |
||||||
|
|
||||||
|
<div class="nc-sidebar-right-item hover:after:bg-green-500 group"> |
||||||
|
<MdiReloadIcon class="group-hover:(!text-white)" @click="reloadTri.trigger()" /> |
||||||
|
</div> |
||||||
|
</a-tooltip> |
||||||
</template> |
</template> |
||||||
|
|
||||||
<style scoped></style> |
<style scoped></style> |
||||||
|
@ -1,14 +1,14 @@ |
|||||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||||
import MdiDoorOpenIcon from '~icons/mdi/door-open' |
import MdiMenuClose from '~icons/mdi/menu-close' |
||||||
import MdiDoorClosedIcon from '~icons/mdi/door-closed' |
|
||||||
|
|
||||||
const drawerOpen = inject('navDrawerOpen', ref(false)) |
const drawerOpen = inject('navDrawerOpen', ref(false)) |
||||||
const Icon = computed(() => (drawerOpen.value ? MdiDoorOpenIcon : MdiDoorClosedIcon)) |
|
||||||
</script> |
</script> |
||||||
|
|
||||||
<template> |
<template> |
||||||
<a-tooltip placement="left"> |
<a-tooltip placement="left"> |
||||||
<template #title> {{ $t('tooltip.toggleNavDraw') }} </template> |
<template #title> {{ $t('tooltip.toggleNavDraw') }} </template> |
||||||
<Icon class="rounded text-xl p-1 text-gray-500 hover:(text-white bg-pink-500 shadow)" @click="drawerOpen = !drawerOpen" /> |
<div class="nc-sidebar-right-item hover:after:bg-pink-500 group"> |
||||||
|
<MdiMenuClose class="group-hover:(!text-white)" @click="drawerOpen = !drawerOpen" /> |
||||||
|
</div> |
||||||
</a-tooltip> |
</a-tooltip> |
||||||
</template> |
</template> |
||||||
|
@ -0,0 +1,35 @@ |
|||||||
|
<template> |
||||||
|
<div class="flex gap-2"> |
||||||
|
<slot name="start" /> |
||||||
|
|
||||||
|
<SmartsheetToolbarLockMenu /> |
||||||
|
|
||||||
|
<div class="dot" /> |
||||||
|
|
||||||
|
<SmartsheetToolbarReload /> |
||||||
|
|
||||||
|
<div class="dot" /> |
||||||
|
|
||||||
|
<SmartsheetToolbarAddRow /> |
||||||
|
|
||||||
|
<div class="dot" /> |
||||||
|
|
||||||
|
<SmartsheetToolbarDeleteTable /> |
||||||
|
|
||||||
|
<div class="dot" /> |
||||||
|
|
||||||
|
<SmartsheetToolbarToggleDrawer /> |
||||||
|
|
||||||
|
<slot name="end" /> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
:deep(.nc-toolbar-btn) { |
||||||
|
@apply border-0 !text-xs font-semibold px-2; |
||||||
|
} |
||||||
|
|
||||||
|
.dot { |
||||||
|
@apply w-[3px] h-[3px] bg-gray-300 rounded-full; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,63 @@ |
|||||||
|
import type { AxiosError, AxiosResponse } from 'axios' |
||||||
|
import type { Api } from 'nocodb-sdk' |
||||||
|
import type { Ref } from 'vue' |
||||||
|
import type { EventHook } from '@vueuse/core' |
||||||
|
import { createEventHook, ref, useNuxtApp } from '#imports' |
||||||
|
|
||||||
|
interface UseApiReturn<D = any, R = any> { |
||||||
|
api: Api<any> |
||||||
|
isLoading: Ref<boolean> |
||||||
|
error: Ref<AxiosError<D, R> | null> |
||||||
|
response: Ref<AxiosResponse<D, R> | null> |
||||||
|
onError: EventHook<AxiosError<D, R>>['on'] |
||||||
|
onResponse: EventHook<AxiosResponse<D, R>>['on'] |
||||||
|
} |
||||||
|
|
||||||
|
/** todo: add props? */ |
||||||
|
type UseApiProps = never |
||||||
|
|
||||||
|
export function useApi<Data = any, RequestConfig = any>(_?: UseApiProps): UseApiReturn<Data, RequestConfig> { |
||||||
|
const isLoading = ref(false) |
||||||
|
|
||||||
|
const error = ref(null) |
||||||
|
|
||||||
|
const response = ref<any>(null) |
||||||
|
|
||||||
|
const errorHook = createEventHook<AxiosError<Data, RequestConfig>>() |
||||||
|
|
||||||
|
const responseHook = createEventHook<AxiosResponse<Data, RequestConfig>>() |
||||||
|
|
||||||
|
const { $api } = useNuxtApp() |
||||||
|
|
||||||
|
$api.instance.interceptors.request.use( |
||||||
|
(config) => { |
||||||
|
error.value = null |
||||||
|
response.value = null |
||||||
|
isLoading.value = true |
||||||
|
|
||||||
|
return config |
||||||
|
}, |
||||||
|
(requestError) => { |
||||||
|
errorHook.trigger(requestError) |
||||||
|
error.value = requestError |
||||||
|
response.value = null |
||||||
|
isLoading.value = false |
||||||
|
}, |
||||||
|
) |
||||||
|
|
||||||
|
$api.instance.interceptors.response.use( |
||||||
|
(apiResponse) => { |
||||||
|
responseHook.trigger(apiResponse as AxiosResponse<Data, RequestConfig>) |
||||||
|
// can't properly typecast
|
||||||
|
response.value = apiResponse |
||||||
|
isLoading.value = false |
||||||
|
}, |
||||||
|
(apiError) => { |
||||||
|
errorHook.trigger(apiError) |
||||||
|
error.value = apiError |
||||||
|
isLoading.value = false |
||||||
|
}, |
||||||
|
) |
||||||
|
|
||||||
|
return { api: $api, isLoading, response, error, onError: errorHook.on, onResponse: responseHook.on } |
||||||
|
} |
Loading…
Reference in new issue