Browse Source

feat: details page for extensions

nc-feat/extensions
mertmit 8 months ago
parent
commit
17511f8c11
  1. 110
      packages/nc-gui/components/extensions/Details.vue
  2. 9
      packages/nc-gui/components/extensions/Extension.vue
  3. 11
      packages/nc-gui/components/extensions/Market.vue
  4. 10
      packages/nc-gui/components/extensions/Pane.vue
  5. 19
      packages/nc-gui/composables/useExtensions.ts
  6. 2
      packages/nc-gui/extensions/csv-import/manifest.json

110
packages/nc-gui/components/extensions/Details.vue

@ -0,0 +1,110 @@
<script lang="ts" setup>
import { useVModel } from '#imports'
interface Prop {
modelValue: boolean
extensionId: string
from: 'market' | 'extension'
}
const props = defineProps<Prop>()
const emit = defineEmits(['update:modelValue'])
const vModel = useVModel(props, 'modelValue', emit)
const { availableExtensions, addExtension, getExtensionIcon, isMarketVisible } = useExtensions()
const onBack = () => {
vModel.value = false
isMarketVisible.value = true
}
const onAddExtension = (ext: any) => {
addExtension(ext)
vModel.value = false
}
const activeExtension = computed(() => {
return availableExtensions.value.find((ext) => ext.id === props.extensionId)
})
</script>
<template>
<NcModal
v-model:visible="vModel"
:body-style="{ 'max-height': '864px', 'height': '85vh' }"
:class="{ active: vModel }"
:closable="from === 'extension'"
:footer="null"
:width="1280"
size="medium"
wrap-class-name="nc-modal-extension-market"
>
<div v-if="activeExtension" class="flex flex-col w-full h-full">
<div v-if="from === 'market'" class="h-[40px] flex items-start">
<div class="flex items-center gap-2 pr-2 pb-2 cursor-pointer hover:text-primary" @click="onBack">
<GeneralIcon icon="ncArrowLeft" />
<span>Back</span>
</div>
</div>
<div v-else class="h-[40px]"></div>
<div class="extension-details">
<div class="extension-details-left">
<div class="flex">
<img :src="getExtensionIcon(activeExtension.iconUrl)" alt="icon" class="h-[90px]" />
<div class="flex flex-col p-4">
<div class="font-weight-700 text-2xl">{{ activeExtension.title }}</div>
</div>
</div>
<div class="p-4">
<div class="whitespace-pre-line">{{ activeExtension.description }}</div>
</div>
</div>
<div class="extension-details-right">
<NcButton class="w-full" @click="onAddExtension(activeExtension)">
<div class="flex items-center justify-center">Add Extension</div>
</NcButton>
<div class="flex flex-col gap-1">
<div class="text-md font-weight-600">Version</div>
<div>{{ activeExtension.version }}</div>
</div>
<div class="flex flex-col gap-1">
<div v-if="activeExtension.publisherName" class="text-md font-weight-600">Publisher</div>
<div>{{ activeExtension.publisherName }}</div>
</div>
<div v-if="activeExtension.publisherEmail" class="flex flex-col gap-1">
<div class="text-md font-weight-600">Publisher Email</div>
<div>
<a :href="`mailto:${activeExtension.publisherEmail}`" target="_blank" rel="noopener noreferrer">
{{ activeExtension.publisherEmail }}
</a>
</div>
</div>
<div v-if="activeExtension.publisherUrl" class="flex flex-col gap-1">
<div class="text-md font-weight-600">Publisher Website</div>
<div>
<a :href="activeExtension.publisherUrl" target="_blank" rel="noopener noreferrer">
{{ activeExtension.publisherUrl }}
</a>
</div>
</div>
</div>
</div>
</div>
</NcModal>
</template>
<style lang="scss" scoped>
.extension-details {
@apply flex w-full h-full;
.extension-details-left {
@apply flex flex-col w-3/4 p-2;
}
.extension-details-right {
@apply w-1/4 p-2 flex flex-col gap-4;
}
}
</style>

9
packages/nc-gui/components/extensions/Extension.vue

