11<script setup lang="ts">
22import { computed , ref , useTemplateRef } from ' vue'
33import ContextMenu , { type ContextMenuMethods } from ' primevue/contextmenu'
4+ import type { MenuItem } from ' primevue/menuitem'
45import { useConfirm } from ' primevue/useconfirm'
56import { useToast } from ' primevue/usetoast'
6- import MongoDbCreateCollectionDialog from ' @/components/datasources/mongodb/MongoDbCreateCollectionDialog.vue'
7- import {
8- createMongoDbCollection ,
9- deleteMongoDbCollection ,
10- parseMongoPath ,
11- } from ' @/datasources/mongodb/browser'
127import SidebarSourceItemButton from ' @/components/sidebar/source/SidebarSourceItemButton.vue'
138import SidebarSourceSection from ' @/components/sidebar/source/SidebarSourceSection.vue'
149import { getRegisteredDataSourceDefinition , supportsQueryConsole } from ' @/datasources/registry'
@@ -24,7 +19,6 @@ import { useTabsStore } from '@/stores/tabs-store.ts'
2419import { useWorkspaceStore } from ' @/stores/workspace-store.ts'
2520import type { DataSourceBrowserTabData , DataSourceResourceItem } from ' @/types/datasources'
2621import type { DataSourceQueryTabData } from ' @/types/query-console'
27- import { isResourceBrowserTab } from ' @/types/tabs'
2822import type { DataSourceRecord } from ' @/types/workspace'
2923
3024const props = defineProps <{
@@ -45,10 +39,12 @@ const isExpanded = ref(false)
4539const isLoading = ref (false )
4640const items = ref <DataSourceResourceItem []>([])
4741const selectedItem = ref <DataSourceResourceItem | null >(null )
48- const createCollectionVisible = ref (false )
49- const createCollectionDatabase = ref (' ' )
5042const sourceMenu = useTemplateRef <ContextMenuMethods >(' sourceMenu' )
5143const itemMenu = useTemplateRef <ContextMenuMethods >(' itemMenu' )
44+ const resourceExtension = useTemplateRef <{
45+ getSourceMenuItems: () => MenuItem []
46+ getItemMenuItems: (item : DataSourceResourceItem ) => MenuItem []
47+ }>(' resourceExtension' )
5248
5349const sourceDefinition = computed (() =>
5450 getRegisteredDataSourceDefinition (props .source .type , workspaceStore .serverInfo ),
@@ -98,12 +94,52 @@ const canWriteSource = computed(() =>
9894const primaryActionIcon = computed (() =>
9995 canQuerySource .value ? ' ti ti-terminal-2' : ' ti ti-folder-open' ,
10096)
101- const defaultMongoDatabase = computed (() =>
102- props .source .type === ' mongodb' ? parseMongoPath (defaultBrowserPath .value ).database : ' ' ,
103- )
104- const selectedMongoTarget = computed (() =>
105- props .source .type === ' mongodb' ? parseMongoPath (selectedItem .value ?.path ) : null ,
106- )
97+ const sourceMenuItems = computed (() => [
98+ ... (canQuerySource .value
99+ ? [
100+ {
101+ label: ' Open console' ,
102+ icon: ' ti ti-terminal-2' ,
103+ command : () => openQueryConsole (),
104+ disabled: ! canQuerySource .value ,
105+ },
106+ ]
107+ : []),
108+ {
109+ label: ' Open browser' ,
110+ icon: ' ti ti-folder-open' ,
111+ command : () => openBrowser (),
112+ disabled: ! canBrowseSource .value ,
113+ },
114+ {
115+ label: ' Edit datasource' ,
116+ icon: ' ti ti-settings-cog' ,
117+ command : () => emit (' editDatasource' ),
118+ disabled: ! canManageSource .value ,
119+ },
120+ ... (resourceExtension .value ?.getSourceMenuItems () ?? []),
121+ {
122+ label: ' Refresh resources' ,
123+ icon: ' ti ti-refresh' ,
124+ command: loadItems ,
125+ },
126+ { separator: true },
127+ {
128+ label: ' Delete datasource' ,
129+ icon: ' ti ti-trash' ,
130+ command: deleteDatasource ,
131+ disabled: ! canManageSource .value ,
132+ },
133+ ])
134+ const itemMenuItems = computed (() => [
135+ {
136+ label: selectedItem .value ?.kind === ' container' ? ' Open' : ' Preview' ,
137+ icon: selectedItem .value ?.kind === ' container' ? ' ti ti-folder-open' : ' ti ti-file-search' ,
138+ command : () => selectedItem .value && openBrowser (selectedItem .value .path ),
139+ disabled: ! canBrowseSource .value ,
140+ },
141+ ... (selectedItem .value ? resourceExtension .value ?.getItemMenuItems (selectedItem .value ) ?? [] : []),
142+ ])
107143
108144async function loadItems() {
109145 if (! workspaceStore .currentProjectId ) {
@@ -191,120 +227,6 @@ async function deleteDatasource() {
191227 })
192228}
193229
194- function showMongoCreateCollectionDialog(database : string ) {
195- if (! database || ! canWriteSource .value ) {
196- return
197- }
198-
199- createCollectionDatabase .value = database
200- createCollectionVisible .value = true
201- }
202-
203- async function createMongoCollection(collectionName : string ) {
204- if (
205- props .source .type !== ' mongodb' ||
206- ! canWriteSource .value ||
207- ! workspaceStore .currentProjectId ||
208- ! createCollectionDatabase .value
209- ) {
210- return
211- }
212-
213- try {
214- const client = await workspaceStore .getClient ()
215- await createMongoDbCollection ({
216- client ,
217- projectId: workspaceStore .currentProjectId ,
218- sourceId: props .source .id ,
219- database: createCollectionDatabase .value ,
220- collection: collectionName ,
221- })
222- createCollectionVisible .value = false
223-
224- if (isExpanded .value ) {
225- await loadItems ()
226- }
227-
228- toast .add ({
229- severity: ' success' ,
230- summary: ' Collection created' ,
231- detail: ` ${collectionName } is now available in ${createCollectionDatabase .value } ` ,
232- life: 2200 ,
233- })
234-
235- await openBrowser (` ${createCollectionDatabase .value }/${collectionName } ` )
236- } catch (error ) {
237- toast .add ({
238- severity: ' error' ,
239- summary: ' Collection create failed' ,
240- detail: getErrorMessage (error , ' The MongoDB collection could not be created' ),
241- life: 3200 ,
242- })
243- }
244- }
245-
246- async function deleteMongoCollection(item : DataSourceResourceItem ) {
247- if (
248- props .source .type !== ' mongodb' ||
249- ! canWriteSource .value ||
250- ! workspaceStore .currentProjectId
251- ) {
252- return
253- }
254-
255- const parsed = parseMongoPath (item .path )
256- if (! parsed .database || ! parsed .collection ) {
257- return
258- }
259-
260- confirm .require ({
261- header: ' Delete Collection' ,
262- message: ` Delete collection ${parsed .collection }? ` ,
263- acceptClass: ' p-button-danger' ,
264- accept : async () => {
265- try {
266- const client = await workspaceStore .getClient ()
267- await deleteMongoDbCollection ({
268- client ,
269- projectId: workspaceStore .currentProjectId ! ,
270- sourceId: props .source .id ,
271- database: parsed .database ,
272- collection: parsed .collection ,
273- })
274-
275- tabsStore .closeTabsMatching (
276- (tab ) =>
277- isResourceBrowserTab (tab ) &&
278- tab .data .sourceType === ' mongodb' &&
279- tab .data .sourceId === props .source .id &&
280- Boolean (
281- tab .data .path === item .path ||
282- tab .data .path ?.startsWith (` ${item .path }/_doc/ ` ),
283- ),
284- )
285-
286- if (isExpanded .value ) {
287- await loadItems ()
288- }
289-
290- toast .add ({
291- severity: ' success' ,
292- summary: ' Collection deleted' ,
293- detail: ` ${parsed .collection } has been removed ` ,
294- life: 2200 ,
295- })
296- } catch (error ) {
297- toast .add ({
298- severity: ' error' ,
299- summary: ' Collection delete failed' ,
300- detail: getErrorMessage (error , ' The MongoDB collection could not be deleted' ),
301- life: 3200 ,
302- })
303- }
304- },
305- })
306- }
307-
308230async function openQueryConsole() {
309231 if (! canQuerySource .value || ! workspaceStore .currentProjectId ) {
310232 return
@@ -362,85 +284,6 @@ async function runPrimaryAction() {
362284 await openBrowser ()
363285}
364286
365- const sourceMenuItems = computed (() => [
366- ... (canQuerySource .value
367- ? [
368- {
369- label: ' Open console' ,
370- icon: ' ti ti-terminal-2' ,
371- command : () => openQueryConsole (),
372- disabled: ! canQuerySource .value ,
373- },
374- ]
375- : []),
376- {
377- label: ' Open browser' ,
378- icon: ' ti ti-folder-open' ,
379- command : () => openBrowser (),
380- disabled: ! canBrowseSource .value ,
381- },
382- {
383- label: ' Edit datasource' ,
384- icon: ' ti ti-settings-cog' ,
385- command : () => emit (' editDatasource' ),
386- disabled: ! canManageSource .value ,
387- },
388- ... (props .source .type === ' mongodb' && defaultMongoDatabase .value
389- ? [
390- {
391- label: ' Add collection' ,
392- icon: ' ti ti-plus' ,
393- command : () => showMongoCreateCollectionDialog (defaultMongoDatabase .value ),
394- disabled: ! canWriteSource .value ,
395- },
396- ]
397- : []),
398- {
399- label: ' Refresh resources' ,
400- icon: ' ti ti-refresh' ,
401- command: loadItems ,
402- },
403- { separator: true },
404- {
405- label: ' Delete datasource' ,
406- icon: ' ti ti-trash' ,
407- command: deleteDatasource ,
408- disabled: ! canManageSource .value ,
409- },
410- ])
411-
412- const itemMenuItems = computed (() => [
413- {
414- label: selectedItem .value ?.kind === ' container' ? ' Open' : ' Preview' ,
415- icon: selectedItem .value ?.kind === ' container' ? ' ti ti-folder-open' : ' ti ti-file-search' ,
416- command : () => selectedItem .value && openBrowser (selectedItem .value .path ),
417- disabled: ! canBrowseSource .value ,
418- },
419- ... (props .source .type === ' mongodb' &&
420- selectedMongoTarget .value ?.database &&
421- ! selectedMongoTarget .value .collection
422- ? [
423- {
424- label: ' Add collection' ,
425- icon: ' ti ti-plus' ,
426- command : () => showMongoCreateCollectionDialog (selectedMongoTarget .value ! .database ),
427- disabled: ! canWriteSource .value ,
428- },
429- ]
430- : []),
431- ... (props .source .type === ' mongodb' && selectedMongoTarget .value ?.collection
432- ? [
433- { separator: true },
434- {
435- label: ' Delete collection' ,
436- icon: ' ti ti-trash' ,
437- command : () => selectedItem .value && deleteMongoCollection (selectedItem .value ),
438- disabled: ! canWriteSource .value ,
439- },
440- ]
441- : []),
442- ])
443-
444287function showSourceMenu(event : MouseEvent ) {
445288 sourceMenu .value ?.show (event )
446289}
@@ -486,11 +329,16 @@ function getItemIcon(item: DataSourceResourceItem) {
486329 <template #overlay >
487330 <ContextMenu ref="sourceMenu" :model =" sourceMenuItems " />
488331 <ContextMenu ref="itemMenu" :model =" itemMenuItems " />
489- <MongoDbCreateCollectionDialog
490- v-if =" source .type === ' mongodb' "
491- v-model :visible =" createCollectionVisible "
492- :database =" createCollectionDatabase "
493- @create =" createMongoCollection "
332+ <component
333+ :is =" sourceDefinition.sidebarResourceExtensionComponent"
334+ v-if =" sourceDefinition.sidebarResourceExtensionComponent"
335+ ref =" resourceExtension"
336+ :source =" source"
337+ :default-browser-path =" defaultBrowserPath"
338+ :expanded =" isExpanded"
339+ :can-write-source =" canWriteSource"
340+ :open-browser =" openBrowser"
341+ :refresh-resources =" loadItems"
494342 />
495343 </template >
496344 </SidebarSourceSection >
0 commit comments