@owdproject/core 3.1.3 → 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.
Files changed (50) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +6 -7
  3. package/bin/owd.js +14 -14
  4. package/index.ts +5 -2
  5. package/module.ts +78 -61
  6. package/package.json +19 -17
  7. package/project.json +4 -0
  8. package/runtime/components/Core/Application/CoreApplicationRender.vue +6 -5
  9. package/runtime/components/Core/Application/CoreApplicationWindowsRender.vue +8 -8
  10. package/runtime/components/Core/Background/CoreBackground.vue +1 -1
  11. package/runtime/components/Core/Desktop/CoreDesktop.vue +31 -24
  12. package/runtime/components/Core/Explorer/CoreExplorerFile.vue +47 -38
  13. package/runtime/components/Core/Explorer/CoreExplorerFolder.vue +0 -1
  14. package/runtime/components/Core/Time/CoreTime.vue +10 -7
  15. package/runtime/components/Core/Window/CoreWindow.vue +49 -35
  16. package/runtime/components/Core/Window/CoreWindowContent.vue +3 -5
  17. package/runtime/components/Core/Window/CoreWindowNav.vue +12 -7
  18. package/runtime/composables/useApplicationEntries.ts +51 -0
  19. package/runtime/composables/useApplicationManager.ts +278 -5
  20. package/runtime/composables/useDesktopManager.ts +22 -4
  21. package/runtime/composables/useTerminalManager.ts +63 -4
  22. package/runtime/core/controllers/ApplicationController.ts +203 -192
  23. package/runtime/core/controllers/WindowController.ts +342 -334
  24. package/runtime/plugins/resize.client.ts +4 -4
  25. package/runtime/stores/storeApplication.ts +236 -0
  26. package/runtime/stores/storeApplicationMeta.ts +12 -8
  27. package/runtime/stores/storeApplicationWindows.ts +16 -12
  28. package/runtime/stores/storeDesktop.ts +35 -29
  29. package/runtime/stores/storeDesktopDefaultApps.ts +53 -0
  30. package/runtime/stores/storeDesktopVolume.ts +12 -12
  31. package/runtime/stores/storeDesktopWindow.ts +13 -13
  32. package/runtime/stores/storeDesktopWorkspace.ts +35 -31
  33. package/runtime/utils/utilApp.ts +27 -22
  34. package/runtime/utils/utilCommon.ts +43 -43
  35. package/runtime/utils/utilDebug.ts +17 -17
  36. package/runtime/utils/utilDesktop.ts +4 -4
  37. package/runtime/utils/utilTerminal.ts +6 -5
  38. package/runtime/utils/utilWindow.ts +11 -11
  39. package/test/fixtures/basic/app.vue +1 -2
  40. package/test/fixtures/basic/nuxt.config.ts +1 -3
  41. package/tsconfig.app.json +1 -1
  42. package/tsconfig.json +1 -1
  43. package/types/index.d.ts +235 -207
  44. package/vitest.config.ts +3 -3
  45. package/eslint.config.mjs +0 -30
  46. package/runtime/composables/useAppEntries.ts +0 -36
  47. package/runtime/composables/useClipboardFs.ts +0 -25
  48. package/runtime/core/managers/ApplicationManager.ts +0 -237
  49. package/runtime/core/managers/DesktopManager.ts +0 -37
  50. package/runtime/core/managers/TerminalManager.ts +0 -44
@@ -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
7
- }
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
+ }
66
+ }
@@ -1,244 +1,255 @@
1
- import {nanoid} from "nanoid";
2
- import {WindowController} from "./WindowController";
3
- import {useApplicationManager} from "../../composables/useApplicationManager"
4
- import {useApplicationWindowsStore} from "../../stores/storeApplicationWindows"
5
- import {useApplicationMetaStore} from "../../stores/storeApplicationMeta"
6
- import {useTerminalManager} from "../../composables/useTerminalManager"
7
- import {useDesktopManager} from "../../composables/useDesktopManager"
8
- import {debugLog, debugError} from "../../utils/utilDebug"
9
- import {useDesktopWorkspaceStore} from "../../stores/storeDesktopWorkspace"
10
- import {reactive} from '@vue/reactivity'
1
+ import { nanoid } from 'nanoid'
2
+ import { WindowController } from './WindowController'
3
+ import { useApplicationManager } from '../../composables/useApplicationManager'
4
+ import { useApplicationWindowsStore } from '../../stores/storeApplicationWindows'
5
+ import { useApplicationMetaStore } from '../../stores/storeApplicationMeta'
6
+ import { useTerminalManager } from '../../composables/useTerminalManager'
7
+ import { debugLog, debugError } from '../../utils/utilDebug'
8
+ import { useDesktopDefaultAppsStore } from '../../stores/storeDesktopDefaultApps'
9
+ import { useDesktopWorkspaceStore } from '../../stores/storeDesktopWorkspace'
10
+ import { reactive } from '@vue/reactivity'
11
11
 
