Skip to content

Commit 1c82c12

Browse files
committed
feat: add extension setup and custom slots support in the application
1 parent 333bada commit 1c82c12

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

extensions/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

nuxt.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import openapiTS from 'openapi-typescript'
55
import { defineNuxtConfig } from 'nuxt/config'
66
import { parse } from 'yaml'
77
import * as consola from 'consola'
8+
import setupApp from './src/server/extension.setup'
89

910
const SESAME_APP_API_URL = process.env.SESAME_APP_API_URL || 'http://localhost:4002'
1011
const SESAME_ALLOWED_HOSTS = process.env.SESAME_ALLOWED_HOSTS ? process.env.SESAME_ALLOWED_HOSTS.split(',') : []
@@ -65,6 +66,7 @@ export default defineNuxtConfig({
6566
appConfig: {
6667
baseUrl: SESAME_APP_API_URL,
6768
appManagerVersion: process.env.npm_package_version,
69+
customSlots: {},
6870
},
6971
modules: [
7072
'@nuxt-alt/auth',
@@ -76,6 +78,7 @@ export default defineNuxtConfig({
7678
'dayjs-nuxt',
7779
'@nuxt/devtools',
7880
'nuxt-monaco-editor',
81+
...setupApp(),
7982
],
8083
auth: {
8184
globalMiddleware: true,

src/components/hook.vue

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<template lang="pug">
2+
div(:id='"tk-hook:" + name')
3+
template(v-for="(customSlot, key) in customSlots")
4+
pre.bg-red.text-white(v-if='debug' v-html="JSON.stringify({name, customSlot, data}, null, 2)")
5+
component(
6+
v-if='customSlot.componentName'
7+
:key='key'
8+
:is="customSlot.componentName"
9+
v-bind="{...customSlot.data, ...data}"
10+
)
11+
</template>
12+
13+
<script lang="ts" setup>
14+
import { useAppConfig } from '#imports'
15+
import { sort } from 'radash'
16+
17+
//TODO: Convert to a sdk repository and publish it on npm for 3rd-party extensions
18+
interface CustomSlotInterface {
19+
componentName: string
20+
priority?: number
21+
data?: Record<string, any>
22+
}
23+
24+
const props = defineProps({
25+
name: {
26+
type: String,
27+
required: true,
28+
},
29+
data: {
30+
type: Object,
31+
default: () => ({}),
32+
},
33+
debug: {
34+
type: Boolean,
35+
default: false,
36+
},
37+
})
38+
39+
const config = useAppConfig()
40+
const customSlots = computed(() => {
41+
if (config.customSlots.hasOwnProperty(props.name)) {
42+
const configCustomSlots = config.customSlots as Record<string, CustomSlotInterface[]>
43+
return sort(configCustomSlots[props.name], (list: CustomSlotInterface) => list.priority || 0, true)
44+
}
45+
})
46+
</script>

src/server/extension.setup.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { existsSync, readFileSync } from 'fs'
2+
import { dirname, join } from 'path'
3+
import { parse } from 'yaml'
4+
import * as consola from 'consola'
5+
6+
const appList: string[] = []
7+
8+
export const EXTENSION_FILE_INFO = 'extension.yml'
9+
export const EXTENSIONS_FILE_PATH = join(dirname(__dirname), '/../extensions/list.yml')
10+
11+
export function parseExtensionsList(): any[] {
12+
const data = readFileSync(EXTENSIONS_FILE_PATH, 'utf8')
13+
const yml = parse(data)
14+
return yml.list
15+
}
16+
17+
export function extensionParseFile(path: string): any {
18+
consola.info(`[Extension] Parsing extension file: ${path}/${EXTENSION_FILE_INFO}`)
19+
const data = readFileSync(`${path}/${EXTENSION_FILE_INFO}`, 'utf8')
20+
return parse(data)
21+
}
22+
23+
// noinspection JSUnusedGlobalSymbols
24+
export default function (): string[] {
25+
consola.info(`[Extension] Setting up extensions in <${EXTENSIONS_FILE_PATH}>...`)
26+
try {
27+
if (existsSync(EXTENSIONS_FILE_PATH)) {
28+
const list = parseExtensionsList()
29+
for (const extension of list) {
30+
consola.info(`[Extension] Found extension: ${extension.name} (enabled: ${extension.enabled})`)
31+
32+
if (extension.enabled) {
33+
const extensionPath = `${dirname(dirname(__dirname))}/extensions/${extension.path}`
34+
const extensionFile = extensionParseFile(extensionPath)
35+
if (extensionFile.settings.app.target) {
36+
const extensionAppTarget = `${extensionPath}/${extensionFile.settings.app.target}`
37+
appList.push(process.env.NODE_ENV === 'development' ? `${extensionAppTarget}/src/module` : `${extensionAppTarget}/dist/module.cjs`) // TODO: target dev and prod parameters
38+
}
39+
}
40+
}
41+
}
42+
return appList
43+
} catch (err) {
44+
console.error(err) //TODO: universal logger
45+
process.exit(1)
46+
}
47+
}

0 commit comments

Comments
 (0)