@owdproject/core 3.1.4-beta.0 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/module.ts +16 -8
- package/package.json +2 -2
- package/runtime/components/Core/Application/CoreApplicationRender.vue +1 -1
- package/runtime/components/Core/Desktop/CoreDesktop.vue +11 -7
- package/runtime/components/Core/Window/CoreWindow.vue +3 -1
- package/runtime/composables/useApplicationEntries.ts +1 -1
- package/runtime/composables/useApplicationManager.ts +277 -4
- package/runtime/composables/useDesktopManager.ts +22 -4
- package/runtime/composables/useTerminalManager.ts +62 -3
- package/runtime/core/controllers/ApplicationController.ts +6 -6
- package/runtime/core/controllers/WindowController.ts +2 -2
- package/runtime/stores/storeApplication.ts +9 -8
- package/runtime/stores/storeDesktop.ts +2 -0
- package/runtime/stores/storeDesktopDefaultApps.ts +53 -0
- package/runtime/composables/useClipboardFs.ts +0 -25
- package/runtime/core/managers/ApplicationManager.ts +0 -281
- package/runtime/core/managers/DesktopManager.ts +0 -47
- package/runtime/core/managers/TerminalManager.ts +0 -48
package/module.ts
CHANGED
|
@@ -35,7 +35,7 @@ export default defineNuxtModule({
|
|
|
35
35
|
).default
|
|
36
36
|
|
|
37
37
|
} catch (e) {
|
|
38
|
-
console.error('/desktop/owd.config.ts not found or invalid')
|
|
38
|
+
console.error('/desktop/owd.config.ts not found or invalid', e)
|
|
39
39
|
return
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -50,9 +50,17 @@ export default defineNuxtModule({
|
|
|
50
50
|
...clientConfig
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
53
|
+
// init desktop runtime config and define core version
|
|
54
54
|
|
|
55
|
-
_nuxt.options.runtimeConfig.public.
|
|
55
|
+
_nuxt.options.runtimeConfig.public.desktop = {
|
|
56
|
+
coreVersion: pkg.version
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// assign open web desktop config to runtime config
|
|
60
|
+
_nuxt.options.runtimeConfig.public.desktop = deepMerge(
|
|
61
|
+
_nuxt.options.runtimeConfig.public.desktop,
|
|
62
|
+
clientConfig
|
|
63
|
+
)
|
|
56
64
|
|
|
57
65
|
{
|
|
58
66
|
// install open web desktop theme
|
|
@@ -77,13 +85,13 @@ export default defineNuxtModule({
|
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
// assign open web desktop config to runtime config
|
|
81
|
-
_nuxt.options.runtimeConfig.public.desktop = deepMerge(
|
|
82
|
-
_nuxt.options.runtimeConfig.public.desktop,
|
|
83
|
-
clientConfig
|
|
84
|
-
)
|
|
85
88
|
}
|
|
86
89
|
|
|
90
|
+
// assign runtimeConfig desktop prop to appConfig
|
|
91
|
+
// to make it overwritable by components later
|
|
92
|
+
// via useDesktopManager
|
|
93
|
+
_nuxt.options.appConfig.desktop = _nuxt.options.runtimeConfig.public.desktop
|
|
94
|
+
|
|
87
95
|
{
|
|
88
96
|
// install primevue
|
|
89
97
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owdproject/core",
|
|
3
|
-
"version": "3.1.4
|
|
3
|
+
"version": "3.1.4",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"web",
|
|
6
6
|
"desktop",
|
|
@@ -48,6 +48,6 @@
|
|
|
48
48
|
"sass": "^1.89.2",
|
|
49
49
|
"shellwords": "^1.0.1",
|
|
50
50
|
"vue-resizable": "^2.1.7",
|
|
51
|
-
"
|
|
51
|
+
"getopts": "^2.3.0"
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -10,7 +10,7 @@ const applicationManager = useApplicationManager()
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<CoreApplicationWindowsRender
|
|
13
|
-
v-for="app of applicationManager.appsRunning"
|
|
13
|
+
v-for="app of applicationManager.appsRunning.value"
|
|
14
14
|
:key="app.id"
|
|
15
15
|
:workspace-filter="workspaceFilter"
|
|
16
16
|
:windows="app.windowsOpened"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { onMounted, onUnmounted } from 'vue'
|
|
3
|
-
import { useRuntimeConfig } from 'nuxt/app'
|
|
2
|
+
import { onBeforeMount, onMounted, onUnmounted } from 'vue'
|
|
3
|
+
import { useAppConfig, useRuntimeConfig } from 'nuxt/app'
|
|
4
4
|
import { computed, toRaw } from '@vue/reactivity'
|
|
5
5
|
import { useDesktopManager } from '../../../composables/useDesktopManager'
|
|
6
|
-
import { useApplicationManager } from '../../../composables/useApplicationManager'
|
|
7
6
|
import { useDesktopStore } from '../../../stores/storeDesktop'
|
|
7
|
+
import { useDesktopDefaultAppsStore } from '../../../stores/storeDesktopDefaultApps'
|
|
8
8
|
import { useDesktopWorkspaceStore } from '../../../stores/storeDesktopWorkspace'
|
|
9
9
|
|
|
10
10
|
const props = withDefaults(
|
|
@@ -25,9 +25,11 @@ const props = withDefaults(
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
// todo move to owd initialization
|
|
28
|
+
// perhaps in a plugin
|
|
28
29
|
|
|
30
|
+
const appConfig = useAppConfig()
|
|
29
31
|
const desktopManager = useDesktopManager()
|
|
30
|
-
const
|
|
32
|
+
const desktopDefaultAppsStore = useDesktopDefaultAppsStore()
|
|
31
33
|
const runtimeConfig = useRuntimeConfig()
|
|
32
34
|
|
|
33
35
|
// create firsts workspaces if not available
|
|
@@ -42,8 +44,6 @@ if (desktopStore.$persistedState) {
|
|
|
42
44
|
desktopWorkspaceStore.setupWorkspaces()
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
desktopManager.setConfig(runtimeConfig.public.desktop)
|
|
46
|
-
|
|
47
47
|
// override desktop configurations
|
|
48
48
|
desktopManager.setConfig({
|
|
49
49
|
windows: toRaw(props.windows),
|
|
@@ -65,10 +65,14 @@ function handleDesktopResize() {
|
|
|
65
65
|
const classes = computed(() => {
|
|
66
66
|
const list = ['owd-desktop']
|
|
67
67
|
|
|
68
|
-
list.push(`owd-desktop--${
|
|
68
|
+
list.push(`owd-desktop--${appConfig.desktop.name}`)
|
|
69
69
|
|
|
70
70
|
return list
|
|
71
71
|
})
|
|
72
|
+
|
|
73
|
+
onBeforeMount(() => {
|
|
74
|
+
desktopDefaultAppsStore.loadDefaultAppsFromConfig(runtimeConfig)
|
|
75
|
+
})
|
|
72
76
|
</script>
|
|
73
77
|
|
|
74
78
|
<template>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, provide } from 'vue'
|
|
3
3
|
import { computed } from '@vue/reactivity'
|
|
4
|
+
import { useAppConfig } from 'nuxt/app'
|
|
4
5
|
import { useDesktopManager } from '@owdproject/core/runtime/composables/useDesktopManager'
|
|
5
6
|
import { handleWindowControllerProps } from '@owdproject/core/runtime/utils/utilWindow'
|
|
6
7
|
|
|
@@ -27,6 +28,7 @@ const emit = defineEmits([
|
|
|
27
28
|
'toggle-maximize',
|
|
28
29
|
])
|
|
29
30
|
|
|
31
|
+
const appConfig = useAppConfig()
|
|
30
32
|
const desktopManager = useDesktopManager() // used in <style v-bind>
|
|
31
33
|
const windowController: IWindowController = handleWindowControllerProps(
|
|
32
34
|
props.window,
|
|
@@ -151,7 +153,7 @@ const classes = computed(() => {
|
|
|
151
153
|
|
|
152
154
|
<style scoped lang="scss">
|
|
153
155
|
.owd-window {
|
|
154
|
-
position: v-bind('
|
|
156
|
+
position: v-bind('appConfig.desktop.windows.position');
|
|
155
157
|
|
|
156
158
|
&--dragging,
|
|
157
159
|
&--resizing {
|
|
@@ -21,7 +21,7 @@ export function useApplicationEntries() {
|
|
|
21
21
|
visibility: Visibility = 'primary',
|
|
22
22
|
): Ref<ApplicationEntryWithInherited[]> {
|
|
23
23
|
return computed(() => {
|
|
24
|
-
const currentEntries = [...applicationManager.appsEntries]
|
|
24
|
+
const currentEntries = [...applicationManager.appsEntries.value]
|
|
25
25
|
|
|
26
26
|
// filtering
|
|
27
27
|
const filtered =
|
|
@@ -1,7 +1,280 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { reactive, markRaw, computed } from 'vue'
|
|
2
|
+
import { ApplicationController } from '../core/controllers/ApplicationController'
|
|
3
|
+
import { normalizeApplicationConfig } from '../utils/utilApp'
|
|
4
|
+
import { debugLog } from '../utils/utilDebug'
|
|
5
|
+
import * as shellwords from 'shellwords'
|
|
6
|
+
import getopts from "getopts"
|
|
2
7
|
|
|
3
|
-
const
|
|
8
|
+
const apps = reactive(new Map<string, IApplicationController>())
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Application Manager Composable (Singleton)
|
|
12
|
+
*/
|
|
13
|
+
export function useApplicationManager() {
|
|
14
|
+
/**
|
|
15
|
+
* Define new application
|
|
16
|
+
*
|
|
17
|
+
* @param id
|
|
18
|
+
* @param config
|
|
19
|
+
*/
|
|
20
|
+
async function defineApp(id: string, config: ApplicationConfig) {
|
|
21
|
+
if (isAppDefined(id)) {
|
|
22
|
+
debugLog(`App "${id}" is already defined`)
|
|
23
|
+
return getAppById(id)!
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const normalizedConfig = normalizeApplicationConfig(config)
|
|
27
|
+
const applicationConfig = markRaw(normalizedConfig)
|
|
28
|
+
|
|
29
|
+
const applicationController: IApplicationController = new ApplicationController(id, applicationConfig)
|
|
30
|
+
await applicationController.initApplication()
|
|
31
|
+
|
|
32
|
+
apps.set(id, applicationController)
|
|
33
|
+
|
|
34
|
+
return applicationController
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check if app has been defined
|
|
39
|
+
*
|
|
40
|
+
* @param {string} id
|
|
41
|
+
*/
|
|
42
|
+
function isAppDefined(id: string) {
|
|
43
|
+
return getAppById(id)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves an app instance by its unique identifier
|
|
48
|
+
*
|
|
49
|
+
* @param {string} id
|
|
50
|
+
*/
|
|
51
|
+
function getAppById(id: string) {
|
|
52
|
+
return apps.get(id)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if app is running
|
|
57
|
+
*
|
|
58
|
+
* @param {string} id
|
|
59
|
+
*/
|
|
60
|
+
function isAppRunning(id: string) {
|
|
61
|
+
if (!isAppDefined(id)) {
|
|
62
|
+
throw Error(`App "${id}" is not defined`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const applicationController = getAppById(id)!
|
|
66
|
+
return applicationController.isRunning
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Launch app entry
|
|
71
|
+
*
|
|
72
|
+
* @param id
|
|
73
|
+
* @param entryKey
|
|
74
|
+
* @param argument
|
|
75
|
+
*/
|
|
76
|
+
async function launchAppEntry(
|
|
77
|
+
id: string,
|
|
78
|
+
entryKey: string,
|
|
79
|
+
argument: string = ''
|
|
80
|
+
): Promise<IApplicationController | undefined | void> {
|
|
81
|
+
if (!isAppDefined(id)) {
|
|
82
|
+
throw Error(`App "${id}" is not defined`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const applicationController = getAppById(id)!
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
applicationController.config.entries &&
|
|
89
|
+
!applicationController.config.entries.hasOwnProperty(entryKey)
|
|
90
|
+
) {
|
|
91
|
+
throw Error(`App entry "${entryKey}" is not defined in ${id} application`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const entry: ApplicationEntry = applicationController.config.entries[entryKey]!
|
|
95
|
+
|
|
96
|
+
if (argument) argument = ` ${argument}`
|
|
97
|
+
|
|
98
|
+
await execAppCommand(applicationController.id, entry.command + argument)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Run app command
|
|
103
|
+
*
|
|
104
|
+
* @param id
|
|
105
|
+
* @param rawCommand
|
|
106
|
+
*/
|
|
107
|
+
async function execAppCommand(
|
|
108
|
+
id: string,
|
|
109
|
+
rawCommand: string,
|
|
110
|
+
): Promise<CommandOutput> {
|
|
111
|
+
if (!isAppDefined(id)) {
|
|
112
|
+
throw Error(`App "${id}" is not defined`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const applicationController = getAppById(id)!
|
|
116
|
+
|
|
117
|
+
const args = shellwords.split(rawCommand)
|
|
118
|
+
const parsed = getopts(args)
|
|
119
|
+
const command: string = parsed._[0]
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
applicationController.config.commands &&
|
|
123
|
+
!applicationController.config.commands.hasOwnProperty(command)
|
|
124
|
+
) {
|
|
125
|
+
throw Error(
|
|
126
|
+
`App command "${command}" is not defined in ${id} application`,
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const commandFn: any = applicationController.config.commands![command]
|
|
131
|
+
|
|
132
|
+
const commandOutput = await commandFn(applicationController, parsed)
|
|
133
|
+
|
|
134
|
+
applicationController.setRunning(true)
|
|
135
|
+
|
|
136
|
+
return commandOutput
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Close application
|
|
141
|
+
*
|
|
142
|
+
* @param id
|
|
143
|
+
*/
|
|
144
|
+
function closeApp(id: string) {
|
|
145
|
+
if (!isAppDefined(id)) {
|
|
146
|
+
throw Error(`App "${id}" is not defined`)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const applicationController = getAppById(id)!
|
|
150
|
+
|
|
151
|
+
applicationController.closeAllWindows()
|
|
152
|
+
applicationController.setRunning(false)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Array of available menu entries for system bars, docks
|
|
157
|
+
*/
|
|
158
|
+
const appsEntries = computed(() => {
|
|
159
|
+
const entries: ApplicationEntryWithInherited[] = []
|
|
160
|
+
|
|
161
|
+
for (const applicationController of apps.values()) {
|
|
162
|
+
if (!applicationController.config.entries) {
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const entryKey of Object.keys(applicationController.config.entries)) {
|
|
167
|
+
const entry = applicationController.config.entries[entryKey]!
|
|
168
|
+
|
|
169
|
+
entries.push({
|
|
170
|
+
application: applicationController,
|
|
171
|
+
title: entry.title ?? applicationController.config.title,
|
|
172
|
+
icon: entry.icon ?? applicationController.config.icon,
|
|
173
|
+
category: entry.category ?? applicationController.config.category,
|
|
174
|
+
visibility: entry.visibility ?? 'primary',
|
|
175
|
+
command: entry.command,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return entries
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Array of opened windows for system bars, docks
|
|
185
|
+
*/
|
|
186
|
+
const windowsOpened = computed(() => {
|
|
187
|
+
const windows: Map<string, IWindowController>[] = []
|
|
188
|
+
|
|
189
|
+
for (const applicationController of apps.values()) {
|
|
190
|
+
if (applicationController.isRunning) {
|
|
191
|
+
windows.push(...applicationController.windows)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return windows
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Array of running applications
|
|
200
|
+
*/
|
|
201
|
+
const appsRunning = computed(() => {
|
|
202
|
+
const runningApps: IApplicationController[] = []
|
|
203
|
+
|
|
204
|
+
for (const applicationController of apps.values()) {
|
|
205
|
+
if (applicationController.isRunning) {
|
|
206
|
+
runningApps.push(applicationController)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return runningApps
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
function getWindowOpenedId(windowId: string) {
|
|
214
|
+
const mapWindowFound = windowsOpened.value.find((window: any) => {
|
|
215
|
+
return window[1].state.id === windowId
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
if (mapWindowFound) {
|
|
219
|
+
// @ts-ignore
|
|
220
|
+
return mapWindowFound[1] as IWindowController
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gets all unique categories from the installed apps
|
|
226
|
+
*/
|
|
227
|
+
const appCategories = computed(() => {
|
|
228
|
+
const categories = new Set<string>()
|
|
229
|
+
|
|
230
|
+
for (const applicationController of apps.values()) {
|
|
231
|
+
if (applicationController.config.category) {
|
|
232
|
+
categories.add(applicationController.config.category)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return Array.from(categories).sort()
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Gets the apps ordered by category
|
|
241
|
+
*/
|
|
242
|
+
const appsByCategory = computed(() => {
|
|
243
|
+
const categorizedApps: {
|
|
244
|
+
[category: string]: IApplicationController[]
|
|
245
|
+
} = {}
|
|
246
|
+
|
|
247
|
+
for (const applicationController of apps.values()) {
|
|
248
|
+
const category = applicationController.config.category || 'other'
|
|
249
|
+
if (!categorizedApps[category]) {
|
|
250
|
+
categorizedApps[category] = []
|
|
251
|
+
}
|
|
252
|
+
categorizedApps[category].push(applicationController)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (const category in categorizedApps) {
|
|
256
|
+
categorizedApps[category].sort((a, b) =>
|
|
257
|
+
a.config.title.localeCompare(b.config.title),
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return categorizedApps
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
apps,
|
|
266
|
+
defineApp,
|
|
267
|
+
isAppDefined,
|
|
268
|
+
getAppById,
|
|
269
|
+
isAppRunning,
|
|
270
|
+
launchAppEntry,
|
|
271
|
+
execAppCommand,
|
|
272
|
+
closeApp,
|
|
273
|
+
getWindowOpenedId,
|
|
274
|
+
appsEntries,
|
|
275
|
+
appsRunning,
|
|
276
|
+
windowsOpened,
|
|
277
|
+
appCategories,
|
|
278
|
+
appsByCategory,
|
|
279
|
+
}
|
|
7
280
|
}
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const desktopManager = new DesktopManager()
|
|
1
|
+
import { deepMerge } from '../utils/utilCommon'
|
|
2
|
+
import { useAppConfig } from 'nuxt/app'
|
|
4
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Desktop Manager Composable (Singleton)
|
|
6
|
+
*/
|
|
5
7
|
export function useDesktopManager() {
|
|
6
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Merges and sets the desktop config at runtime
|
|
10
|
+
*
|
|
11
|
+
* @param newConfig
|
|
12
|
+
*/
|
|
13
|
+
function setConfig(newConfig: DesktopConfig) {
|
|
14
|
+
const appConfig = useAppConfig()
|
|
15
|
+
|
|
16
|
+
appConfig.desktop = deepMerge(
|
|
17
|
+
appConfig.desktop,
|
|
18
|
+
newConfig,
|
|
19
|
+
) as DesktopConfig
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
setConfig,
|
|
24
|
+
}
|
|
7
25
|
}
|
|
@@ -1,7 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useApplicationManager } from './useApplicationManager'
|
|
2
|
+
import { debugLog } from '../utils/utilDebug'
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
const commands = new Map<string, TerminalCommand>()
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Terminal Manager Composable (Singleton)
|
|
8
|
+
*/
|
|
5
9
|
export function useTerminalManager() {
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Add a new terminal command
|
|
12
|
+
*
|
|
13
|
+
* @param command
|
|
14
|
+
*/
|
|
15
|
+
const addCommand = (command: TerminalCommand) => {
|
|
16
|
+
for (const existingCommand of commands.keys()) {
|
|
17
|
+
if (
|
|
18
|
+
existingCommand.startsWith(command.name) ||
|
|
19
|
+
command.name.startsWith(existingCommand)
|
|
20
|
+
) {
|
|
21
|
+
throw new Error(`Command prefix conflict with "${existingCommand}"`)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
commands.set(command.name, command)
|
|
26
|
+
debugLog(`Registered terminal command: ${command.name} → ${command.applicationId}`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* List all registered command names
|
|
31
|
+
*/
|
|
32
|
+
const listCommands = (): string[] => {
|
|
33
|
+
return Array.from(commands.keys())
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Execute a terminal command
|
|
38
|
+
*
|
|
39
|
+
* @param input
|
|
40
|
+
*/
|
|
41
|
+
const execCommand = async (input: string): Promise<CommandOutput | void> => {
|
|
42
|
+
const applicationManager = useApplicationManager()
|
|
43
|
+
|
|
44
|
+
const [name, ...args] = input.trim().split(/\s+/)
|
|
45
|
+
|
|
46
|
+
if (!name) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!commands.has(name)) {
|
|
51
|
+
return {
|
|
52
|
+
message: `Command "${name}" not found`,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const application = commands.get(name)!
|
|
57
|
+
|
|
58
|
+
return applicationManager.execAppCommand(application.applicationId, input)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
addCommand,
|
|
63
|
+
listCommands,
|
|
64
|
+
execCommand,
|
|
65
|
+
}
|
|
7
66
|
}
|
|
@@ -4,14 +4,13 @@ import { useApplicationManager } from '../../composables/useApplicationManager'
|
|
|
4
4
|
import { useApplicationWindowsStore } from '../../stores/storeApplicationWindows'
|
|
5
5
|
import { useApplicationMetaStore } from '../../stores/storeApplicationMeta'
|
|
6
6
|
import { useTerminalManager } from '../../composables/useTerminalManager'
|
|
7
|
-
import { useDesktopManager } from '../../composables/useDesktopManager'
|
|
8
7
|
import { debugLog, debugError } from '../../utils/utilDebug'
|
|
8
|
+
import { useDesktopDefaultAppsStore } from '../../stores/storeDesktopDefaultApps'
|
|
9
9
|
import { useDesktopWorkspaceStore } from '../../stores/storeDesktopWorkspace'
|
|
10
10
|
import { reactive } from '@vue/reactivity'
|
|
11
11
|
|
|
12
12
|
export class ApplicationController implements IApplicationController {
|
|
13
13
|
private readonly applicationManager: IApplicationManager
|
|
14
|
-
private readonly desktopManager: IDesktopManager
|
|
15
14
|
private readonly terminalManager: ITerminalManager
|
|
16
15
|
|
|
17
16
|
public readonly id
|
|
@@ -26,7 +25,6 @@ export class ApplicationController implements IApplicationController {
|
|
|
26
25
|
constructor(id: string, config: ApplicationConfig) {
|
|
27
26
|
this.applicationManager = useApplicationManager()
|
|
28
27
|
this.terminalManager = useTerminalManager()
|
|
29
|
-
this.desktopManager = useDesktopManager()
|
|
30
28
|
|
|
31
29
|
this.id = id
|
|
32
30
|
this.config = config
|
|
@@ -35,20 +33,22 @@ export class ApplicationController implements IApplicationController {
|
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
public async initApplication(): Promise<void> {
|
|
36
|
+
const desktopDefaultAppsStore = useDesktopDefaultAppsStore()
|
|
37
|
+
|
|
38
38
|
// provides
|
|
39
39
|
|
|
40
40
|
// set as default app for specific purposes
|
|
41
41
|
// todo improve this and move it in a store
|
|
42
42
|
if (this.config.provides) {
|
|
43
|
-
const existingDefault =
|
|
43
|
+
const existingDefault = desktopDefaultAppsStore.getDefaultApp(
|
|
44
44
|
this.config.provides.name,
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
if (!existingDefault) {
|
|
48
|
-
|
|
48
|
+
desktopDefaultAppsStore.setDefaultApp(
|
|
49
49
|
this.config.provides.name,
|
|
50
50
|
this,
|
|
51
|
-
this.config.provides.
|
|
51
|
+
this.config.provides.entry,
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
debugLog(
|
|
@@ -208,7 +208,7 @@ export class WindowController implements IWindowController {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
// set focus false on all other windows
|
|
211
|
-
for (const [windowId, window] of applicationManager.windowsOpened) {
|
|
211
|
+
for (const [windowId, window] of applicationManager.windowsOpened.value) {
|
|
212
212
|
window.actions.setFocus(false)
|
|
213
213
|
}
|
|
214
214
|
|
|
@@ -283,7 +283,7 @@ export class WindowController implements IWindowController {
|
|
|
283
283
|
maxHeight:
|
|
284
284
|
typeof stateSize.maxHeight !== 'undefined'
|
|
285
285
|
? stateSize.maxHeight
|
|
286
|
-
:
|
|
286
|
+
: configSize.maxHeight,
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// actually unused
|
|
2
|
+
|
|
1
3
|
import { defineStore } from 'pinia'
|
|
2
4
|
import { reactive, ref, computed } from 'vue'
|
|
3
5
|
import { nanoid } from 'nanoid'
|
|
@@ -6,7 +8,7 @@ import { useApplicationManager } from '../composables/useApplicationManager'
|
|
|
6
8
|
import { useApplicationWindowsStore } from './storeApplicationWindows'
|
|
7
9
|
import { useApplicationMetaStore } from './storeApplicationMeta'
|
|
8
10
|
import { useTerminalManager } from '../composables/useTerminalManager'
|
|
9
|
-
import {
|
|
11
|
+
import { useDesktopDefaultAppsStore } from './storeDesktopDefaultApps'
|
|
10
12
|
import { useDesktopWorkspaceStore } from './storeDesktopWorkspace'
|
|
11
13
|
import { debugLog, debugError } from '../utils/utilDebug'
|
|
12
14
|
|
|
@@ -22,13 +24,12 @@ export const useApplicationStore = function(applicationId: string, applicationCo
|
|
|
22
24
|
const windows = reactive(new Map<string, WindowController>())
|
|
23
25
|
const isRunning = ref<boolean>(false)
|
|
24
26
|
|
|
25
|
-
// composables
|
|
27
|
+
// composables and external stores
|
|
26
28
|
const applicationManager = useApplicationManager()
|
|
27
29
|
const terminalManager = useTerminalManager()
|
|
28
|
-
const
|
|
30
|
+
const desktopDefaultAppsStore = useDesktopDefaultAppsStore()
|
|
29
31
|
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
30
32
|
|
|
31
|
-
// stores figli
|
|
32
33
|
let storeWindows: ReturnType<typeof useApplicationWindowsStore>
|
|
33
34
|
let storeMeta: ReturnType<typeof useApplicationMetaStore>
|
|
34
35
|
|
|
@@ -37,13 +38,13 @@ export const useApplicationStore = function(applicationId: string, applicationCo
|
|
|
37
38
|
storeWindows = useApplicationWindowsStore(applicationId)
|
|
38
39
|
storeMeta = useApplicationMetaStore(applicationId)
|
|
39
40
|
|
|
40
|
-
//
|
|
41
|
+
// set default app
|
|
41
42
|
if (applicationConfig.provides) {
|
|
42
|
-
const existingDefault =
|
|
43
|
+
const existingDefault = desktopDefaultAppsStore.getDefaultApp(
|
|
43
44
|
applicationConfig.provides.name,
|
|
44
45
|
)
|
|
45
46
|
if (!existingDefault) {
|
|
46
|
-
|
|
47
|
+
desktopDefaultAppsStore.setDefaultApp(
|
|
47
48
|
applicationConfig.provides.name,
|
|
48
49
|
store, // store o qualcosa che rappresenta questa app?
|
|
49
50
|
applicationConfig.entries![applicationConfig.provides.entry]!,
|
|
@@ -54,7 +55,7 @@ export const useApplicationStore = function(applicationId: string, applicationCo
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
//
|
|
58
|
+
// register terminal commands
|
|
58
59
|
if (applicationConfig.commands) {
|
|
59
60
|
for (const commandKey of Object.keys(applicationConfig.commands)) {
|
|
60
61
|
terminalManager.addCommand({
|
|
@@ -16,6 +16,7 @@ export const useDesktopStore = defineStore(
|
|
|
16
16
|
window: {
|
|
17
17
|
positionZ: number
|
|
18
18
|
}
|
|
19
|
+
defaultApps: {[key: string]: string}
|
|
19
20
|
}>({
|
|
20
21
|
workspace: {
|
|
21
22
|
overview: false,
|
|
@@ -28,6 +29,7 @@ export const useDesktopStore = defineStore(
|
|
|
28
29
|
window: {
|
|
29
30
|
positionZ: 0,
|
|
30
31
|
},
|
|
32
|
+
defaultApps: {}
|
|
31
33
|
})
|
|
32
34
|
|
|
33
35
|
return {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { useDesktopStore } from './storeDesktop'
|
|
3
|
+
|
|
4
|
+
export const useDesktopDefaultAppsStore = defineStore(
|
|
5
|
+
'owd/desktop/defaultApps',
|
|
6
|
+
() => {
|
|
7
|
+
const desktopStore = useDesktopStore()
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sets a default app for a given feature
|
|
11
|
+
*/
|
|
12
|
+
function setDefaultApp(
|
|
13
|
+
feature: string,
|
|
14
|
+
application: IApplicationController,
|
|
15
|
+
entry: string,
|
|
16
|
+
) {
|
|
17
|
+
if (!desktopStore.state.hasOwnProperty('defaultApps')) {
|
|
18
|
+
desktopStore.state.defaultApps = {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
desktopStore.state.defaultApps[feature] = {
|
|
22
|
+
applicationId: application.id,
|
|
23
|
+
entry,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets the default app config for a given feature
|
|
29
|
+
*/
|
|
30
|
+
function getDefaultApp(feature: string): DefaultAppConfig {
|
|
31
|
+
if (!desktopStore.state.hasOwnProperty('defaultApps')) {
|
|
32
|
+
desktopStore.state.defaultApps = {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return desktopStore.state.defaultApps[feature] as DefaultAppConfig
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Loads default apps from current config
|
|
40
|
+
*/
|
|
41
|
+
function loadDefaultAppsFromConfig(runtimeConfig) {
|
|
42
|
+
if (runtimeConfig.public.desktop.defaultApps) {
|
|
43
|
+
desktopStore.state.defaultApps = runtimeConfig.public.desktop.defaultApps
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
setDefaultApp,
|
|
49
|
+
getDefaultApp,
|
|
50
|
+
loadDefaultAppsFromConfig,
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
)
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
|
|
3
|
-
type ClipboardOperation = 'copy' | 'cut'
|
|
4
|
-
|
|
5
|
-
const clipboardFiles = ref<string[]>([])
|
|
6
|
-
const clipboardType = ref<ClipboardOperation | null>(null)
|
|
7
|
-
|
|
8
|
-
export function useClipboardFs() {
|
|
9
|
-
function setClipboard(paths: string[], type: ClipboardOperation) {
|
|
10
|
-
clipboardFiles.value = paths
|
|
11
|
-
clipboardType.value = type
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function clearClipboard() {
|
|
15
|
-
clipboardFiles.value = []
|
|
16
|
-
clipboardType.value = null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
clipboardFiles,
|
|
21
|
-
clipboardType,
|
|
22
|
-
setClipboard,
|
|
23
|
-
clearClipboard,
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import type { Reactive } from '@vue/reactivity'
|
|
2
|
-
import { reactive, markRaw } from '@vue/reactivity'
|
|
3
|
-
import { ApplicationController } from '../controllers/ApplicationController'
|
|
4
|
-
import { normalizeApplicationConfig } from '../../utils/utilApp'
|
|
5
|
-
import { debugLog } from '../../utils/utilDebug'
|
|
6
|
-
import * as shellwords from 'shellwords'
|
|
7
|
-
import yargsParser from 'yargs-parser'
|
|
8
|
-
|
|
9
|
-
export class ApplicationManager implements IApplicationManager {
|
|
10
|
-
public apps = reactive(new Map<string, IApplicationController>())
|
|
11
|
-
|
|
12
|
-
constructor() {}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Define new application
|
|
16
|
-
*
|
|
17
|
-
* @param id
|
|
18
|
-
* @param config
|
|
19
|
-
*/
|
|
20
|
-
public async defineApp(id: string, config: ApplicationConfig) {
|
|
21
|
-
if (this.isAppDefined(id)) {
|
|
22
|
-
debugLog(`App "${id}" is already defined`)
|
|
23
|
-
return this.getAppById(id)!
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const normalizedConfig = normalizeApplicationConfig(config)
|
|
27
|
-
const applicationConfig = markRaw(normalizedConfig)
|
|
28
|
-
|
|
29
|
-
const applicationController: IApplicationController = new ApplicationController(id, applicationConfig)
|
|
30
|
-
await applicationController.initApplication()
|
|
31
|
-
|
|
32
|
-
this.apps.set(id, applicationController)
|
|
33
|
-
|
|
34
|
-
return applicationController
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Check if app has been defned
|
|
39
|
-
*
|
|
40
|
-
* @param {string} id
|
|
41
|
-
*/
|
|
42
|
-
public isAppDefined(id: string) {
|
|
43
|
-
return this.getAppById(id)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Retrieves an app instance by its unique identifier
|
|
48
|
-
*
|
|
49
|
-
* @param {string} id
|
|
50
|
-
*/
|
|
51
|
-
public getAppById(id: string) {
|
|
52
|
-
return this.apps.get(id)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Check if app is running
|
|
57
|
-
*
|
|
58
|
-
* @param {string} id
|
|
59
|
-
*/
|
|
60
|
-
public isAppRunning(id: string) {
|
|
61
|
-
if (!this.isAppDefined(id)) {
|
|
62
|
-
throw Error(`App "${id}" is not defined`)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const applicationController: IApplicationController = this.getAppById(id)!
|
|
66
|
-
|
|
67
|
-
if (!applicationController.isRunning) {
|
|
68
|
-
return false
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return true
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Launch app entry
|
|
76
|
-
*
|
|
77
|
-
* @param id
|
|
78
|
-
* @param entryKey
|
|
79
|
-
*/
|
|
80
|
-
public async launchAppEntry(
|
|
81
|
-
id: string,
|
|
82
|
-
entryKey: string,
|
|
83
|
-
): Promise<IApplicationController | undefined | void> {
|
|
84
|
-
if (!this.isAppDefined(id)) {
|
|
85
|
-
throw Error(`App "${id}" is not defined`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const applicationController: IApplicationController = this.getAppById(id)!
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
applicationController.config.entries &&
|
|
92
|
-
!applicationController.config.entries.hasOwnProperty(entryKey)
|
|
93
|
-
) {
|
|
94
|
-
throw Error(`App entry "${entryKey}" is not defined in ${id} application`)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const entry: ApplicationEntry = applicationController.config.entries[entryKey]!
|
|
98
|
-
|
|
99
|
-
await this.execAppCommand(applicationController.id, entry.command)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Run app command
|
|
104
|
-
*
|
|
105
|
-
* @param id
|
|
106
|
-
* @param rawCommand
|
|
107
|
-
*/
|
|
108
|
-
public async execAppCommand(
|
|
109
|
-
id: string,
|
|
110
|
-
rawCommand: string,
|
|
111
|
-
): Promise<CommandOutput> {
|
|
112
|
-
if (!this.isAppDefined(id)) {
|
|
113
|
-
throw Error(`App "${id}" is not defined`)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const applicationController: IApplicationController = this.getAppById(id)!
|
|
117
|
-
|
|
118
|
-
const args = shellwords.split(rawCommand)
|
|
119
|
-
const parsed = yargsParser(args)
|
|
120
|
-
const command: string = parsed._[0]
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
applicationController.config.commands &&
|
|
124
|
-
!applicationController.config.commands.hasOwnProperty(command)
|
|
125
|
-
) {
|
|
126
|
-
throw Error(
|
|
127
|
-
`App command "${command}" is not defined in ${id} application`,
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const commandFn: any = applicationController.config.commands![command]
|
|
132
|
-
|
|
133
|
-
const commandOutput = await commandFn(
|
|
134
|
-
applicationController,
|
|
135
|
-
parsed,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
applicationController.setRunning(true)
|
|
139
|
-
|
|
140
|
-
return commandOutput
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Close application
|
|
145
|
-
*
|
|
146
|
-
* @param id
|
|
147
|
-
*/
|
|
148
|
-
public closeApp(id: string) {
|
|
149
|
-
if (!this.isAppDefined(id)) {
|
|
150
|
-
throw Error(`App "${id}" is not defined`)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const applicationController: IApplicationController = this.getAppById(id)!
|
|
154
|
-
|
|
155
|
-
applicationController.closeAllWindows()
|
|
156
|
-
applicationController.setRunning(false)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Array of available menu entries for system bars, docks
|
|
161
|
-
*/
|
|
162
|
-
public get appsEntries() {
|
|
163
|
-
const entries: Reactive<ApplicationEntryWithInherited[]> = reactive([])
|
|
164
|
-
|
|
165
|
-
for (const applicationController of this.apps.values()) {
|
|
166
|
-
if (!applicationController.config.entries) {
|
|
167
|
-
continue
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
for (const entryKey of Object.keys(
|
|
171
|
-
applicationController.config.entries,
|
|
172
|
-
)) {
|
|
173
|
-
const entry: ApplicationEntry =
|
|
174
|
-
applicationController.config.entries[entryKey]!
|
|
175
|
-
|
|
176
|
-
entries.push({
|
|
177
|
-
application: applicationController,
|
|
178
|
-
title:
|
|
179
|
-
entry.title !== undefined
|
|
180
|
-
? entry.title
|
|
181
|
-
: applicationController.config.title,
|
|
182
|
-
icon:
|
|
183
|
-
entry.icon !== undefined
|
|
184
|
-
? entry.icon
|
|
185
|
-
: applicationController.config.icon,
|
|
186
|
-
category:
|
|
187
|
-
entry.category !== undefined
|
|
188
|
-
? entry.category
|
|
189
|
-
: applicationController.config.category,
|
|
190
|
-
visibility: entry.visibility ?? 'primary',
|
|
191
|
-
command: entry.command,
|
|
192
|
-
})
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return entries
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Array of opened windows for system bars, docks
|
|
201
|
-
*/
|
|
202
|
-
public get windowsOpened() {
|
|
203
|
-
const windows: Reactive<Map<string, IWindowController>[]> = reactive([])
|
|
204
|
-
|
|
205
|
-
for (const applicationController of this.apps.values()) {
|
|
206
|
-
if (applicationController.isRunning) {
|
|
207
|
-
windows.push(...applicationController.windows)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return windows
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Array of opened windows for system bars, docks
|
|
216
|
-
*/
|
|
217
|
-
public get appsRunning() {
|
|
218
|
-
const applications: Reactive<IApplicationController[]> = reactive([])
|
|
219
|
-
|
|
220
|
-
for (const applicationController of this.apps.values()) {
|
|
221
|
-
if (applicationController.isRunning) {
|
|
222
|
-
applications.push(applicationController)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return applications
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
public getWindowOpenedId(windowId: string) {
|
|
230
|
-
const mapWindowFound: Map<string, IWindowController> | undefined =
|
|
231
|
-
this.windowsOpened.find((window: any) => {
|
|
232
|
-
return window[1].state.id === windowId
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
if (mapWindowFound) {
|
|
236
|
-
// @ts-ignore
|
|
237
|
-
return mapWindowFound[1] as IWindowController
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Gets all unique categories from the installed apps
|
|
243
|
-
*/
|
|
244
|
-
public get appCategories(): string[] {
|
|
245
|
-
const categories = new Set<string>()
|
|
246
|
-
|
|
247
|
-
for (const applicationController of this.apps.values()) {
|
|
248
|
-
if (applicationController.config.category) {
|
|
249
|
-
categories.add(applicationController.config.category)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return Array.from(categories).sort()
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Gets the apps ordered by category
|
|
257
|
-
*/
|
|
258
|
-
public get appsByCategory(): {
|
|
259
|
-
[category: string]: IApplicationController[]
|
|
260
|
-
} {
|
|
261
|
-
const categorizedApps: {
|
|
262
|
-
[category: string]: IApplicationController[]
|
|
263
|
-
} = {}
|
|
264
|
-
|
|
265
|
-
for (const applicationController of this.apps.values()) {
|
|
266
|
-
const category = applicationController.config.category || 'other'
|
|
267
|
-
if (!categorizedApps[category]) {
|
|
268
|
-
categorizedApps[category] = []
|
|
269
|
-
}
|
|
270
|
-
categorizedApps[category].push(applicationController)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
for (const category in categorizedApps) {
|
|
274
|
-
categorizedApps[category]!.sort((a, b) =>
|
|
275
|
-
a.config.title.localeCompare(b.config.title),
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return categorizedApps
|
|
280
|
-
}
|
|
281
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export class DesktopManager {
|
|
2
|
-
private defaultApps: DefaultAppsConfig = {}
|
|
3
|
-
|
|
4
|
-
constructor() {}
|
|
5
|
-
|
|
6
|
-
get config(): DesktopConfig {
|
|
7
|
-
const runtimeConfig = useRuntimeConfig()
|
|
8
|
-
|
|
9
|
-
return runtimeConfig.public.desktop
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public hasFeature(featureName: string) {
|
|
13
|
-
return this.config.features?.indexOf(featureName) !== -1
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public setConfig(config: DesktopConfig) {
|
|
17
|
-
const runtimeConfig = useRuntimeConfig()
|
|
18
|
-
|
|
19
|
-
runtimeConfig.public.desktop = deepMerge(
|
|
20
|
-
runtimeConfig.public.desktop,
|
|
21
|
-
config
|
|
22
|
-
) as DesktopConfig
|
|
23
|
-
|
|
24
|
-
this.loadDefaultAppsFromConfig()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public setDefaultApp(
|
|
28
|
-
feature: string,
|
|
29
|
-
application: IApplicationController,
|
|
30
|
-
command: string,
|
|
31
|
-
) {
|
|
32
|
-
this.defaultApps[feature] = {
|
|
33
|
-
application,
|
|
34
|
-
command,
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public getDefaultApp(feature: string): DefaultAppConfig {
|
|
39
|
-
return this.defaultApps[feature] as DefaultAppConfig
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private loadDefaultAppsFromConfig() {
|
|
43
|
-
if (this.config.defaultApps) {
|
|
44
|
-
this.defaultApps = { ...this.config.defaultApps }
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { useApplicationManager } from '../../composables/useApplicationManager'
|
|
2
|
-
import { debugLog } from '../../utils/utilDebug'
|
|
3
|
-
|
|
4
|
-
export class TerminalManager {
|
|
5
|
-
private commands: Map<string, TerminalCommand> = new Map()
|
|
6
|
-
|
|
7
|
-
constructor() {}
|
|
8
|
-
|
|
9
|
-
public addCommand(command: TerminalCommand) {
|
|
10
|
-
for (const existingCommand of this.commands.keys()) {
|
|
11
|
-
if (
|
|
12
|
-
existingCommand.startsWith(command.name) ||
|
|
13
|
-
command.name.startsWith(existingCommand)
|
|
14
|
-
) {
|
|
15
|
-
throw new Error(`Command prefix conflict with "${existingCommand}"`)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
this.commands.set(command.name, command)
|
|
20
|
-
debugLog(
|
|
21
|
-
`Registered terminal command: ${command.name} → ${command.applicationId}`,
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public listCommands(): string[] {
|
|
26
|
-
return Array.from(this.commands.keys())
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public async execCommand(input: string): Promise<CommandOutput | void> {
|
|
30
|
-
const applicationManager = useApplicationManager()
|
|
31
|
-
|
|
32
|
-
const [name, ...args] = input.trim().split(/\s+/)
|
|
33
|
-
|
|
34
|
-
if (!name) {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!this.commands.has(name)) {
|
|
39
|
-
return {
|
|
40
|
-
message: `Command "${name}" not found`,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const application = this.commands.get(name)!
|
|
45
|
-
|
|
46
|
-
return applicationManager.execAppCommand(application.applicationId, input)
|
|
47
|
-
}
|
|
48
|
-
}
|