@owdproject/core 3.3.1 → 4.0.0-alpha.3
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/README.md +91 -59
- package/dist/dom/index.d.mts +65 -0
- package/dist/dom/index.d.ts +65 -0
- package/dist/dom/index.mjs +224 -0
- package/dist/events/index.d.mts +70 -0
- package/dist/events/index.d.ts +70 -0
- package/dist/events/index.mjs +3 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.mjs +115 -0
- package/dist/layout/index.d.mts +41 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/index.mjs +64 -0
- package/dist/machines/index.d.mts +31 -0
- package/dist/machines/index.d.ts +31 -0
- package/dist/machines/index.mjs +2 -0
- package/dist/managers/index.d.mts +117 -0
- package/dist/managers/index.d.ts +117 -0
- package/dist/managers/index.mjs +6 -0
- package/dist/session/index.d.mts +57 -0
- package/dist/session/index.d.ts +57 -0
- package/dist/session/index.mjs +65 -0
- package/dist/shared/core.B0B0KfVK.mjs +865 -0
- package/dist/shared/core.B1XxB289.mjs +239 -0
- package/dist/shared/core.B3mp7ztE.mjs +237 -0
- package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
- package/dist/shared/core.CsDFgGnX.mjs +40 -0
- package/dist/shared/core.Di1eFcr_.d.mts +114 -0
- package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
- package/dist/shared/core.b3Xldzyu.mjs +29 -0
- package/dist/types/index.d.mts +266 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +60 -87
- package/bin/cli.js +0 -395
- package/bin/desktop.js +0 -5
- package/bin/lib/catalog.js +0 -293
- package/bin/lib/config.js +0 -109
- package/bin/lib/desktopConfig.js +0 -56
- package/bin/lib/generateTemplate.js +0 -389
- package/bin/lib/install.js +0 -408
- package/bin/lib/migrateModulePlayground.config.mjs +0 -164
- package/bin/lib/migrateModulePlayground.mjs +0 -313
- package/bin/lib/npmVersions.js +0 -124
- package/bin/lib/playgroundContext.js +0 -188
- package/bin/lib/scaffold.js +0 -197
- package/bin/lib/status.js +0 -289
- package/bin/lib/validateModule.js +0 -697
- package/bin/lib/workspace.js +0 -182
- package/bin/owd.js +0 -5
- package/bin/tui.js +0 -1379
- package/dist/module.d.mts +0 -13
- package/dist/module.json +0 -9
- package/dist/module.mjs +0 -268
- package/dist/types.d.mts +0 -7
- package/index.ts +0 -5
- package/module.ts +0 -223
- package/runtime/components/Desktop/Application/DesktopApplicationRender.vue +0 -20
- package/runtime/components/Desktop/Application/DesktopApplicationWindowsRender.vue +0 -38
- package/runtime/components/Desktop/Background/DesktopBackground.vue +0 -16
- package/runtime/components/Desktop/Core/DesktopCore.vue +0 -90
- package/runtime/components/Desktop/Time/DesktopTime.vue +0 -56
- package/runtime/components/Desktop/Window/DesktopWindow.vue +0 -204
- package/runtime/components/Desktop/Window/DesktopWindowContent.vue +0 -28
- package/runtime/components/Desktop/Window/DesktopWindowNav.vue +0 -66
- package/runtime/composables/useApplicationEntries.ts +0 -51
- package/runtime/composables/useApplicationManager.ts +0 -285
- package/runtime/composables/useDesktopManager.ts +0 -49
- package/runtime/composables/useTerminalManager.ts +0 -66
- package/runtime/composables/useWorkspaceManager.ts +0 -41
- package/runtime/internal/controllers/ApplicationController.ts +0 -345
- package/runtime/internal/controllers/WindowController.ts +0 -462
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -17
- package/runtime/plugins/resize.client.ts +0 -6
- package/runtime/stores/storeApplicationMeta.ts +0 -59
- package/runtime/stores/storeApplicationWindows.ts +0 -20
- package/runtime/stores/storeDesktop.ts +0 -111
- package/runtime/stores/storeDesktopDefaultApps.ts +0 -53
- package/runtime/stores/storeDesktopVolume.ts +0 -18
- package/runtime/stores/storeDesktopWindow.ts +0 -20
- package/runtime/stores/storeDesktopWorkspace.ts +0 -75
- package/runtime/utils/captureElementToCanvas.ts +0 -21
- package/runtime/utils/explorerEntryPath.ts +0 -10
- package/runtime/utils/resolveDesktopConfigPath.ts +0 -52
- package/runtime/utils/splitDesktopUserConfig.ts +0 -85
- package/runtime/utils/utilApp.ts +0 -37
- package/runtime/utils/utilCommon.ts +0 -26
- package/runtime/utils/utilDebug.ts +0 -30
- package/runtime/utils/utilDesktop.ts +0 -35
- package/runtime/utils/utilTerminal.ts +0 -6
- package/runtime/utils/utilWindow.ts +0 -15
- package/runtime/utils/validateDesktopUserConfig.ts +0 -44
- package/types/index.d.ts +0 -420
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, onUnmounted } from 'vue'
|
|
3
|
-
import { computed } from '@vue/reactivity'
|
|
4
|
-
import { useI18n } from 'vue-i18n'
|
|
5
|
-
|
|
6
|
-
const date: Ref<Date> = ref(new Date())
|
|
7
|
-
const { locale } = useI18n()
|
|
8
|
-
|
|
9
|
-
let minuteTimeout: any
|
|
10
|
-
|
|
11
|
-
onMounted(() => {
|
|
12
|
-
function scheduleNextMinute() {
|
|
13
|
-
const now = new Date()
|
|
14
|
-
const millisecondsToNextMinute =
|
|
15
|
-
(60 - now.getSeconds()) * 1000 - now.getMilliseconds()
|
|
16
|
-
minuteTimeout = setTimeout(() => {
|
|
17
|
-
date.value = new Date()
|
|
18
|
-
scheduleNextMinute()
|
|
19
|
-
}, millisecondsToNextMinute)
|
|
20
|
-
}
|
|
21
|
-
scheduleNextMinute()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
onUnmounted(() => {
|
|
25
|
-
clearTimeout(minuteTimeout)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const time = computed(() => {
|
|
29
|
-
if (!date.value) {
|
|
30
|
-
return ''
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let hours = date.value.getHours()
|
|
34
|
-
let minutes: string = date.value.getMinutes().toString()
|
|
35
|
-
let period = 'AM'
|
|
36
|
-
|
|
37
|
-
if (locale.value !== 'it') {
|
|
38
|
-
if (hours >= 12) {
|
|
39
|
-
period = 'PM'
|
|
40
|
-
if (hours > 12) hours -= 12
|
|
41
|
-
} else if (hours === 0) {
|
|
42
|
-
hours = 12
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (minutes.length === 1) minutes = `0${minutes}`
|
|
47
|
-
|
|
48
|
-
return locale.value === 'it'
|
|
49
|
-
? `${hours}:${minutes}`
|
|
50
|
-
: `${hours}:${minutes} ${period}`
|
|
51
|
-
})
|
|
52
|
-
</script>
|
|
53
|
-
|
|
54
|
-
<template>
|
|
55
|
-
<time class="owd-time" v-text="time" />
|
|
56
|
-
</template>
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, provide } from 'vue'
|
|
3
|
-
import { computed } from '@vue/reactivity'
|
|
4
|
-
import { useAppConfig } from 'nuxt/app'
|
|
5
|
-
import { handleWindowControllerProps } from '@owdproject/core/runtime/utils/utilWindow'
|
|
6
|
-
import { useDesktopWorkspaceStore } from '../../../stores/storeDesktopWorkspace'
|
|
7
|
-
|
|
8
|
-
const props = defineProps<{
|
|
9
|
-
window?: IWindowController
|
|
10
|
-
content?: WindowContent
|
|
11
|
-
}>()
|
|
12
|
-
|
|
13
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
14
|
-
|
|
15
|
-
const emit = defineEmits([
|
|
16
|
-
'resize:start',
|
|
17
|
-
'resize:move',
|
|
18
|
-
'resize:end',
|
|
19
|
-
'drag:start',
|
|
20
|
-
'drag:move',
|
|
21
|
-
'drag:end',
|
|
22
|
-
'close',
|
|
23
|
-
'open',
|
|
24
|
-
'blur',
|
|
25
|
-
'focus',
|
|
26
|
-
'minimize',
|
|
27
|
-
'restore',
|
|
28
|
-
'maximize',
|
|
29
|
-
'unmaximize',
|
|
30
|
-
'toggle-maximize',
|
|
31
|
-
])
|
|
32
|
-
|
|
33
|
-
const appConfig = useAppConfig()
|
|
34
|
-
const windowController: IWindowController = handleWindowControllerProps(
|
|
35
|
-
props.window,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
provide<IWindowController>('windowController', windowController)
|
|
39
|
-
provide<WindowContent>('windowContent', props.content ?? {})
|
|
40
|
-
|
|
41
|
-
const isDragging = ref(false)
|
|
42
|
-
const isResizing = ref(false)
|
|
43
|
-
|
|
44
|
-
function onWindowPointerDown() {
|
|
45
|
-
windowController?.actions?.setActive(true)
|
|
46
|
-
windowController?.actions?.bringToFront()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function onWindowDragStart(data: any) {
|
|
50
|
-
isDragging.value = true
|
|
51
|
-
|
|
52
|
-
emit('drag:start', data)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function onWindowDragMove(data: any) {
|
|
56
|
-
emit('drag:move', data)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function onWindowDragEnd(data: { left: number; top: number }) {
|
|
60
|
-
windowController?.actions?.setPosition({
|
|
61
|
-
x: data.left,
|
|
62
|
-
y: data.top,
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
isDragging.value = false
|
|
66
|
-
|
|
67
|
-
emit('drag:end', data)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function onWindowResizeStart(data: any) {
|
|
71
|
-
isResizing.value = true
|
|
72
|
-
|
|
73
|
-
emit('resize:start', data)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function onWindowResizeMove(data: any) {
|
|
77
|
-
emit('resize:move', data)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Window end resize event
|
|
82
|
-
*/
|
|
83
|
-
function onWindowResizeEnd(data: {
|
|
84
|
-
left: number
|
|
85
|
-
top: number
|
|
86
|
-
width: number
|
|
87
|
-
height: number
|
|
88
|
-
}) {
|
|
89
|
-
isResizing.value = false
|
|
90
|
-
|
|
91
|
-
windowController?.actions?.setPosition({
|
|
92
|
-
x: data.left,
|
|
93
|
-
y: data.top,
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
windowController?.actions?.setSize({
|
|
97
|
-
width: data.width,
|
|
98
|
-
height: data.height,
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
emit('resize:end', data)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const classes = computed(() => {
|
|
105
|
-
const list = ['owd-window']
|
|
106
|
-
|
|
107
|
-
if (windowController?.state.focused) {
|
|
108
|
-
list.push('owd-window--focused')
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (isDragging.value) {
|
|
112
|
-
list.push('owd-window--dragging')
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (isResizing.value) {
|
|
116
|
-
list.push('owd-window--resizing')
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return list
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
/** While workspace overview is open, disable vue-resizable chrome drag and use native HTML5 drag to move windows between desktops. */
|
|
123
|
-
const workspaceChromeDragSelector = computed(() => {
|
|
124
|
-
if (desktopWorkspaceStore.overview) {
|
|
125
|
-
return '.owd-window-overview-drag-none'
|
|
126
|
-
}
|
|
127
|
-
return windowController?.isDraggable
|
|
128
|
-
? '.owd-window-nav__draggable'
|
|
129
|
-
: '.owd-window-nav__draggable-none'
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
function onOverviewNativeDragStart(e: DragEvent) {
|
|
133
|
-
if (!desktopWorkspaceStore.overview || !windowController) return
|
|
134
|
-
e.stopPropagation()
|
|
135
|
-
e.dataTransfer?.setData('text/plain', windowController.state.id)
|
|
136
|
-
e.dataTransfer!.effectAllowed = 'move'
|
|
137
|
-
try {
|
|
138
|
-
const img = new Image()
|
|
139
|
-
img.src =
|
|
140
|
-
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
|
141
|
-
e.dataTransfer?.setDragImage(img, 0, 0)
|
|
142
|
-
} catch {
|
|
143
|
-
/* noop */
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** `fit-parent` clamps drag/resize to the parent box — wrong for viewport-fixed shells (Win11, GNOME). */
|
|
148
|
-
const shouldFitParent = computed(
|
|
149
|
-
() => appConfig.desktop.windows.position !== 'fixed',
|
|
150
|
-
)
|
|
151
|
-
</script>
|
|
152
|
-
|
|
153
|
-
<template>
|
|
154
|
-
<vue-resizable
|
|
155
|
-
ref="windowResizableController"
|
|
156
|
-
:class="classes"
|
|
157
|
-
:width="windowController?.size.width"
|
|
158
|
-
:height="windowController?.size.height"
|
|
159
|
-
:min-width="windowController?.size.minWidth"
|
|
160
|
-
:min-height="windowController?.size.minHeight"
|
|
161
|
-
:max-width="windowController?.size.maxWidth"
|
|
162
|
-
:max-height="windowController?.size.maxHeight"
|
|
163
|
-
:left="windowController?.position?.x"
|
|
164
|
-
:top="windowController?.position?.y"
|
|
165
|
-
:active="windowController?.isResizable ? undefined : []"
|
|
166
|
-
:fit-parent="shouldFitParent"
|
|
167
|
-
@drag:start="onWindowDragStart"
|
|
168
|
-
@drag:move="onWindowDragMove"
|
|
169
|
-
@drag:end="onWindowDragEnd"
|
|
170
|
-
@resize:start="onWindowResizeStart"
|
|
171
|
-
@resize:move="onWindowResizeMove"
|
|
172
|
-
@resize:end="onWindowResizeEnd"
|
|
173
|
-
:style="{ zIndex: windowController?.position?.z }"
|
|
174
|
-
:drag-selector="workspaceChromeDragSelector"
|
|
175
|
-
:draggable="desktopWorkspaceStore.overview"
|
|
176
|
-
@pointerdown="onWindowPointerDown"
|
|
177
|
-
@dragstart="onOverviewNativeDragStart"
|
|
178
|
-
>
|
|
179
|
-
<slot />
|
|
180
|
-
</vue-resizable>
|
|
181
|
-
</template>
|
|
182
|
-
|
|
183
|
-
<style scoped lang="scss">
|
|
184
|
-
/* vue-resizable sets `.resizable-component { position: relative }` — override so desktop geometry stays consistent */
|
|
185
|
-
.owd-window.resizable-component {
|
|
186
|
-
position: v-bind('appConfig.desktop.windows.position') !important;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.owd-window {
|
|
190
|
-
position: v-bind('appConfig.desktop.windows.position');
|
|
191
|
-
|
|
192
|
-
&--dragging,
|
|
193
|
-
&--resizing {
|
|
194
|
-
:deep(.owd-window__content) {
|
|
195
|
-
pointer-events: none;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
:deep(.owd-window__content) {
|
|
200
|
-
overflow-y: auto;
|
|
201
|
-
height: 100%;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
</style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { inject } from 'vue'
|
|
3
|
-
import { computed } from '@vue/reactivity'
|
|
4
|
-
|
|
5
|
-
const windowContent = inject<WindowContent>('windowContent')
|
|
6
|
-
|
|
7
|
-
const classes = computed(() => {
|
|
8
|
-
const list = ['owd-window__content']
|
|
9
|
-
|
|
10
|
-
if (windowContent?.centered) {
|
|
11
|
-
list.push('owd-window__content--centered')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (windowContent?.padded) {
|
|
15
|
-
list.push('owd-window__content--padded')
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return list
|
|
19
|
-
})
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<template>
|
|
23
|
-
<div :class="classes">
|
|
24
|
-
<slot />
|
|
25
|
-
</div>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<style scoped lang="scss"></style>
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { inject } from 'vue'
|
|
3
|
-
import { computed } from '@vue/reactivity'
|
|
4
|
-
|
|
5
|
-
const windowController = inject<IWindowController>('windowController')
|
|
6
|
-
|
|
7
|
-
const classes = computed(() => {
|
|
8
|
-
const list = ['owd-window-nav']
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
typeof windowController?.state.active === 'undefined' ||
|
|
12
|
-
!!windowController?.state.active
|
|
13
|
-
) {
|
|
14
|
-
list.push('owd-window-nav--active')
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (windowController?.state.focused) {
|
|
18
|
-
list.push('owd-window-nav--focused')
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return list
|
|
22
|
-
})
|
|
23
|
-
</script>
|
|
24
|
-
|
|
25
|
-
<template>
|
|
26
|
-
<div :class="classes">
|
|
27
|
-
<div class="owd-window-nav__draggable" />
|
|
28
|
-
|
|
29
|
-
<slot />
|
|
30
|
-
</div>
|
|
31
|
-
</template>
|
|
32
|
-
|
|
33
|
-
<style lang="scss">
|
|
34
|
-
/**
|
|
35
|
-
* Title/icon sit above the drag layer in DOM order; use pointer-events so
|
|
36
|
-
* mousedown reaches `.owd-window-nav__draggable` for vue-resizable. Window
|
|
37
|
-
* controls stay clickable.
|
|
38
|
-
*/
|
|
39
|
-
.owd-window-nav {
|
|
40
|
-
position: relative;
|
|
41
|
-
display: flex;
|
|
42
|
-
align-items: stretch;
|
|
43
|
-
width: 100%;
|
|
44
|
-
min-height: 0;
|
|
45
|
-
|
|
46
|
-
&__draggable {
|
|
47
|
-
position: absolute;
|
|
48
|
-
inset: 0;
|
|
49
|
-
z-index: 1;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
> :not(.owd-window-nav__draggable) {
|
|
53
|
-
position: relative;
|
|
54
|
-
z-index: 2;
|
|
55
|
-
pointer-events: none;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
> .owd-window-nav__btn-group {
|
|
59
|
-
pointer-events: auto;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
> .owd-window-nav__interactive {
|
|
63
|
-
pointer-events: auto;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
</style>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { useApplicationManager } from './useApplicationManager'
|
|
2
|
-
import { computed } from '@vue/reactivity'
|
|
3
|
-
|
|
4
|
-
type SortBy =
|
|
5
|
-
| 'title'
|
|
6
|
-
| 'category'
|
|
7
|
-
| ((
|
|
8
|
-
a: ApplicationEntryWithInherited,
|
|
9
|
-
b: ApplicationEntryWithInherited,
|
|
10
|
-
) => number)
|
|
11
|
-
type Visibility =
|
|
12
|
-
| 'primary'
|
|
13
|
-
| 'all'
|
|
14
|
-
| ((entry: ApplicationEntryWithInherited) => boolean)
|
|
15
|
-
|
|
16
|
-
export function useApplicationEntries() {
|
|
17
|
-
const applicationManager = useApplicationManager()
|
|
18
|
-
|
|
19
|
-
const sortedAppEntries = function (
|
|
20
|
-
sortBy: SortBy = 'title',
|
|
21
|
-
visibility: Visibility = 'primary',
|
|
22
|
-
): Ref<ApplicationEntryWithInherited[]> {
|
|
23
|
-
return computed(() => {
|
|
24
|
-
const currentEntries = [...applicationManager.appsEntries.value]
|
|
25
|
-
|
|
26
|
-
// filtering
|
|
27
|
-
const filtered =
|
|
28
|
-
typeof visibility === 'function'
|
|
29
|
-
? currentEntries.filter(visibility)
|
|
30
|
-
: visibility === 'primary'
|
|
31
|
-
? currentEntries.filter((e) => e.visibility !== 'secondary')
|
|
32
|
-
: currentEntries
|
|
33
|
-
|
|
34
|
-
// sorting
|
|
35
|
-
const sorted =
|
|
36
|
-
typeof sortBy === 'function'
|
|
37
|
-
? filtered.sort(sortBy)
|
|
38
|
-
: sortBy === 'title'
|
|
39
|
-
? filtered.sort((a, b) =>
|
|
40
|
-
(a.title || '').localeCompare(b.title || ''),
|
|
41
|
-
)
|
|
42
|
-
: filtered.sort((a, b) =>
|
|
43
|
-
(a.category || '').localeCompare(b.category || ''),
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
return sorted
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return { sortedAppEntries }
|
|
51
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import { reactive, markRaw, computed } from 'vue'
|
|
2
|
-
import { ApplicationController } from '../internal/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"
|
|
7
|
-
|
|
8
|
-
const apps = reactive(new Map<string, IApplicationController>())
|
|
9
|
-
|
|
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, markRaw(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 = new Map<string, IWindowController>()
|
|
188
|
-
|
|
189
|
-
for (const applicationController of apps.values()) {
|
|
190
|
-
if (
|
|
191
|
-
!applicationController.isRunning &&
|
|
192
|
-
applicationController.openWindowCount.value === 0
|
|
193
|
-
) {
|
|
194
|
-
continue
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
for (const [windowId, window] of applicationController.windows) {
|
|
198
|
-
windows.set(windowId, window)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return windows
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Array of running applications
|
|
207
|
-
*/
|
|
208
|
-
const appsRunning = computed(() => {
|
|
209
|
-
const runningApps: IApplicationController[] = []
|
|
210
|
-
|
|
211
|
-
for (const applicationController of apps.values()) {
|
|
212
|
-
const openCount = applicationController.openWindowCount.value
|
|
213
|
-
if (applicationController.isRunning || openCount > 0) {
|
|
214
|
-
runningApps.push(applicationController)
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return runningApps
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
function getWindowOpenedId(windowId: string) {
|
|
222
|
-
for (const window of windowsOpened.value.values()) {
|
|
223
|
-
if (window.state.id === windowId) {
|
|
224
|
-
return window
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Gets all unique categories from the installed apps
|
|
231
|
-
*/
|
|
232
|
-
const appCategories = computed(() => {
|
|
233
|
-
const categories = new Set<string>()
|
|
234
|
-
|
|
235
|
-
for (const applicationController of apps.values()) {
|
|
236
|
-
if (applicationController.config.category) {
|
|
237
|
-
categories.add(applicationController.config.category)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return Array.from(categories).sort()
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Gets the apps ordered by category
|
|
246
|
-
*/
|
|
247
|
-
const appsByCategory = computed(() => {
|
|
248
|
-
const categorizedApps: {
|
|
249
|
-
[category: string]: IApplicationController[]
|
|
250
|
-
} = {}
|
|
251
|
-
|
|
252
|
-
for (const applicationController of apps.values()) {
|
|
253
|
-
const category = applicationController.config.category || 'other'
|
|
254
|
-
if (!categorizedApps[category]) {
|
|
255
|
-
categorizedApps[category] = []
|
|
256
|
-
}
|
|
257
|
-
categorizedApps[category].push(applicationController)
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
for (const category in categorizedApps) {
|
|
261
|
-
categorizedApps[category].sort((a, b) =>
|
|
262
|
-
a.config.title.localeCompare(b.config.title),
|
|
263
|
-
)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return categorizedApps
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
return {
|
|
270
|
-
defineApp,
|
|
271
|
-
isAppDefined,
|
|
272
|
-
getAppById,
|
|
273
|
-
isAppRunning,
|
|
274
|
-
launchAppEntry,
|
|
275
|
-
execAppCommand,
|
|
276
|
-
closeApp,
|
|
277
|
-
getWindowOpenedId,
|
|
278
|
-
apps,
|
|
279
|
-
appsEntries,
|
|
280
|
-
appsRunning,
|
|
281
|
-
windowsOpened,
|
|
282
|
-
appCategories,
|
|
283
|
-
appsByCategory,
|
|
284
|
-
}
|
|
285
|
-
}
|