12
12
  export class ApplicationController implements IApplicationController {
13
- private readonly applicationManager: IApplicationManager
14
- private readonly desktopManager: IDesktopManager
15
- private readonly terminalManager: ITerminalManager
13
+ private readonly applicationManager: IApplicationManager
14
+ private readonly terminalManager: ITerminalManager
16
15
 
17
- public readonly id
18
- public readonly config
19
- public readonly store
16
+ public readonly id
17
+ public readonly config
18
+ public readonly storeWindows
19
+ public readonly storeMeta
20
20
 
21
- public windows = reactive(new Map<string, IWindowController>())
21
+ public windows = reactive(new Map<string, IWindowController>())
22
22
 
23
- public isRunning: boolean = false
23
+ public isRunning = false
24
24
 
25
- constructor(
26
- id: string,
27
- config: ApplicationConfig
28
- ) {
29
- this.applicationManager = useApplicationManager()
30
- this.terminalManager = useTerminalManager()
31
- this.desktopManager = useDesktopManager()
32
-
33
- this.id = id
34
- this.config = config
35
- this.storeWindows = useApplicationWindowsStore(id)
36
- this.storeMeta = useApplicationMetaStore(id)
37
- }
38
-
39
- public async initApplication(): Promise<void> {
40
-
41
- // provides
42
-
43
- // set as default app for specific purposes
44
- // todo improve this and move it in a store
45
- if (this.config.provides) {
46
- const existingDefault = this.desktopManager.getDefaultApp(this.config.provides.name)
25
+ constructor(id: string, config: ApplicationConfig) {
26
+ this.applicationManager = useApplicationManager()
27
+ this.terminalManager = useTerminalManager()
47
28
 
48
- if (!existingDefault) {
49
- this.desktopManager.setDefaultApp(
50
- this.config.provides.name,
51
- this,
52
- this.config.entries[this.config.provides.entry] as ApplicationEntry
53
- )
29
+ this.id = id
30
+ this.config = config
31
+ this.storeWindows = useApplicationWindowsStore(id)
32
+ this.storeMeta = useApplicationMetaStore(id)
33
+ }
54
34
 
55
- debugLog(`${this.config.title} has been set as predefined app for "${this.config.provides.name}"`)
56
- }
57
- }
35
+ public async initApplication(): Promise<void> {
36
+ const desktopDefaultAppsStore = useDesktopDefaultAppsStore()
58
37
 
59
- // terminal
38
+ // provides
60
39
 
61
- if (this.config.commands) {
62
- for (const commandKey of Object.keys(this.config.commands)) {
63
- this.terminalManager.addCommand({
64
- applicationId: this.id,
65
- name: commandKey
66
- })
67
- }
68
- }
40
+ // set as default app for specific purposes
41
+ // todo improve this and move it in a store
42
+ if (this.config.provides) {
43
+ const existingDefault = desktopDefaultAppsStore.getDefaultApp(
44
+ this.config.provides.name,
45
+ )
69
46
 
70
- // store
71
-
72
- if (this.storeWindows.$persistedState) {
73
- await this.storeWindows.$persistedState.isReady()
74
- }
75
-
76
- if (this.storeMeta.$persistedState) {
77
- await this.storeMeta.$persistedState.isReady()
78
- }
79
-
80
- // set default meta values
81
- // this.storeMeta.meta = this.config.meta ?? {}
82
-
83
- // restore application state
84
- await this.restoreApplication()
47
+ if (!existingDefault) {
48
+ desktopDefaultAppsStore.setDefaultApp(
49
+ this.config.provides.name,
50
+ this,
51
+ this.config.provides.entry,
52
+ )
85
53
 
86
- // once app is defined, always run "onReady"
87
- if (typeof this.config.onReady === 'function') {
88
- // todo transform in hook
89
- this.config.onReady(this)
90
- }
54
+ debugLog(
55
+ `${this.config.title} has been set as predefined app for "${this.config.provides.name}"`,
56
+ )
57
+ }
91
58
  }
92
59
 
93
- /**
94
- * App always tries to restore previous windows
95
- * and returns a boolean if it succeeded
96
- */
97
- public async restoreApplication() {
98
- if (typeof this.config.onRestore === 'function') {
99
- // todo transform in hook
100
- await this.config.onRestore(this)
101
- }
60
+ // terminal
102
61
 
103
- if (!this.storeWindows.windows || Object.keys(this.storeWindows.windows).length === 0) {
104
- return false
105
- }
62
+ if (this.config.commands) {
63
+ for (const commandKey of Object.keys(this.config.commands)) {
64
+ this.terminalManager.addCommand({
65
+ applicationId: this.id,
66
+ name: commandKey,
67
+ })
68
+ }
69
+ }
106
70
 
107
- this.restoreWindows()
71
+ // store
108
72
 
109
- this.setRunning(true)
73
+ if (this.storeWindows.$persistedState) {
74
+ await this.storeWindows.$persistedState.isReady()
75
+ }
110
76
 
111
- return true
77
+ if (this.storeMeta.$persistedState) {
78
+ await this.storeMeta.$persistedState.isReady()
112
79
  }
113
80
 
114
- private restoreWindows() {
115
- Object.keys(this.storeWindows.windows).map(windowId => {
116
- const windowStore: WindowStoredState | undefined = this.storeWindows.windows[windowId]
81
+ // set default meta values
82
+ // this.storeMeta.meta = this.config.meta ?? {}
117
83
 
118
- if (windowStore) {
119
- this.openWindow(windowStore.model, windowStore, {isRestoring: true})
120
- }
121
- })
84
+ // restore application state
85
+ await this.restoreApplication()
122
86
 
123
- debugLog('Windows have been restored', this.windows)
87
+ // once app is defined, always run "onReady"
88
+ if (typeof this.config.onReady === 'function') {
89
+ // todo transform in hook
90
+ this.config.onReady(this)
91
+ }
92
+ }
93
+
94
+ /**
95
+ * App always tries to restore previous windows
96
+ * and returns a boolean if it succeeded
97
+ */
98
+ public async restoreApplication() {
99
+ if (typeof this.config.onRestore === 'function') {
100
+ // todo transform in hook
101
+ await this.config.onRestore(this)
124
102
  }
125
103
 
126
- public openWindow(model: string, windowStoredState: WindowStoredState | undefined, meta?: any) {
127
- const desktopWorkspaceStore = useDesktopWorkspaceStore()
128
-
129
- if (!this.config.windows || !this.config.windows.hasOwnProperty(model)) {
130
- debugError(`Window model "${model}" not found`)
131
- return
132
- }
133
-
134
- let windowId: string
104
+ if (
105
+ !this.storeWindows.windows ||
106
+ Object.keys(this.storeWindows.windows).length === 0
107
+ ) {
108
+ return false
109
+ }
135
110
 
136
- if (!windowStoredState) {
111
+ this.restoreWindows()
137
112
 
138
- windowId = `${model}-${nanoid(6)}`
113
+ this.setRunning(true)
139
114
 
140
- const windowConfig: WindowConfig = this.config.windows[model] as WindowConfig
141
- const screenHeight = window.innerHeight
142
- const centerY = (screenHeight - Number(windowConfig.size.height)) / 2
143
- const positionY = windowConfig.position?.y !== undefined
144
- ? window.scrollY + windowConfig.position.y
145
- : window.scrollY + centerY
115
+ return true
116
+ }
146
117
 
147
- this.storeWindows.windows[windowId] = {
148
- model,
149
- state: {
150
- id: windowId,
151
- active: true,
152
- focused: false,
153
- position: {
154
- x: windowConfig.position?.x,
155
- y: positionY,
156
- },
157
- createdAt: +new Date(),
158
- workspace: desktopWorkspaceStore.active
159
- },
160
- meta
161
- }
118
+ private restoreWindows() {
119
+ Object.keys(this.storeWindows.windows).map((windowId) => {
120
+ const windowStore: WindowStoredState | undefined =
121
+ this.storeWindows.windows[windowId]
162
122
 
163
- windowStoredState = this.storeWindows.windows[windowId]
123
+ if (windowStore) {
124
+ this.openWindow(windowStore.model, windowStore, {
125
+ isRestoring: true,
126
+ })
127
+ }
128
+ })
129
+
130
+ debugLog('Windows have been restored', this.windows)
131
+ }
132
+
133
+ public openWindow(
134
+ model: string,
135
+ windowStoredState: WindowStoredState | undefined,
136
+ meta?: any,
137
+ ) {
138
+ const desktopWorkspaceStore = useDesktopWorkspaceStore()
139
+
140
+ if (!this.config.windows || !this.config.windows.hasOwnProperty(model)) {
141
+ debugError(`Window model "${model}" not found`)
142
+ return
143
+ }
164
144
 
165
- } else {
145
+ let windowId: string
146
+
147
+ if (!windowStoredState) {
148
+ windowId = `${model}-${nanoid(6)}`
149
+
150
+ const windowConfig: WindowConfig = this.config.windows[
151
+ model
152
+ ] as WindowConfig
153
+ const screenHeight = window.innerHeight
154
+ const centerY = (screenHeight - Number(windowConfig.size.height)) / 2
155
+ const positionY =
156
+ windowConfig.position?.y !== undefined
157
+ ? window.scrollY + windowConfig.position.y
158
+ : window.scrollY + centerY
159
+
160
+ this.storeWindows.windows[windowId] = {
161
+ model,
162
+ state: {
163
+ id: windowId,
164
+ active: true,
165
+ focused: false,
166
+ position: {
167
+ x: windowConfig.position?.x,
168
+ y: positionY,
169
+ },
170
+ createdAt: +new Date(),
171
+ workspace: desktopWorkspaceStore.active,
172
+ },
173
+ meta,
174
+ }
175
+
176
+ windowStoredState = this.storeWindows.windows[windowId]
177
+ } else {
178
+ // restore previous id if state is defined
179
+ windowId = windowStoredState.state.id
180
+ }
166
181
 
167
- // restore previous id if state is defined
168
- windowId = windowStoredState.state.id
182
+ const windowConfig = this.config.windows[model] as WindowConfig
169
183
 
170
- }
184
+ const windowController = new WindowController(
185
+ this,
186
+ model,
187
+ windowConfig,
188
+ windowStoredState!,
189
+ )
171
190
 
172
- const windowConfig = this.config.windows[model] as WindowConfig
191
+ if (!meta?.isRestoring) {
192
+ windowController.actions.bringToFront()
193
+ }
173
194
 
174
- const windowController = new WindowController(
175
- this,
176
- model,
177
- windowConfig,
178
- windowStoredState!
179
- )
195
+ this.windows.set(windowId, windowController)
180
196
 
181
- if (!meta?.isRestoring) {
182
- windowController.actions.bringToFront()
183
- }
197
+ this.setRunning(true)
184
198
 
185
- this.windows.set(
186
- windowId,
187
- windowController,
188
- )
199
+ return windowController
200
+ }
189
201
 
190
- this.setRunning(true)
202
+ public closeWindow(windowId: string) {
203
+ delete this.storeWindows.windows[windowId]
204
+ this.windows.delete(windowId)
191
205
 
192
- return windowController
206
+ if (this.windows.size === 0) {
207
+ this.applicationManager.closeApp(this.id)
193
208
  }
209
+ }
194
210
 
195
- public closeWindow(windowId: string) {
196
- delete this.storeWindows.windows[windowId];
197
- this.windows.delete(windowId);
198
-
199
- if (this.windows.size === 0) {
200
- this.applicationManager.closeApp(this.id)
201
- }
202
- }
211
+ public closeAllWindows() {
212
+ this.storeWindows.windows = {}
213
+ this.windows.clear()
214
+ }
203
215
 
204
- public closeAllWindows() {
205
- this.storeWindows.windows = {}
206
- this.windows.clear()
207
- }
216
+ get windowsOpened() {
217
+ return this.windows
218
+ }
208
219
 
209
- get windowsOpened() {
210
- return this.windows;
211
- }
220
+ public getWindowById(id: string): IWindowController[] {
221
+ return this.windows.get(id)
222
+ }
212
223
 
213
- public getWindowsByModel(model: string): IWindowController[] {
214
- return Array.from(this.windows.values()).filter(w => w.model === model)
215
- }
224
+ public getWindowsByModel(model: string): IWindowController[] {
225
+ return Array.from(this.windows.values()).filter((w) => w.model === model)
226
+ }
216
227
 
217
- public getFirstWindowByModel(model: string): IWindowController | undefined {
218
- return Array.from(this.windows.values()).find(w => w.model === model)
219
- }
228
+ public getFirstWindowByModel(model: string): IWindowController | undefined {
229
+ return Array.from(this.windows.values()).find((w) => w.model === model)
230
+ }
220
231
 
221
- public setRunning(value: boolean): void {
222
- this.isRunning = value
223
- }
232
+ public setRunning(value: boolean): void {
233
+ this.isRunning = value
234
+ }
224
235
 
225
- // meta
236
+ // meta
226
237
 
227
- get meta() {
228
- return this.storeMeta.meta
229
- }
238
+ get meta() {
239
+ return this.storeMeta.meta
240
+ }
230
241
 
231
- getMeta(key: string) {
232
- return this.meta[key]
233
- }
242
+ getMeta(key: string) {
243
+ return this.meta[key]
244
+ }
234
245
 
235
- setMeta(key: string, value: any) {
236
- this.meta[key] = value
237
- }
246
+ setMeta(key: string, value: any) {
247
+ this.meta[key] = value
248
+ }
238
249
 
239
- // commands
250
+ // commands
240
251
 
241
- async execCommand(command: string): Promise<CommandOutput | void> {
242
- return this.applicationManager.execAppCommand(this.id, command)
243
- }
252
+ async execCommand(command: string): Promise<CommandOutput | void> {
253
+ return this.applicationManager.execAppCommand(this.id, command)
254
+ }
244
255
  }