@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 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
- // set core version to runtime config
53
+ // init desktop runtime config and define core version
54
54
 
55
- _nuxt.options.runtimeConfig.public.coreVersion = pkg.version
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-beta.0",
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
- "yargs-parser": "^22.0.0"
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 applicationManager = useApplicationManager()
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--${desktopManager.config.name}`)
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('desktopManager.config.windows.position');
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 { ApplicationManager } from '../core/managers/ApplicationManager'
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 applicationManager = new ApplicationManager()
8
+ const apps = reactive(new Map<string, IApplicationController>())
4
9
 
5
- export function useApplicationManager(): IApplicationManager {
6
- return applicationManager
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 { DesktopManager } from '../core/managers/DesktopManager'
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
- return desktopManager
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 { TerminalManager } from '../core/managers/TerminalManager'
1
+ import { useApplicationManager } from './useApplicationManager'
2
+ import { debugLog } from '../utils/utilDebug'
2
3
 
3
- const terminalManager = new TerminalManager()
4
+ const commands = new Map<string, TerminalCommand>()
4
5
 
6
+ /**
7
+ * Terminal Manager Composable (Singleton)
8
+ */
5
9
  export function useTerminalManager() {
6
- return terminalManager
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 = this.desktopManager.getDefaultApp(
43
+ const existingDefault = desktopDefaultAppsStore.getDefaultApp(
44
44
  this.config.provides.name,
45
45
  )
46
46
 
47
47
  if (!existingDefault) {
48
- this.desktopManager.setDefaultApp(
48
+ desktopDefaultAppsStore.setDefaultApp(
49
49
  this.config.provides.name,
50
50
  this,
51
- this.config.provides.command,
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
- : (configSize.maxHeight ?? 600),
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 { useDesktopManager } from '../composables/useDesktopManager'
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 e stores esterni
27
+ // composables and external stores
26
28
  const applicationManager = useApplicationManager()
27
29
  const terminalManager = useTerminalManager()
28
- const desktopManager = useDesktopManager()
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
- // Fornisci applicazione di default se presente
41
+ // set default app
41
42
  if (applicationConfig.provides) {
42
- const existingDefault = desktopManager.getDefaultApp(
43
+ const existingDefault = desktopDefaultAppsStore.getDefaultApp(
43
44
  applicationConfig.provides.name,
44
45
  )
45
46
  if (!existingDefault) {
46
- desktopManager.setDefaultApp(
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
- // registra comandi terminale
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
- }