@kispace-io/core 0.7.0

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 (272) hide show
  1. package/dist/api/base-classes.d.ts +7 -0
  2. package/dist/api/base-classes.d.ts.map +1 -0
  3. package/dist/api/constants.d.ts +2 -0
  4. package/dist/api/constants.d.ts.map +1 -0
  5. package/dist/api/index.d.ts +6 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/index.js +80 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/services.d.ts +27 -0
  10. package/dist/api/services.d.ts.map +1 -0
  11. package/dist/api/types.d.ts +11 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/commands/files.d.ts +2 -0
  14. package/dist/commands/files.d.ts.map +1 -0
  15. package/dist/commands/global.d.ts +1 -0
  16. package/dist/commands/global.d.ts.map +1 -0
  17. package/dist/commands/index.d.ts +1 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/version-info.d.ts +2 -0
  20. package/dist/commands/version-info.d.ts.map +1 -0
  21. package/dist/components/index.d.ts +1 -0
  22. package/dist/components/index.d.ts.map +1 -0
  23. package/dist/components/k-app-selector.d.ts +17 -0
  24. package/dist/components/k-app-selector.d.ts.map +1 -0
  25. package/dist/components/k-app-switcher.d.ts +13 -0
  26. package/dist/components/k-app-switcher.d.ts.map +1 -0
  27. package/dist/components/k-command.d.ts +31 -0
  28. package/dist/components/k-command.d.ts.map +1 -0
  29. package/dist/components/k-extensions.d.ts +32 -0
  30. package/dist/components/k-extensions.d.ts.map +1 -0
  31. package/dist/components/k-fastviews.d.ts +34 -0
  32. package/dist/components/k-fastviews.d.ts.map +1 -0
  33. package/dist/components/k-filebrowser.d.ts +40 -0
  34. package/dist/components/k-filebrowser.d.ts.map +1 -0
  35. package/dist/components/k-language-selector.d.ts +12 -0
  36. package/dist/components/k-language-selector.d.ts.map +1 -0
  37. package/dist/components/k-log-terminal.d.ts +36 -0
  38. package/dist/components/k-log-terminal.d.ts.map +1 -0
  39. package/dist/components/k-part-name.d.ts +12 -0
  40. package/dist/components/k-part-name.d.ts.map +1 -0
  41. package/dist/components/k-tasks.d.ts +13 -0
  42. package/dist/components/k-tasks.d.ts.map +1 -0
  43. package/dist/components/k-workspace-name.d.ts +14 -0
  44. package/dist/components/k-workspace-name.d.ts.map +1 -0
  45. package/dist/contributions/default-ui-contributions.d.ts +2 -0
  46. package/dist/contributions/default-ui-contributions.d.ts.map +1 -0
  47. package/dist/contributions/index.d.ts +1 -0
  48. package/dist/contributions/index.d.ts.map +1 -0
  49. package/dist/contributions/marketplace-catalog-contributions.d.ts +2 -0
  50. package/dist/contributions/marketplace-catalog-contributions.d.ts.map +1 -0
  51. package/dist/core/app-host-config.d.ts +7 -0
  52. package/dist/core/app-host-config.d.ts.map +1 -0
  53. package/dist/core/apploader.d.ts +214 -0
  54. package/dist/core/apploader.d.ts.map +1 -0
  55. package/dist/core/appstate.d.ts +12 -0
  56. package/dist/core/appstate.d.ts.map +1 -0
  57. package/dist/core/commandregistry.d.ts +79 -0
  58. package/dist/core/commandregistry.d.ts.map +1 -0
  59. package/dist/core/config.d.ts +15 -0
  60. package/dist/core/config.d.ts.map +1 -0
  61. package/dist/core/constants.d.ts +21 -0
  62. package/dist/core/constants.d.ts.map +1 -0
  63. package/dist/core/contributionregistry.d.ts +49 -0
  64. package/dist/core/contributionregistry.d.ts.map +1 -0
  65. package/dist/core/di.d.ts +18 -0
  66. package/dist/core/di.d.ts.map +1 -0
  67. package/dist/core/dialogservice.d.ts +33 -0
  68. package/dist/core/dialogservice.d.ts.map +1 -0
  69. package/dist/core/editorregistry.d.ts +73 -0
  70. package/dist/core/editorregistry.d.ts.map +1 -0
  71. package/dist/core/esmsh-service.d.ts +40 -0
  72. package/dist/core/esmsh-service.d.ts.map +1 -0
  73. package/dist/core/events.d.ts +7 -0
  74. package/dist/core/events.d.ts.map +1 -0
  75. package/dist/core/events.js +63 -0
  76. package/dist/core/events.js.map +1 -0
  77. package/dist/core/extensionregistry.d.ts +98 -0
  78. package/dist/core/extensionregistry.d.ts.map +1 -0
  79. package/dist/core/filesys.d.ts +139 -0
  80. package/dist/core/filesys.d.ts.map +1 -0
  81. package/dist/core/i18n.d.ts +50 -0
  82. package/dist/core/i18n.d.ts.map +1 -0
  83. package/dist/core/index.d.ts +1 -0
  84. package/dist/core/index.d.ts.map +1 -0
  85. package/dist/core/k-utils.d.ts +2 -0
  86. package/dist/core/k-utils.d.ts.map +1 -0
  87. package/dist/core/keybindings.d.ts +67 -0
  88. package/dist/core/keybindings.d.ts.map +1 -0
  89. package/dist/core/logger.d.ts +44 -0
  90. package/dist/core/logger.d.ts.map +1 -0
  91. package/dist/core/marketplaceregistry.d.ts +25 -0
  92. package/dist/core/marketplaceregistry.d.ts.map +1 -0
  93. package/dist/core/packageinfoservice.d.ts +16 -0
  94. package/dist/core/packageinfoservice.d.ts.map +1 -0
  95. package/dist/core/persistenceservice.d.ts +6 -0
  96. package/dist/core/persistenceservice.d.ts.map +1 -0
  97. package/dist/core/settingsservice.d.ts +19 -0
  98. package/dist/core/settingsservice.d.ts.map +1 -0
  99. package/dist/core/signals.d.ts +3 -0
  100. package/dist/core/signals.d.ts.map +1 -0
  101. package/dist/core/taskservice.d.ts +20 -0
  102. package/dist/core/taskservice.d.ts.map +1 -0
  103. package/dist/core/toast.d.ts +4 -0
  104. package/dist/core/toast.d.ts.map +1 -0
  105. package/dist/core/tree-utils.d.ts +16 -0
  106. package/dist/core/tree-utils.d.ts.map +1 -0
  107. package/dist/dialogs/confirm-dialog.d.ts +14 -0
  108. package/dist/dialogs/confirm-dialog.d.ts.map +1 -0
  109. package/dist/dialogs/index.d.ts +5 -0
  110. package/dist/dialogs/index.d.ts.map +1 -0
  111. package/dist/dialogs/info-dialog.d.ts +13 -0
  112. package/dist/dialogs/info-dialog.d.ts.map +1 -0
  113. package/dist/dialogs/navigable-info-dialog.d.ts +33 -0
  114. package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -0
  115. package/dist/dialogs/prompt-dialog.d.ts +21 -0
  116. package/dist/dialogs/prompt-dialog.d.ts.map +1 -0
  117. package/dist/externals/lit.d.ts +20 -0
  118. package/dist/externals/lit.d.ts.map +1 -0
  119. package/dist/externals/lit.js +15 -0
  120. package/dist/externals/lit.js.map +1 -0
  121. package/dist/externals/third-party.d.ts +7 -0
  122. package/dist/externals/third-party.d.ts.map +1 -0
  123. package/dist/externals/third-party.js +2 -0
  124. package/dist/externals/third-party.js.map +1 -0
  125. package/dist/externals/webawesome.d.ts +1 -0
  126. package/dist/externals/webawesome.d.ts.map +1 -0
  127. package/dist/externals/webawesome.js +52 -0
  128. package/dist/externals/webawesome.js.map +1 -0
  129. package/dist/i18n/extensions.json.d.ts +42 -0
  130. package/dist/i18n/fastviews.json.d.ts +13 -0
  131. package/dist/i18n/filebrowser.json.d.ts +35 -0
  132. package/dist/i18n/index.d.ts +2 -0
  133. package/dist/i18n/index.d.ts.map +1 -0
  134. package/dist/i18n/logterminal.json.d.ts +45 -0
  135. package/dist/i18n/partname.json.d.ts +15 -0
  136. package/dist/i18n/tasks.json.d.ts +15 -0
  137. package/dist/i18n/workspace.json.d.ts +15 -0
  138. package/dist/index.d.ts +2 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +80 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/k-icon-BZC7dQV0.js +492 -0
  143. package/dist/k-icon-BZC7dQV0.js.map +1 -0
  144. package/dist/k-nocontent-Bh_yToGh.js +48 -0
  145. package/dist/k-nocontent-Bh_yToGh.js.map +1 -0
  146. package/dist/k-resizable-grid-Ch3iWZaL.js +3157 -0
  147. package/dist/k-resizable-grid-Ch3iWZaL.js.map +1 -0
  148. package/dist/k-standard-layout-CQ1VZoxa.js +5011 -0
  149. package/dist/k-standard-layout-CQ1VZoxa.js.map +1 -0
  150. package/dist/layouts/k-standard-layout.d.ts +16 -0
  151. package/dist/layouts/k-standard-layout.d.ts.map +1 -0
  152. package/dist/parts/index.d.ts +1 -0
  153. package/dist/parts/index.d.ts.map +1 -0
  154. package/dist/parts/index.js +53 -0
  155. package/dist/parts/index.js.map +1 -0
  156. package/dist/parts/k-app.d.ts +11 -0
  157. package/dist/parts/k-app.d.ts.map +1 -0
  158. package/dist/parts/k-container.d.ts +4 -0
  159. package/dist/parts/k-container.d.ts.map +1 -0
  160. package/dist/parts/k-contextmenu.d.ts +38 -0
  161. package/dist/parts/k-contextmenu.d.ts.map +1 -0
  162. package/dist/parts/k-dialog-content.d.ts +9 -0
  163. package/dist/parts/k-dialog-content.d.ts.map +1 -0
  164. package/dist/parts/k-element.d.ts +36 -0
  165. package/dist/parts/k-element.d.ts.map +1 -0
  166. package/dist/parts/k-part.d.ts +96 -0
  167. package/dist/parts/k-part.d.ts.map +1 -0
  168. package/dist/parts/k-resizable-grid.d.ts +31 -0
  169. package/dist/parts/k-resizable-grid.d.ts.map +1 -0
  170. package/dist/parts/k-tabs.d.ts +74 -0
  171. package/dist/parts/k-tabs.d.ts.map +1 -0
  172. package/dist/parts/k-toolbar.d.ts +21 -0
  173. package/dist/parts/k-toolbar.d.ts.map +1 -0
  174. package/dist/widgets/index.d.ts +1 -0
  175. package/dist/widgets/index.d.ts.map +1 -0
  176. package/dist/widgets/index.js +3 -0
  177. package/dist/widgets/index.js.map +1 -0
  178. package/dist/widgets/k-icon.d.ts +10 -0
  179. package/dist/widgets/k-icon.d.ts.map +1 -0
  180. package/dist/widgets/k-nocontent.d.ts +13 -0
  181. package/dist/widgets/k-nocontent.d.ts.map +1 -0
  182. package/dist/widgets/k-widget.d.ts +25 -0
  183. package/dist/widgets/k-widget.d.ts.map +1 -0
  184. package/package.json +81 -0
  185. package/src/api/base-classes.ts +10 -0
  186. package/src/api/constants.ts +3 -0
  187. package/src/api/index.ts +31 -0
  188. package/src/api/services.ts +52 -0
  189. package/src/api/types.ts +46 -0
  190. package/src/commands/files.ts +829 -0
  191. package/src/commands/global.ts +225 -0
  192. package/src/commands/index.ts +4 -0
  193. package/src/commands/version-info.ts +214 -0
  194. package/src/components/index.ts +10 -0
  195. package/src/components/k-app-selector.ts +233 -0
  196. package/src/components/k-app-switcher.ts +126 -0
  197. package/src/components/k-command.ts +236 -0
  198. package/src/components/k-extensions.ts +615 -0
  199. package/src/components/k-fastviews.ts +314 -0
  200. package/src/components/k-filebrowser.ts +442 -0
  201. package/src/components/k-language-selector.ts +166 -0
  202. package/src/components/k-log-terminal.ts +337 -0
  203. package/src/components/k-part-name.ts +54 -0
  204. package/src/components/k-tasks.ts +267 -0
  205. package/src/components/k-workspace-name.ts +56 -0
  206. package/src/contributions/default-ui-contributions.ts +51 -0
  207. package/src/contributions/index.ts +3 -0
  208. package/src/contributions/marketplace-catalog-contributions.ts +6 -0
  209. package/src/core/app-host-config.ts +23 -0
  210. package/src/core/apploader.ts +630 -0
  211. package/src/core/appstate.ts +15 -0
  212. package/src/core/commandregistry.ts +210 -0
  213. package/src/core/config.ts +29 -0
  214. package/src/core/constants.ts +27 -0
  215. package/src/core/contributionregistry.ts +77 -0
  216. package/src/core/di.ts +54 -0
  217. package/src/core/dialogservice.ts +266 -0
  218. package/src/core/editorregistry.ts +303 -0
  219. package/src/core/esmsh-service.ts +404 -0
  220. package/src/core/events.ts +68 -0
  221. package/src/core/extensionregistry.ts +399 -0
  222. package/src/core/filesys.ts +618 -0
  223. package/src/core/i18n.ts +221 -0
  224. package/src/core/index.ts +51 -0
  225. package/src/core/k-utils.ts +11 -0
  226. package/src/core/keybindings.ts +274 -0
  227. package/src/core/logger.ts +187 -0
  228. package/src/core/marketplaceregistry.ts +197 -0
  229. package/src/core/packageinfoservice.ts +56 -0
  230. package/src/core/persistenceservice.ts +15 -0
  231. package/src/core/settingsservice.ts +70 -0
  232. package/src/core/signals.ts +18 -0
  233. package/src/core/taskservice.ts +72 -0
  234. package/src/core/toast.ts +11 -0
  235. package/src/core/tree-utils.ts +24 -0
  236. package/src/dialogs/confirm-dialog.ts +72 -0
  237. package/src/dialogs/index.ts +4 -0
  238. package/src/dialogs/info-dialog.ts +67 -0
  239. package/src/dialogs/navigable-info-dialog.ts +256 -0
  240. package/src/dialogs/prompt-dialog.ts +123 -0
  241. package/src/externals/lit.ts +26 -0
  242. package/src/externals/third-party.ts +9 -0
  243. package/src/externals/webawesome.ts +54 -0
  244. package/src/i18n/extensions.json +39 -0
  245. package/src/i18n/fastviews.json +10 -0
  246. package/src/i18n/filebrowser.json +33 -0
  247. package/src/i18n/index.ts +25 -0
  248. package/src/i18n/logterminal.json +42 -0
  249. package/src/i18n/partname.json +12 -0
  250. package/src/i18n/tasks.json +12 -0
  251. package/src/i18n/workspace.json +12 -0
  252. package/src/icons/icons.txt +3 -0
  253. package/src/icons/js.svg +6 -0
  254. package/src/icons/jupyter.svg +18 -0
  255. package/src/icons/python.svg +15 -0
  256. package/src/index.ts +3 -0
  257. package/src/layouts/k-standard-layout.ts +174 -0
  258. package/src/parts/index.ts +6 -0
  259. package/src/parts/k-app.ts +29 -0
  260. package/src/parts/k-container.ts +4 -0
  261. package/src/parts/k-contextmenu.ts +245 -0
  262. package/src/parts/k-dialog-content.ts +31 -0
  263. package/src/parts/k-element.ts +100 -0
  264. package/src/parts/k-part.ts +158 -0
  265. package/src/parts/k-resizable-grid.ts +366 -0
  266. package/src/parts/k-tabs.ts +574 -0
  267. package/src/parts/k-toolbar.ts +158 -0
  268. package/src/vite-env.d.ts +2 -0
  269. package/src/widgets/index.ts +2 -0
  270. package/src/widgets/k-icon.ts +39 -0
  271. package/src/widgets/k-nocontent.ts +40 -0
  272. package/src/widgets/k-widget.ts +90 -0