@ -6,7 +6,8 @@ interface Prop {
const { extensionId, error } = defineProps<Prop>()
const { extensionList, extensionsLoaded, availableExtensions, getExtensionIcon, duplicateExtension } = useExtensions()
const { extensionList, extensionsLoaded, availableExtensions, getExtensionIcon, duplicateExtension, showExtensionDetails } =
useExtensions()
const activeError = ref(error)
@ -120,7 +121,11 @@ const closeFullscreen = (e: MouseEvent) => {
<GeneralIcon icon="duplicate" />
Duplicate
</NcMenuItem>
<NcMenuItem data-rec="true" class="!hover:text-primary">
<NcMenuItem
data-rec="true"
class="!hover:text-primary"
@click="showExtensionDetails(extension.extensionId, 'extension')"
>
<GeneralIcon icon="info" />
Details
</NcMenuItem>

11
packages/nc-gui/components/extensions/Market.vue

@ -11,7 +11,12 @@ const emit = defineEmits(['update:modelValue'])
const vModel = useVModel(props, 'modelValue', emit)
const { availableExtensions, addExtension, getExtensionIcon } = useExtensions()
const { availableExtensions, addExtension, getExtensionIcon, showExtensionDetails } = useExtensions()
const onExtensionClick = (extensionId: string) => {
showExtensionDetails(extensionId)
vModel.value = false
}
const onAddExtension = (ext: any) => {
addExtension(ext)
@ -40,14 +45,14 @@ const onAddExtension = (ext: any) => {
<div class="flex flex-col flex-1 px-4 py-2">
<div class="flex flex-wrap gap-4 p-2">
<template v-for="ext of availableExtensions" :key="ext.id">
<div class="flex border-1 rounded-lg p-2 w-[360px] cursor-pointer">
<div class="flex border-1 rounded-lg p-2 w-[360px] cursor-pointer" @click="onExtensionClick(ext.id)">
<div class="h-[60px] overflow-hidden m-auto">
<img :src="getExtensionIcon(ext.iconUrl)" alt="icon" class="w-full h-full object-cover" />
</div>
<div class="flex flex-grow flex-col ml-3">
<div class="flex justify-between">
<div class="font-weight-600">{{ ext.title }}</div>
<NcButton size="xsmall" @click="onAddExtension(ext)">
<NcButton size="xsmall" @click.stop="onAddExtension(ext)">
<div class="flex items-center gap-1 mx-1">
<GeneralIcon icon="plus" />
Add

10
packages/nc-gui/components/extensions/Pane.vue

@ -2,9 +2,7 @@
import { Pane } from 'splitpanes'
import 'splitpanes/dist/splitpanes.css'
const { extensionList, isPanelExpanded } = useExtensions()
const isMarketVisible = ref(false)
const { extensionList, isPanelExpanded, isDetailsVisible, detailsExtensionId, detailsFrom, isMarketVisible } = useExtensions()
const toggleMarket = () => {
isMarketVisible.value = !isMarketVisible.value
@ -48,6 +46,12 @@ const toggleMarket = () => {
</div>
</template>
<ExtensionsMarket v-if="isMarketVisible" v-model="isMarketVisible" />
<ExtensionsDetails
v-if="isDetailsVisible && detailsExtensionId"
v-model="isDetailsVisible"
:extension-id="detailsExtensionId"
:from="detailsFrom"
/>
</Pane>
</template>

19
packages/nc-gui/composables/useExtensions.ts

@ -341,6 +341,20 @@ export const useExtensions = createSharedComposable(() => {
})
})
// Extension details modal
const isDetailsVisible = ref(false)
const detailsExtensionId = ref<string>()
const detailsFrom = ref<'market' | 'extension'>('market')
const showExtensionDetails = (extensionId: string, from?: 'market' | 'extension') => {
detailsExtensionId.value = extensionId
isDetailsVisible.value = true
detailsFrom.value = from || 'market'
}
// Extension market modal
const isMarketVisible = ref(false)
return {
extensionsLoaded,
availableExtensions,
@ -354,5 +368,10 @@ export const useExtensions = createSharedComposable(() => {
clearKvStore,
deleteExtension,
getExtensionIcon,
isDetailsVisible,
detailsExtensionId,
detailsFrom,
showExtensionDetails,
isMarketVisible,
}
})

2
packages/nc-gui/extensions/csv-import/manifest.json

@ -1,7 +1,7 @@
{
"id": "nc-csv-import",
"title": "CSV Import",
"description": "Import CSV files into NocoDB",
"description": "The CSV Import extension for NocoDB empowers users with seamless integration, enabling effortless uploading of CSV files into existing tables. With its intuitive interface, users can effortlessly bind any column from their CSV files to corresponding columns within their NocoDB tables, facilitating efficient data management.\n\nThis versatile extension further enhances productivity by supporting upsert operations, allowing users to match records based on specified columns. Whether updating existing data or importing new information, the CSV Import extension streamlines the process, ensuring accuracy and consistency across datasets.\n\nKey Features:\n\n- Simplified CSV file uploading to NocoDB tables.\n- Flexible column binding for seamless data integration.\n- Upsert functionality for efficient record matching and updating.\n\nExperience unparalleled convenience and precision in data management with the CSV Import extension for NocoDB. Streamline your workflow and unlock the full potential of your datasets today.",
"entry": "csv-import",
"version": "0.1",
"iconUrl": "csv-import/icon.png",

Loading…
Cancel
Save