@@ -0,0 +1,337 @@
1
+ import { css, html } from 'lit';
2
+ import { customElement, state } from 'lit/decorators.js';
3
+ import { KPart } from '../parts/k-part';
4
+ import { createRef, ref, Ref } from 'lit/directives/ref.js';
5
+ import { registerLogHandler, unregisterLogHandler, type LogLevel } from '../core/logger';
6
+ import { i18n } from '../core/i18n';
7
+
8
+ const t = i18n('logterminal');
9
+
10
+ export interface LogMessage {
11
+ timestamp: Date;
12
+ level: LogLevel;
13
+ source: string;
14
+ message: string;
15
+ }
16
+
17
+ @customElement('k-log-terminal')
18
+ export class KLogTerminal extends KPart {
19
+ @state()
20
+ private messages: LogMessage[] = [];
21
+
22
+ @state()
23
+ private autoScroll: boolean = true;
24
+
25
+ @state()
26
+ private filter: LogLevel | 'all' = 'all';
27
+
28
+ private containerRef: Ref<HTMLDivElement> = createRef();
29
+
30
+ connectedCallback() {
31
+ super.connectedCallback();
32
+ // Load persisted settings
33
+ this.loadSettings();
34
+ // Register this terminal as the log handler
35
+ registerLogHandler(this.log.bind(this));
36
+ }
37
+
38
+ disconnectedCallback() {
39
+ super.disconnectedCallback();
40
+ // Unregister log handler
41
+ unregisterLogHandler();
42
+ }
43
+
44
+ public log(source: string, message: string, level: LogLevel = 'info') {
45
+ const logMessage: LogMessage = {
46
+ timestamp: new Date(),
47
+ level,
48
+ source,
49
+ message
50
+ };
51
+
52
+ this.messages = [...this.messages, logMessage];
53
+ this.updateToolbar();
54
+
55
+ if (this.autoScroll) {
56
+ this.updateComplete.then(() => {
57
+ const container = this.containerRef.value;
58
+ if (container) {
59
+ container.scrollTop = container.scrollHeight;
60
+ }
61
+ });
62
+ }
63
+ }
64
+
65
+ public clear() {
66
+ this.messages = [];
67
+ this.updateToolbar();
68
+ }
69
+
70
+ private getFilteredMessages() {
71
+ if (this.filter === 'all') {
72
+ return this.messages;
73
+ }
74
+ return this.messages.filter(m => m.level === this.filter);
75
+ }
76
+
77
+ private formatTimestamp(date: Date): string {
78
+ return date.toLocaleTimeString('en-US', {
79
+ hour12: false,
80
+ hour: '2-digit',
81
+ minute: '2-digit',
82
+ second: '2-digit'
83
+ });
84
+ }
85
+
86
+ private getLevelIcon(level: LogLevel): string {
87
+ switch (level) {
88
+ case 'info': return 'circle-info';
89
+ case 'warning': return 'triangle-exclamation';
90
+ case 'error': return 'circle-xmark';
91
+ case 'debug': return 'bug';
92
+ }
93
+ }
94
+
95
+ private getLevelColor(level: LogLevel): string {
96
+ switch (level) {
97
+ case 'info': return 'var(--wa-color-primary-text, #0066cc)';
98
+ case 'warning': return 'var(--wa-color-warning-text, #ff9800)';
99
+ case 'error': return 'var(--wa-color-danger-text, #dc3545)';
100
+ case 'debug': return 'var(--wa-color-neutral-text-subtle, #6c757d)';
101
+ }
102
+ }
103
+
104
+ protected renderToolbar() {
105
+ const infoCount = this.messages.filter(m => m.level === 'info').length;
106
+ const warningCount = this.messages.filter(m => m.level === 'warning').length;
107
+ const errorCount = this.messages.filter(m => m.level === 'error').length;
108
+ const debugCount = this.messages.filter(m => m.level === 'debug').length;
109
+
110
+ return html`
111
+ <k-command
112
+ icon="list"
113
+ title="${t('ALL_LOGS')}"
114
+ appearance="${this.filter === 'all' ? 'filled' : 'plain'}"
115
+ variant="${this.filter === 'all' ? 'brand' : 'neutral'}"
116
+ .action=${() => {
117
+ this.filter = 'all';
118
+ this.saveSettings();
119
+ this.updateToolbar();
120
+ }}>
121
+ ${t('ALL')} (${this.messages.length})
122
+ </k-command>
123
+
124
+ <k-command
125
+ icon="circle-info"
126
+ title="${t('INFO_LOGS')}"
127
+ appearance="${this.filter === 'info' ? 'filled' : 'plain'}"
128
+ variant="${this.filter === 'info' ? 'brand' : 'neutral'}"
129
+ .action=${() => {
130
+ this.filter = 'info';
131
+ this.saveSettings();
132
+ this.updateToolbar();
133
+ }}>
134
+ ${t('INFO')}${infoCount > 0 ? ` (${infoCount})` : ''}
135
+ </k-command>
136
+
137
+ <k-command
138
+ icon="triangle-exclamation"
139
+ title="${t('WARNING_LOGS')}"
140
+ appearance="${this.filter === 'warning' ? 'filled' : 'plain'}"
141
+ variant="${this.filter === 'warning' ? 'brand' : 'neutral'}"
142
+ .action=${() => {
143
+ this.filter = 'warning';
144
+ this.saveSettings();
145
+ this.updateToolbar();
146
+ }}>
147
+ ${t('WARNINGS')}${warningCount > 0 ? ` (${warningCount})` : ''}
148
+ </k-command>
149
+
150
+ <k-command
151
+ icon="circle-xmark"
152
+ title="${t('ERROR_LOGS')}"
153
+ appearance="${this.filter === 'error' ? 'filled' : 'plain'}"
154
+ variant="${this.filter === 'error' ? 'brand' : 'neutral'}"
155
+ .action=${() => {
156
+ this.filter = 'error';
157
+ this.saveSettings();
158
+ this.updateToolbar();
159
+ }}>
160
+ ${t('ERRORS')}${errorCount > 0 ? ` (${errorCount})` : ''}
161
+ </k-command>
162
+
163
+ <k-command
164
+ icon="bug"
165
+ title="${t('DEBUG_LOGS')}"
166
+ appearance="${this.filter === 'debug' ? 'filled' : 'plain'}"
167
+ variant="${this.filter === 'debug' ? 'brand' : 'neutral'}"
168
+ .action=${() => {
169
+ this.filter = 'debug';
170
+ this.saveSettings();
171
+ this.updateToolbar();
172
+ }}>
173
+ ${t('DEBUG')}${debugCount > 0 ? ` (${debugCount})` : ''}
174
+ </k-command>
175
+
176
+ <wa-divider orientation="vertical"></wa-divider>
177
+
178
+ <k-command
179
+ icon="arrow-down"
180
+ title="${this.autoScroll ? t('AUTO_SCROLL_ENABLED') : t('AUTO_SCROLL_DISABLED')}"
181
+ appearance="${this.autoScroll ? 'filled' : 'plain'}"
182
+ variant="${this.autoScroll ? 'brand' : 'neutral'}"
183
+ .action=${() => {
184
+ this.autoScroll = !this.autoScroll;
185
+ this.saveSettings();
186
+ this.updateToolbar();
187
+ }}>
188
+ ${this.autoScroll ? t('AUTO_SCROLL') : t('MANUAL')}
189
+ </k-command>
190
+
191
+ <k-command
192
+ icon="trash"
193
+ title="${t('CLEAR_LOGS')}"
194
+ .action=${() => this.clear()}>
195
+ ${t('CLEAR')}
196
+ </k-command>
197
+ `;
198
+ }
199
+
200
+ render() {
201
+ const filteredMessages = this.getFilteredMessages();
202
+
203
+ return html`
204
+ <div class="log-terminal">
205
+ <div class="messages" ${ref(this.containerRef)}>
206
+ ${filteredMessages.length === 0
207
+ ? html`<div class="empty-state">${t('NO_LOG_MESSAGES')}</div>`
208
+ : filteredMessages.map(msg => html`
209
+ <div class="message" data-level="${msg.level}">
210
+ <span class="timestamp">${this.formatTimestamp(msg.timestamp)}</span>
211
+ <wa-icon
212
+ name="${this.getLevelIcon(msg.level)}"
213
+ label="${msg.level}"
214
+ style="color: ${this.getLevelColor(msg.level)}">
215
+ </wa-icon>
216
+ <span class="source">[${msg.source}]</span>
217
+ <span class="text">${msg.message}</span>
218
+ </div>
219
+ `)
220
+ }
221
+ </div>
222
+ </div>
223
+ `;
224
+ }
225
+
226
+ static styles = css`
227
+ :host {
228
+ display: flex;
229
+ flex-direction: column;
230
+ height: 100%;
231
+ width: 100%;
232
+ }
233
+
234
+ .log-terminal {
235
+ display: flex;
236
+ flex-direction: column;
237
+ height: 100%;
238
+ width: 100%;
239
+ }
240
+
241
+ .messages {
242
+ flex: 1;
243
+ overflow-y: auto;
244
+ padding: 0.5rem;
245
+ font-family: var(--wa-font-mono);
246
+ font-size: 0.875rem;
247
+ line-height: 1.5;
248
+ }
249
+
250
+ .message {
251
+ display: flex;
252
+ gap: 0.5rem;
253
+ padding: 0.25rem 0.5rem;
254
+ align-items: baseline;
255
+ border-radius: var(--wa-border-radius-small);
256
+ }
257
+
258
+ .message:hover {
259
+ background: var(--wa-color-neutral-background-hover);
260
+ }
261
+
262
+ .timestamp {
263
+ color: var(--wa-color-neutral-text-subtle);
264
+ font-size: 0.75rem;
265
+ white-space: nowrap;
266
+ }
267
+
268
+ .source {
269
+ color: var(--wa-color-primary-text);
270
+ font-weight: 500;
271
+ white-space: nowrap;
272
+ }
273
+
274
+ .text {
275
+ color: var(--wa-color-neutral-text);
276
+ word-break: break-word;
277
+ }
278
+
279
+ .message[data-level="error"] .text {
280
+ color: var(--wa-color-danger-text);
281
+ }
282
+
283
+ .message[data-level="warning"] .text {
284
+ color: var(--wa-color-warning-text);
285
+ }
286
+
287
+ .message[data-level="debug"] .text {
288
+ color: var(--wa-color-neutral-text-subtle);
289
+ }
290
+
291
+ .empty-state {
292
+ display: flex;
293
+ align-items: center;
294
+ justify-content: center;
295
+ height: 100%;
296
+ color: var(--wa-color-neutral-text-subtle);
297
+ font-style: italic;
298
+ }
299
+
300
+ wa-icon {
301
+ flex-shrink: 0;
302
+ }
303
+ `;
304
+
305
+ private async loadSettings() {
306
+ const persisted = await this.getDialogSetting();
307
+
308
+ if (persisted) {
309
+ if (typeof persisted.filter === 'string' &&
310
+ (persisted.filter === 'all' || ['info', 'warning', 'error', 'debug'].includes(persisted.filter))) {
311
+ this.filter = persisted.filter;
312
+ }
313
+ if (typeof persisted.autoScroll === 'boolean') {
314
+ this.autoScroll = persisted.autoScroll;
315
+ }
316
+ this.updateToolbar();
317
+ }
318
+ }
319
+
320
+ private async saveSettings() {
321
+ await this.setDialogSetting({
322
+ filter: this.filter,
323
+ autoScroll: this.autoScroll
324
+ });
325
+ }
326
+ }
327
+
328
+ declare global {
329
+ interface HTMLElementTagNameMap {
330
+ 'k-log-terminal': KLogTerminal;
331
+ }
332
+
333
+ interface Window {
334
+ logToTerminal?: (source: string, message: string, level?: LogLevel) => void;
335
+ }
336
+ }
337
+
@@ -0,0 +1,54 @@
1
+ import {customElement} from "lit/decorators.js";
2
+ import {KElement} from "../parts/k-element";
3
+ import {html} from "lit";
4
+ import {activePartSignal} from "../core/appstate";
5
+ import {contributionRegistry, HTMLContribution} from "../core/contributionregistry";
6
+ import {TOOLBAR_BOTTOM_CENTER} from "../core/constants";
7
+ import '../widgets/k-icon';
8
+ import {i18n} from "../core/i18n";
9
+
10
+ const t = i18n('partname');
11
+
12
+ contributionRegistry.registerContribution(TOOLBAR_BOTTOM_CENTER, {
13
+ html: "<k-part-name></k-part-name>"
14
+ } as HTMLContribution)
15
+
16
+ @customElement('k-part-name')
17
+ export class KPartName extends KElement {
18
+ protected doBeforeUI() {
19
+ this.watch(activePartSignal, () => {
20
+ this.requestUpdate();
21
+ });
22
+ }
23
+
24
+ private getPartName(): string {
25
+ const activePart = activePartSignal.get();
26
+ if (!activePart) {
27
+ return t('NO_PART');
28
+ }
29
+
30
+ return activePart.tabContribution?.label || activePart.getAttribute('id') || t('NO_PART');
31
+ }
32
+
33
+ protected render() {
34
+ const activePart = activePartSignal.get();
35
+ const partIcon = activePart?.tabContribution?.icon || "box";
36
+
37
+ return html`
38
+ <wa-button
39
+ appearance="plain"
40
+ size="small"
41
+ title="${t('ACTIVE_PART')}">
42
+ <k-icon slot="start" name="${partIcon}" label="Part"></k-icon>
43
+ ${this.getPartName()}
44
+ </wa-button>
45
+ `;
46
+ }
47
+ }
48
+
49
+ declare global {
50
+ interface HTMLElementTagNameMap {
51
+ 'k-part-name': KPartName
52
+ }
53
+ }
54
+
@@ -0,0 +1,267 @@
1
+ import {contributionRegistry, HTMLContribution} from "../core/contributionregistry";
2
+ import {TOOLBAR_BOTTOM_CENTER} from "../core/constants";
3
+ import {customElement} from "lit/decorators.js";
4
+ import {KPart} from "../parts/k-part";
5
+ import {css, html, render} from "lit";
6
+ import {activeTasksSignal} from "../core/appstate";
7
+ import {taskService, ProgressMonitor} from "../core/taskservice";
8
+ import {i18n} from "../core/i18n";
9
+
10
+ const t = i18n('tasks');
11
+
12
+ contributionRegistry.registerContribution(TOOLBAR_BOTTOM_CENTER, {
13
+ html: "<k-tasks></k-tasks>"
14
+ } as HTMLContribution)
15
+
16
+ // Singleton dialog container for progress dialog
17
+ let progressDialogContainer: HTMLElement | null = null;
18
+
19
+ function getProgressDialogContainer(): HTMLElement {
20
+ if (!progressDialogContainer) {
21
+ progressDialogContainer = document.createElement('div');
22
+ progressDialogContainer.id = 'progress-dialog-container';
23
+ document.body.appendChild(progressDialogContainer);
24
+ }
25
+ return progressDialogContainer;
26
+ }
27
+
28
+ function getDialogElement(): any {
29
+ const container = getProgressDialogContainer();
30
+ return container.querySelector('wa-dialog') as any;
31
+ }
32
+
33
+ function showProgressDialog() {
34
+ updateProgressDialog(true);
35
+ }
36
+
37
+ function updateProgressDialog(forceOpen = false) {
38
+ const container = getProgressDialogContainer();
39
+ const tasks = taskService.getActiveTasks();
40
+ const currentTaskCount = tasks.length;
41
+
42
+ if (currentTaskCount === 0) {
43
+ render(html``, container);
44
+ return;
45
+ }
46
+
47
+ // Check if dialog exists and is open (before rendering, since render replaces DOM)
48
+ const existingDialog = getDialogElement();
49
+ const isOpen = forceOpen || (existingDialog?.open === true);
50
+
51
+ // Only update dialog if it's open or if we're forcing it open
52
+ // If it was closed (dismissed), don't show it again on progress updates
53
+ if (!isOpen) {
54
+ return;
55
+ }
56
+
57
+ const handleClose = () => {
58
+ // Close the dialog - this prevents it from showing again on progress updates
59
+ const dialog = getDialogElement();
60
+ if (dialog) {
61
+ dialog.open = false;
62
+ }
63
+ };
64
+
65
+ const handleAfterHide = () => {
66
+ // Clean up after the dialog closes and animations complete
67
+ render(html``, container);
68
+ };
69
+
70
+ const template = html`
71
+ <wa-dialog
72
+ label="${t('ACTIVE_TASKS')}"
73
+ open
74
+ light-dismiss
75
+ style="--width: 600px;"
76
+ @wa-request-close=${handleClose}
77
+ @wa-after-hide=${handleAfterHide}
78
+ >
79
+ <style>
80
+ .progress-dialog-content {
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: 1.5rem;
84
+ }
85
+
86
+ .task-item {
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 0.75rem;
90
+ padding: 1rem;
91
+ background: var(--wa-color-neutral-10);
92
+ border-radius: 8px;
93
+ border: 1px solid var(--wa-color-neutral-20);
94
+ }
95
+
96
+ :host-context(.wa-light) .task-item {
97
+ background: var(--wa-color-neutral-95);
98
+ border: 1px solid var(--wa-color-neutral-85);
99
+ }
100
+
101
+ .task-header {
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 0.75rem;
105
+ }
106
+
107
+ .task-name {
108
+ font-weight: 600;
109
+ font-size: 1rem;
110
+ color: var(--wa-color-neutral-90);
111
+ }
112
+
113
+ :host-context(.wa-light) .task-name {
114
+ color: var(--wa-color-neutral-10);
115
+ }
116
+
117
+ .task-message {
118
+ font-size: 0.875rem;
119
+ color: var(--wa-color-neutral-70);
120
+ margin-top: 0.25rem;
121
+ }
122
+
123
+ :host-context(.wa-light) .task-message {
124
+ color: var(--wa-color-neutral-30);
125
+ }
126
+
127
+ .task-progress {
128
+ margin-top: 0.5rem;
129
+ }
130
+
131
+ wa-progress-bar {
132
+ --track-height: 1.5rem;
133
+ }
134
+
135
+ wa-progress-bar::part(label) {
136
+ text-align: center;
137
+ width: 100%;
138
+ font-size: 0.875rem;
139
+ }
140
+
141
+ .no-tasks {
142
+ text-align: center;
143
+ padding: 2rem;
144
+ color: var(--wa-color-neutral-60);
145
+ }
146
+
147
+ :host-context(.wa-light) .no-tasks {
148
+ color: var(--wa-color-neutral-40);
149
+ }
150
+ </style>
151
+
152
+ <div class="progress-dialog-content">
153
+ ${tasks.map((taskProgress: ProgressMonitor) => {
154
+ const hasProgress = taskProgress.progress >= 0 || taskProgress.totalSteps > 0
155
+ const progress = taskProgress.progress >= 0
156
+ ? taskProgress.progress
157
+ : (taskProgress.totalSteps > 0
158
+ ? Math.round((taskProgress.currentStep / taskProgress.totalSteps) * 100)
159
+ : 0)
160
+
161
+ const showSteps = taskProgress.progress < 0 && taskProgress.totalSteps > 0
162
+
163
+ return html`
164
+ <div class="task-item">
165
+ <div class="task-header">
166
+ <wa-icon name="hourglass" style="color: var(--wa-color-warning-fill-loud);"></wa-icon>
167
+ <div style="flex: 1;">
168
+ <div class="task-name">${taskProgress.name}</div>
169
+ ${taskProgress.message ? html`
170
+ <div class="task-message">${taskProgress.message}</div>
171
+ ` : ''}
172
+ </div>
173
+ </div>
174
+ <div class="task-progress">
175
+ ${hasProgress ? html`
176
+ <wa-progress-bar value="${progress}">
177
+ ${showSteps ? `${taskProgress.currentStep}/${taskProgress.totalSteps} - ` : ''}${progress}%
178
+ </wa-progress-bar>
179
+ ` : html`
180
+ <wa-progress-bar indeterminate></wa-progress-bar>
181
+ `}
182
+ </div>
183
+ </div>
184
+ `
185
+ })}
186
+ </div>
187
+ </wa-dialog>
188
+ `;
189
+
190
+ render(template, container);
191
+ }
192
+
193
+ @customElement('k-tasks')
194
+ export class KTasks extends KPart {
195
+ static styles = css`
196
+ :host {
197
+ display: flex;
198
+ align-items: center;
199
+ }
200
+
201
+ .task-indicator {
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 0.5rem;
205
+ cursor: pointer;
206
+ padding: 0.25rem 0.5rem;
207
+ border-radius: 4px;
208
+ transition: background-color 0.2s;
209
+ }
210
+
211
+ .task-indicator:hover {
212
+ background: var(--wa-color-neutral-15);
213
+ }
214
+
215
+ :host-context(.wa-light) .task-indicator:hover {
216
+ background: var(--wa-color-neutral-85);
217
+ }
218
+
219
+ .task-count {
220
+ font-size: 0.875rem;
221
+ color: var(--wa-color-neutral-70);
222
+ }
223
+
224
+ :host-context(.wa-light) .task-count {
225
+ color: var(--wa-color-neutral-30);
226
+ }
227
+ `
228
+
229
+ protected doBeforeUI() {
230
+ this.watch(activeTasksSignal, () => {
231
+ // Update dialog content if it's open, and always update the indicator
232
+ updateProgressDialog();
233
+ this.requestUpdate();
234
+ });
235
+ }
236
+
237
+ private handleIndicatorClick() {
238
+ // Show the dialog when clicking the hourglass
239
+ showProgressDialog();
240
+ }
241
+
242
+ protected render() {
243
+ activeTasksSignal.get()
244
+ const tasks = taskService.getActiveTasks();
245
+ const taskCount = tasks.length;
246
+
247
+ if (taskCount === 0) {
248
+ return html``;
249
+ }
250
+
251
+ return html`
252
+ <div class="task-indicator" @click=${this.handleIndicatorClick} title="${t('ACTIVE_TASKS_TITLE', { taskCount: taskCount.toString() })}">
253
+ <wa-spinner
254
+ style="font-size: 1rem; --indicator-color: var(--wa-color-warning-fill-loud);"
255
+ label="${t('ACTIVE_TASKS')}"
256
+ ></wa-spinner>
257
+ <span class="task-count">${taskCount}</span>
258
+ </div>
259
+ `
260
+ }
261
+ }
262
+
263
+ declare global {
264
+ interface HTMLElementTagNameMap {
265
+ 'k-tasks': KTasks
266
+ }
267
+ }