@serve.zone/gitops 2.13.1

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 (258) hide show
  1. package/.smartconfig.json +114 -0
  2. package/binary/gitops.ts +4 -0
  3. package/changelog.md +185 -0
  4. package/cli.child.js +4 -0
  5. package/cli.js +4 -0
  6. package/cli.ts.js +5 -0
  7. package/deno.json +10 -0
  8. package/dist_serve/bundle.js +36362 -0
  9. package/dist_serve/index.html +33 -0
  10. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  11. package/dist_ts/00_commitinfo_data.js +9 -0
  12. package/dist_ts/cache/classes.cache.cleaner.d.ts +23 -0
  13. package/dist_ts/cache/classes.cache.cleaner.js +61 -0
  14. package/dist_ts/cache/classes.cached.document.d.ts +30 -0
  15. package/dist_ts/cache/classes.cached.document.js +101 -0
  16. package/dist_ts/cache/classes.cachedb.d.ts +22 -0
  17. package/dist_ts/cache/classes.cachedb.js +58 -0
  18. package/dist_ts/cache/classes.secrets.scan.service.d.ts +51 -0
  19. package/dist_ts/cache/classes.secrets.scan.service.js +237 -0
  20. package/dist_ts/cache/documents/classes.cached.project.d.ts +13 -0
  21. package/dist_ts/cache/documents/classes.cached.project.js +101 -0
  22. package/dist_ts/cache/documents/classes.cached.secret.d.ts +24 -0
  23. package/dist_ts/cache/documents/classes.cached.secret.js +158 -0
  24. package/dist_ts/cache/documents/index.d.ts +2 -0
  25. package/dist_ts/cache/documents/index.js +3 -0
  26. package/dist_ts/cache/index.d.ts +7 -0
  27. package/dist_ts/cache/index.js +6 -0
  28. package/dist_ts/classes/actionlog.d.ts +19 -0
  29. package/dist_ts/classes/actionlog.js +44 -0
  30. package/dist_ts/classes/connectionmanager.d.ts +57 -0
  31. package/dist_ts/classes/connectionmanager.js +247 -0
  32. package/dist_ts/classes/gitopsapp.d.ts +30 -0
  33. package/dist_ts/classes/gitopsapp.js +101 -0
  34. package/dist_ts/classes/jobmanager.d.ts +47 -0
  35. package/dist_ts/classes/jobmanager.js +301 -0
  36. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.d.ts +29 -0
  37. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.js +361 -0
  38. package/dist_ts/classes/jobrunners/base.jobrunner.d.ts +14 -0
  39. package/dist_ts/classes/jobrunners/base.jobrunner.js +3 -0
  40. package/dist_ts/classes/jobrunners/index.d.ts +5 -0
  41. package/dist_ts/classes/jobrunners/index.js +14 -0
  42. package/dist_ts/classes/managedsecrets.manager.d.ts +47 -0
  43. package/dist_ts/classes/managedsecrets.manager.js +247 -0
  44. package/dist_ts/classes/syncmanager.d.ts +189 -0
  45. package/dist_ts/classes/syncmanager.js +1787 -0
  46. package/dist_ts/index.d.ts +6 -0
  47. package/dist_ts/index.js +32 -0
  48. package/dist_ts/logging.d.ts +49 -0
  49. package/dist_ts/logging.js +134 -0
  50. package/dist_ts/opsserver/classes.opsserver.d.ts +25 -0
  51. package/dist_ts/opsserver/classes.opsserver.js +70 -0
  52. package/dist_ts/opsserver/handlers/actionlog.handler.d.ts +9 -0
  53. package/dist_ts/opsserver/handlers/actionlog.handler.js +24 -0
  54. package/dist_ts/opsserver/handlers/actions.handler.d.ts +9 -0
  55. package/dist_ts/opsserver/handlers/actions.handler.js +38 -0
  56. package/dist_ts/opsserver/handlers/admin.handler.d.ts +19 -0
  57. package/dist_ts/opsserver/handlers/admin.handler.js +96 -0
  58. package/dist_ts/opsserver/handlers/connections.handler.d.ts +10 -0
  59. package/dist_ts/opsserver/handlers/connections.handler.js +109 -0
  60. package/dist_ts/opsserver/handlers/groups.handler.d.ts +9 -0
  61. package/dist_ts/opsserver/handlers/groups.handler.js +24 -0
  62. package/dist_ts/opsserver/handlers/index.d.ts +13 -0
  63. package/dist_ts/opsserver/handlers/index.js +14 -0
  64. package/dist_ts/opsserver/handlers/jobs.handler.d.ts +16 -0
  65. package/dist_ts/opsserver/handlers/jobs.handler.js +146 -0
  66. package/dist_ts/opsserver/handlers/logs.handler.d.ts +9 -0
  67. package/dist_ts/opsserver/handlers/logs.handler.js +21 -0
  68. package/dist_ts/opsserver/handlers/managedsecrets.handler.d.ts +11 -0
  69. package/dist_ts/opsserver/handlers/managedsecrets.handler.js +110 -0
  70. package/dist_ts/opsserver/handlers/pipelines.handler.d.ts +31 -0
  71. package/dist_ts/opsserver/handlers/pipelines.handler.js +204 -0
  72. package/dist_ts/opsserver/handlers/projects.handler.d.ts +9 -0
  73. package/dist_ts/opsserver/handlers/projects.handler.js +24 -0
  74. package/dist_ts/opsserver/handlers/secrets.handler.d.ts +10 -0
  75. package/dist_ts/opsserver/handlers/secrets.handler.js +171 -0
  76. package/dist_ts/opsserver/handlers/sync.handler.d.ts +16 -0
  77. package/dist_ts/opsserver/handlers/sync.handler.js +166 -0
  78. package/dist_ts/opsserver/handlers/webhook.handler.d.ts +7 -0
  79. package/dist_ts/opsserver/handlers/webhook.handler.js +55 -0
  80. package/dist_ts/opsserver/helpers/guards.d.ts +5 -0
  81. package/dist_ts/opsserver/helpers/guards.js +12 -0
  82. package/dist_ts/opsserver/index.d.ts +1 -0
  83. package/dist_ts/opsserver/index.js +2 -0
  84. package/dist_ts/paths.d.ts +9 -0
  85. package/dist_ts/paths.js +13 -0
  86. package/dist_ts/plugins.d.ts +25 -0
  87. package/dist_ts/plugins.js +32 -0
  88. package/dist_ts/providers/classes.baseprovider.d.ts +51 -0
  89. package/dist_ts/providers/classes.baseprovider.js +17 -0
  90. package/dist_ts/providers/classes.giteaprovider.d.ts +40 -0
  91. package/dist_ts/providers/classes.giteaprovider.js +224 -0
  92. package/dist_ts/providers/classes.gitlabprovider.d.ts +39 -0
  93. package/dist_ts/providers/classes.gitlabprovider.js +207 -0
  94. package/dist_ts/providers/index.d.ts +3 -0
  95. package/dist_ts/providers/index.js +4 -0
  96. package/dist_ts/storage/classes.storagemanager.d.ts +33 -0
  97. package/dist_ts/storage/classes.storagemanager.js +135 -0
  98. package/dist_ts/storage/index.d.ts +2 -0
  99. package/dist_ts/storage/index.js +2 -0
  100. package/dist_ts/timers.d.ts +4 -0
  101. package/dist_ts/timers.js +24 -0
  102. package/dist_ts_bundled/bundle.d.ts +4 -0
  103. package/dist_ts_bundled/bundle.js +12 -0
  104. package/dist_ts_interfaces/data/actionlog.d.ts +12 -0
  105. package/dist_ts_interfaces/data/actionlog.js +2 -0
  106. package/dist_ts_interfaces/data/branch.d.ts +8 -0
  107. package/dist_ts_interfaces/data/branch.js +2 -0
  108. package/dist_ts_interfaces/data/connection.d.ts +12 -0
  109. package/dist_ts_interfaces/data/connection.js +2 -0
  110. package/dist_ts_interfaces/data/group.d.ts +10 -0
  111. package/dist_ts_interfaces/data/group.js +2 -0
  112. package/dist_ts_interfaces/data/identity.d.ts +7 -0
  113. package/dist_ts_interfaces/data/identity.js +2 -0
  114. package/dist_ts_interfaces/data/index.d.ts +11 -0
  115. package/dist_ts_interfaces/data/index.js +12 -0
  116. package/dist_ts_interfaces/data/job.d.ts +37 -0
  117. package/dist_ts_interfaces/data/job.js +2 -0
  118. package/dist_ts_interfaces/data/managedsecret.d.ts +37 -0
  119. package/dist_ts_interfaces/data/managedsecret.js +2 -0
  120. package/dist_ts_interfaces/data/pipeline.d.ts +22 -0
  121. package/dist_ts_interfaces/data/pipeline.js +2 -0
  122. package/dist_ts_interfaces/data/project.d.ts +12 -0
  123. package/dist_ts_interfaces/data/project.js +2 -0
  124. package/dist_ts_interfaces/data/secret.d.ts +11 -0
  125. package/dist_ts_interfaces/data/secret.js +2 -0
  126. package/dist_ts_interfaces/data/sync.d.ts +34 -0
  127. package/dist_ts_interfaces/data/sync.js +2 -0
  128. package/dist_ts_interfaces/index.d.ts +5 -0
  129. package/dist_ts_interfaces/index.js +8 -0
  130. package/dist_ts_interfaces/plugins.d.ts +2 -0
  131. package/dist_ts_interfaces/plugins.js +4 -0
  132. package/dist_ts_interfaces/requests/actionlog.d.ts +15 -0
  133. package/dist_ts_interfaces/requests/actionlog.js +3 -0
  134. package/dist_ts_interfaces/requests/actions.d.ts +31 -0
  135. package/dist_ts_interfaces/requests/actions.js +3 -0
  136. package/dist_ts_interfaces/requests/admin.d.ts +31 -0
  137. package/dist_ts_interfaces/requests/admin.js +3 -0
  138. package/dist_ts_interfaces/requests/connections.d.ts +71 -0
  139. package/dist_ts_interfaces/requests/connections.js +3 -0
  140. package/dist_ts_interfaces/requests/groups.d.ts +14 -0
  141. package/dist_ts_interfaces/requests/groups.js +3 -0
  142. package/dist_ts_interfaces/requests/index.d.ts +13 -0
  143. package/dist_ts_interfaces/requests/index.js +14 -0
  144. package/dist_ts_interfaces/requests/jobs.d.ts +86 -0
  145. package/dist_ts_interfaces/requests/jobs.js +3 -0
  146. package/dist_ts_interfaces/requests/logs.d.ts +14 -0
  147. package/dist_ts_interfaces/requests/logs.js +3 -0
  148. package/dist_ts_interfaces/requests/managedsecrets.d.ts +84 -0
  149. package/dist_ts_interfaces/requests/managedsecrets.js +3 -0
  150. package/dist_ts_interfaces/requests/pipelines.d.ts +55 -0
  151. package/dist_ts_interfaces/requests/pipelines.js +3 -0
  152. package/dist_ts_interfaces/requests/projects.d.ts +14 -0
  153. package/dist_ts_interfaces/requests/projects.js +3 -0
  154. package/dist_ts_interfaces/requests/secrets.d.ts +72 -0
  155. package/dist_ts_interfaces/requests/secrets.js +3 -0
  156. package/dist_ts_interfaces/requests/sync.d.ts +120 -0
  157. package/dist_ts_interfaces/requests/sync.js +3 -0
  158. package/dist_ts_interfaces/requests/webhook.d.ts +13 -0
  159. package/dist_ts_interfaces/requests/webhook.js +3 -0
  160. package/license +21 -0
  161. package/package.json +81 -0
  162. package/readme.md +177 -0
  163. package/readme.todo.md +3 -0
  164. package/ts/00_commitinfo_data.ts +8 -0
  165. package/ts/cache/classes.cache.cleaner.ts +69 -0
  166. package/ts/cache/classes.cached.document.ts +57 -0
  167. package/ts/cache/classes.cachedb.ts +72 -0
  168. package/ts/cache/classes.secrets.scan.service.ts +267 -0
  169. package/ts/cache/documents/classes.cached.project.ts +32 -0
  170. package/ts/cache/documents/classes.cached.secret.ts +81 -0
  171. package/ts/cache/documents/index.ts +2 -0
  172. package/ts/cache/index.ts +7 -0
  173. package/ts/classes/actionlog.ts +57 -0
  174. package/ts/classes/connectionmanager.ts +263 -0
  175. package/ts/classes/gitopsapp.ts +128 -0
  176. package/ts/classes/jobmanager.ts +337 -0
  177. package/ts/classes/jobrunners/autobookstackdocs.runner.ts +435 -0
  178. package/ts/classes/jobrunners/base.jobrunner.ts +16 -0
  179. package/ts/classes/jobrunners/index.ts +17 -0
  180. package/ts/classes/managedsecrets.manager.ts +322 -0
  181. package/ts/classes/syncmanager.ts +2117 -0
  182. package/ts/index.ts +37 -0
  183. package/ts/logging.ts +162 -0
  184. package/ts/opsserver/classes.opsserver.ts +86 -0
  185. package/ts/opsserver/handlers/actionlog.handler.ts +30 -0
  186. package/ts/opsserver/handlers/actions.handler.ts +50 -0
  187. package/ts/opsserver/handlers/admin.handler.ts +122 -0
  188. package/ts/opsserver/handlers/connections.handler.ts +162 -0
  189. package/ts/opsserver/handlers/groups.handler.ts +32 -0
  190. package/ts/opsserver/handlers/index.ts +13 -0
  191. package/ts/opsserver/handlers/jobs.handler.ts +189 -0
  192. package/ts/opsserver/handlers/logs.handler.ts +29 -0
  193. package/ts/opsserver/handlers/managedsecrets.handler.ts +158 -0
  194. package/ts/opsserver/handlers/pipelines.handler.ts +281 -0
  195. package/ts/opsserver/handlers/projects.handler.ts +32 -0
  196. package/ts/opsserver/handlers/secrets.handler.ts +224 -0
  197. package/ts/opsserver/handlers/sync.handler.ts +224 -0
  198. package/ts/opsserver/handlers/webhook.handler.ts +62 -0
  199. package/ts/opsserver/helpers/guards.ts +16 -0
  200. package/ts/opsserver/index.ts +1 -0
  201. package/ts/paths.ts +19 -0
  202. package/ts/plugins.ts +38 -0
  203. package/ts/providers/classes.baseprovider.ts +99 -0
  204. package/ts/providers/classes.giteaprovider.ts +279 -0
  205. package/ts/providers/classes.gitlabprovider.ts +265 -0
  206. package/ts/providers/index.ts +3 -0
  207. package/ts/storage/classes.storagemanager.ts +144 -0
  208. package/ts/storage/index.ts +2 -0
  209. package/ts/timers.ts +34 -0
  210. package/ts_interfaces/data/actionlog.ts +13 -0
  211. package/ts_interfaces/data/branch.ts +9 -0
  212. package/ts_interfaces/data/connection.ts +13 -0
  213. package/ts_interfaces/data/group.ts +10 -0
  214. package/ts_interfaces/data/identity.ts +7 -0
  215. package/ts_interfaces/data/index.ts +11 -0
  216. package/ts_interfaces/data/job.ts +42 -0
  217. package/ts_interfaces/data/managedsecret.ts +41 -0
  218. package/ts_interfaces/data/pipeline.ts +32 -0
  219. package/ts_interfaces/data/project.ts +12 -0
  220. package/ts_interfaces/data/secret.ts +11 -0
  221. package/ts_interfaces/data/sync.ts +37 -0
  222. package/ts_interfaces/index.ts +9 -0
  223. package/ts_interfaces/plugins.ts +6 -0
  224. package/ts_interfaces/requests/actionlog.ts +19 -0
  225. package/ts_interfaces/requests/actions.ts +39 -0
  226. package/ts_interfaces/requests/admin.ts +43 -0
  227. package/ts_interfaces/requests/connections.ts +95 -0
  228. package/ts_interfaces/requests/groups.ts +18 -0
  229. package/ts_interfaces/requests/index.ts +13 -0
  230. package/ts_interfaces/requests/jobs.ts +118 -0
  231. package/ts_interfaces/requests/logs.ts +18 -0
  232. package/ts_interfaces/requests/managedsecrets.ts +112 -0
  233. package/ts_interfaces/requests/pipelines.ts +71 -0
  234. package/ts_interfaces/requests/projects.ts +18 -0
  235. package/ts_interfaces/requests/secrets.ts +92 -0
  236. package/ts_interfaces/requests/sync.ts +157 -0
  237. package/ts_interfaces/requests/webhook.ts +18 -0
  238. package/ts_web/00_commitinfo_data.ts +8 -0
  239. package/ts_web/appstate.ts +1251 -0
  240. package/ts_web/elements/gitops-dashboard.ts +350 -0
  241. package/ts_web/elements/index.ts +10 -0
  242. package/ts_web/elements/shared/css.ts +29 -0
  243. package/ts_web/elements/shared/index.ts +1 -0
  244. package/ts_web/elements/views/actionlog/index.ts +101 -0
  245. package/ts_web/elements/views/actions/index.ts +209 -0
  246. package/ts_web/elements/views/buildlog/index.ts +196 -0
  247. package/ts_web/elements/views/connections/index.ts +260 -0
  248. package/ts_web/elements/views/groups/index.ts +134 -0
  249. package/ts_web/elements/views/jobs/index.ts +424 -0
  250. package/ts_web/elements/views/managedsecrets/index.ts +502 -0
  251. package/ts_web/elements/views/overview/index.ts +86 -0
  252. package/ts_web/elements/views/pipelines/index.ts +561 -0
  253. package/ts_web/elements/views/projects/index.ts +149 -0
  254. package/ts_web/elements/views/secrets/index.ts +310 -0
  255. package/ts_web/elements/views/sync/index.ts +512 -0
  256. package/ts_web/index.ts +7 -0
  257. package/ts_web/plugins.ts +15 -0
  258. package/tsconfig.json +15 -0
@@ -0,0 +1,350 @@
1
+ import * as plugins from '../plugins.js';
2
+ import * as appstate from '../appstate.js';
3
+ import * as interfaces from '../../ts_interfaces/index.js';
4
+ import {
5
+ DeesElement,
6
+ customElement,
7
+ html,
8
+ state,
9
+ css,
10
+ cssManager,
11
+ type TemplateResult,
12
+ } from '@design.estate/dees-element';
13
+
14
+ import type { GitopsViewOverview } from './views/overview/index.js';
15
+ import type { GitopsViewConnections } from './views/connections/index.js';
16
+ import type { GitopsViewProjects } from './views/projects/index.js';
17
+ import type { GitopsViewGroups } from './views/groups/index.js';
18
+ import type { GitopsViewSecrets } from './views/secrets/index.js';
19
+ import type { GitopsViewPipelines } from './views/pipelines/index.js';
20
+ import type { GitopsViewBuildlog } from './views/buildlog/index.js';
21
+ import type { GitopsViewActions } from './views/actions/index.js';
22
+ import type { GitopsViewActionlog } from './views/actionlog/index.js';
23
+ import type { GitopsViewSync } from './views/sync/index.js';
24
+ import type { GitopsViewJobs } from './views/jobs/index.js';
25
+
26
+ @customElement('gitops-dashboard')
27
+ export class GitopsDashboard extends DeesElement {
28
+ @state()
29
+ accessor loginState: appstate.ILoginState = { identity: null, isLoggedIn: false };
30
+
31
+ @state()
32
+ accessor uiState: appstate.IUiState = {
33
+ activeView: 'overview',
34
+ autoRefresh: true,
35
+ refreshInterval: 30000,
36
+ };
37
+
38
+ private viewTabs = [
39
+ { name: 'Overview', iconName: 'lucide:layoutDashboard', element: (async () => (await import('./views/overview/index.js')).GitopsViewOverview)() },
40
+ { name: 'Connections', iconName: 'lucide:plug', element: (async () => (await import('./views/connections/index.js')).GitopsViewConnections)() },
41
+ { name: 'Projects', iconName: 'lucide:folderGit2', element: (async () => (await import('./views/projects/index.js')).GitopsViewProjects)() },
42
+ { name: 'Groups', iconName: 'lucide:users', element: (async () => (await import('./views/groups/index.js')).GitopsViewGroups)() },
43
+ { name: 'Secrets', iconName: 'lucide:key', element: (async () => (await import('./views/secrets/index.js')).GitopsViewSecrets)() },
44
+ { name: 'Managed Secrets', iconName: 'lucide:keyRound', element: (async () => (await import('./views/managedsecrets/index.js')).GitopsViewManagedSecrets)() },
45
+ { name: 'Pipelines', iconName: 'lucide:play', element: (async () => (await import('./views/pipelines/index.js')).GitopsViewPipelines)() },
46
+ { name: 'Build Log', iconName: 'lucide:scrollText', element: (async () => (await import('./views/buildlog/index.js')).GitopsViewBuildlog)() },
47
+ { name: 'Actions', iconName: 'lucide:zap', element: (async () => (await import('./views/actions/index.js')).GitopsViewActions)() },
48
+ { name: 'Action Log', iconName: 'lucide:scroll', element: (async () => (await import('./views/actionlog/index.js')).GitopsViewActionlog)() },
49
+ { name: 'Sync', iconName: 'lucide:refreshCw', element: (async () => (await import('./views/sync/index.js')).GitopsViewSync)() },
50
+ { name: 'Jobs', iconName: 'lucide:briefcase', element: (async () => (await import('./views/jobs/index.js')).GitopsViewJobs)() },
51
+ ];
52
+
53
+ private resolvedViewTabs: Array<{ name: string; iconName: string; element: any }> = [];
54
+
55
+ // Auto-refresh timer
56
+ private autoRefreshTimer: ReturnType<typeof setInterval> | null = null;
57
+
58
+ // WebSocket client
59
+ private ws: WebSocket | null = null;
60
+ private wsReconnectTimer: ReturnType<typeof setTimeout> | null = null;
61
+ private wsIntentionalClose = false;
62
+
63
+ constructor() {
64
+ super();
65
+ document.title = 'GitOps';
66
+
67
+ const loginSubscription = appstate.loginStatePart
68
+ .select((stateArg) => stateArg)
69
+ .subscribe((loginState) => {
70
+ this.loginState = loginState;
71
+ if (loginState.isLoggedIn) {
72
+ appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
73
+ this.connectWebSocket();
74
+ } else {
75
+ this.disconnectWebSocket();
76
+ }
77
+ this.manageAutoRefreshTimer();
78
+ });
79
+ this.rxSubscriptions.push(loginSubscription);
80
+
81
+ const uiSubscription = appstate.uiStatePart
82
+ .select((stateArg) => stateArg)
83
+ .subscribe((uiState) => {
84
+ this.uiState = uiState;
85
+ this.syncAppdashView(uiState.activeView);
86
+ this.manageAutoRefreshTimer();
87
+ });
88
+ this.rxSubscriptions.push(uiSubscription);
89
+ }
90
+
91
+ public static styles = [
92
+ cssManager.defaultStyles,
93
+ css`
94
+ :host {
95
+ display: block;
96
+ width: 100%;
97
+ height: 100%;
98
+ }
99
+ .maincontainer {
100
+ width: 100%;
101
+ height: 100vh;
102
+ }
103
+ .auto-refresh-toggle {
104
+ position: fixed;
105
+ bottom: 16px;
106
+ right: 16px;
107
+ z-index: 1000;
108
+ background: rgba(30, 30, 50, 0.9);
109
+ border: 1px solid rgba(255, 255, 255, 0.1);
110
+ border-radius: 8px;
111
+ padding: 8px 14px;
112
+ color: #ccc;
113
+ font-size: 12px;
114
+ cursor: pointer;
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 8px;
118
+ backdrop-filter: blur(8px);
119
+ transition: background 0.2s;
120
+ }
121
+ .auto-refresh-toggle:hover {
122
+ background: rgba(40, 40, 70, 0.95);
123
+ }
124
+ .auto-refresh-dot {
125
+ width: 8px;
126
+ height: 8px;
127
+ border-radius: 50%;
128
+ background: #666;
129
+ }
130
+ .auto-refresh-dot.active {
131
+ background: #00ff88;
132
+ }
133
+ `,
134
+ ];
135
+
136
+ public render(): TemplateResult {
137
+ return html`
138
+ <div class="maincontainer">
139
+ <dees-simple-login name="GitOps">
140
+ <dees-simple-appdash
141
+ name="GitOps"
142
+ .viewTabs=${this.resolvedViewTabs}
143
+ >
144
+ </dees-simple-appdash>
145
+ </dees-simple-login>
146
+ </div>
147
+ ${this.loginState.isLoggedIn ? html`
148
+ <div
149
+ class="auto-refresh-toggle"
150
+ @click=${() => appstate.uiStatePart.dispatchAction(appstate.toggleAutoRefreshAction, null)}
151
+ >
152
+ <span class="auto-refresh-dot ${this.uiState.autoRefresh ? 'active' : ''}"></span>
153
+ Auto-Refresh: ${this.uiState.autoRefresh ? 'ON' : 'OFF'}
154
+ </div>
155
+ ` : ''}
156
+ `;
157
+ }
158
+
159
+ public async firstUpdated() {
160
+ // Resolve async view tab imports
161
+ this.resolvedViewTabs = await Promise.all(
162
+ this.viewTabs.map(async (tab) => ({
163
+ name: tab.name,
164
+ iconName: tab.iconName,
165
+ element: await tab.element,
166
+ })),
167
+ );
168
+ this.requestUpdate();
169
+ await this.updateComplete;
170
+
171
+ const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
172
+ if (simpleLogin) {
173
+ simpleLogin.addEventListener('login', (e: CustomEvent) => {
174
+ this.login(e.detail.data.username, e.detail.data.password);
175
+ });
176
+ }
177
+
178
+ const appDash = this.shadowRoot!.querySelector('dees-simple-appdash') as any;
179
+ if (appDash) {
180
+ appDash.addEventListener('view-select', (e: CustomEvent) => {
181
+ const viewName = e.detail.view.name.toLowerCase();
182
+ if (this.uiState.activeView === viewName) return;
183
+ appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: viewName });
184
+ });
185
+ appDash.addEventListener('logout', async () => {
186
+ await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
187
+ });
188
+ }
189
+
190
+ // Load initial view on appdash
191
+ if (appDash && this.resolvedViewTabs.length > 0) {
192
+ const initialView = this.resolvedViewTabs.find(
193
+ (t) => t.name.toLowerCase() === this.uiState.activeView,
194
+ ) || this.resolvedViewTabs[0];
195
+ await appDash.loadView(initialView);
196
+ }
197
+
198
+ // Check for stored session (persistent login state)
199
+ const loginState = appstate.loginStatePart.getState();
200
+ if (loginState.identity?.jwt) {
201
+ if (loginState.identity.expiresAt > Date.now()) {
202
+ try {
203
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
204
+ interfaces.requests.IReq_VerifyIdentity
205
+ >('/typedrequest', 'verifyIdentity');
206
+ const response = await typedRequest.fire({ identity: loginState.identity });
207
+ if (response.valid) {
208
+ this.loginState = loginState;
209
+ if (simpleLogin) {
210
+ await simpleLogin.switchToSlottedContent();
211
+ }
212
+ } else {
213
+ await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
214
+ }
215
+ } catch (err) {
216
+ console.warn('Stored session invalid, returning to login:', err);
217
+ await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
218
+ }
219
+ } else {
220
+ await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
221
+ }
222
+ }
223
+ }
224
+
225
+ public override disconnectedCallback() {
226
+ super.disconnectedCallback();
227
+ this.clearAutoRefreshTimer();
228
+ this.disconnectWebSocket();
229
+ }
230
+
231
+ // ============================================================================
232
+ // Auto-refresh timer management
233
+ // ============================================================================
234
+
235
+ private manageAutoRefreshTimer(): void {
236
+ this.clearAutoRefreshTimer();
237
+ const { autoRefresh, refreshInterval } = this.uiState;
238
+ if (autoRefresh && this.loginState.isLoggedIn) {
239
+ this.autoRefreshTimer = setInterval(() => {
240
+ document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
241
+ }, refreshInterval);
242
+ }
243
+ }
244
+
245
+ private clearAutoRefreshTimer(): void {
246
+ if (this.autoRefreshTimer) {
247
+ clearInterval(this.autoRefreshTimer);
248
+ this.autoRefreshTimer = null;
249
+ }
250
+ }
251
+
252
+ // ============================================================================
253
+ // WebSocket client for webhook push notifications
254
+ // ============================================================================
255
+
256
+ private connectWebSocket(): void {
257
+ if (this.ws) return;
258
+
259
+ const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
260
+ const wsUrl = `${protocol}//${location.host}`;
261
+
262
+ try {
263
+ this.wsIntentionalClose = false;
264
+ this.ws = new WebSocket(wsUrl);
265
+
266
+ this.ws.addEventListener('message', (event) => {
267
+ try {
268
+ const data = JSON.parse(event.data);
269
+ // TypedSocket wraps messages; look for webhookNotification method
270
+ if (data?.method === 'webhookNotification' || data?.type === 'webhookEvent') {
271
+ console.log('Webhook event received:', data);
272
+ document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
273
+ }
274
+ } catch {
275
+ // Not JSON, ignore
276
+ }
277
+ });
278
+
279
+ this.ws.addEventListener('close', () => {
280
+ this.ws = null;
281
+ if (!this.wsIntentionalClose && this.loginState.isLoggedIn) {
282
+ this.wsReconnectTimer = setTimeout(() => {
283
+ this.connectWebSocket();
284
+ }, 5000);
285
+ }
286
+ });
287
+
288
+ this.ws.addEventListener('error', () => {
289
+ // Will trigger close event
290
+ });
291
+ } catch (err) {
292
+ console.warn('WebSocket connection failed:', err);
293
+ }
294
+ }
295
+
296
+ private disconnectWebSocket(): void {
297
+ this.wsIntentionalClose = true;
298
+ if (this.wsReconnectTimer) {
299
+ clearTimeout(this.wsReconnectTimer);
300
+ this.wsReconnectTimer = null;
301
+ }
302
+ if (this.ws) {
303
+ this.ws.close();
304
+ this.ws = null;
305
+ }
306
+ }
307
+
308
+ // ============================================================================
309
+ // Login
310
+ // ============================================================================
311
+
312
+ private async login(username: string, password: string) {
313
+ const domtools = await this.domtoolsPromise;
314
+ const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
315
+ const form = simpleLogin?.shadowRoot?.querySelector('dees-form') as any;
316
+
317
+ if (form) {
318
+ form.setStatus('pending', 'Logging in...');
319
+ }
320
+
321
+ const newState = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
322
+ username,
323
+ password,
324
+ });
325
+
326
+ if (newState.identity) {
327
+ if (form) {
328
+ form.setStatus('success', 'Logged in!');
329
+ }
330
+ if (simpleLogin) {
331
+ await simpleLogin.switchToSlottedContent();
332
+ }
333
+ } else {
334
+ if (form) {
335
+ form.setStatus('error', 'Login failed!');
336
+ await domtools.convenience.smartdelay.delayFor(2000);
337
+ form.reset();
338
+ }
339
+ }
340
+ }
341
+
342
+ private syncAppdashView(viewName: string): void {
343
+ const appDash = this.shadowRoot?.querySelector('dees-simple-appdash') as any;
344
+ if (!appDash || this.resolvedViewTabs.length === 0) return;
345
+ const targetTab = this.resolvedViewTabs.find((t) => t.name.toLowerCase() === viewName);
346
+ if (!targetTab) return;
347
+ if (appDash.selectedView === targetTab) return;
348
+ appDash.loadView(targetTab);
349
+ }
350
+ }
@@ -0,0 +1,10 @@
1
+ import './gitops-dashboard.js';
2
+ import './views/overview/index.js';
3
+ import './views/connections/index.js';
4
+ import './views/projects/index.js';
5
+ import './views/groups/index.js';
6
+ import './views/secrets/index.js';
7
+ import './views/pipelines/index.js';
8
+ import './views/buildlog/index.js';
9
+ import './views/actions/index.js';
10
+ import './views/managedsecrets/index.js';
@@ -0,0 +1,29 @@
1
+ import { css } from '@design.estate/dees-element';
2
+
3
+ export const viewHostCss = css`
4
+ :host {
5
+ display: block;
6
+ margin: auto;
7
+ max-width: 1280px;
8
+ padding: 16px 16px;
9
+ color: #fff;
10
+ box-sizing: border-box;
11
+ }
12
+ .view-title {
13
+ font-size: 24px;
14
+ font-weight: 600;
15
+ margin-bottom: 24px;
16
+ }
17
+ .view-description {
18
+ font-size: 14px;
19
+ color: #999;
20
+ margin-bottom: 24px;
21
+ }
22
+ .toolbar {
23
+ display: flex;
24
+ gap: 16px;
25
+ align-items: center;
26
+ margin-bottom: 24px;
27
+ flex-wrap: wrap;
28
+ }
29
+ `;
@@ -0,0 +1 @@
1
+ export * from './css.js';
@@ -0,0 +1,101 @@
1
+ import * as plugins from '../../../plugins.js';
2
+ import * as appstate from '../../../appstate.js';
3
+ import { viewHostCss } from '../../shared/index.js';
4
+ import {
5
+ DeesElement,
6
+ customElement,
7
+ html,
8
+ state,
9
+ css,
10
+ cssManager,
11
+ type TemplateResult,
12
+ } from '@design.estate/dees-element';
13
+
14
+ @customElement('gitops-view-actionlog')
15
+ export class GitopsViewActionlog extends DeesElement {
16
+ @state()
17
+ accessor actionLogState: appstate.IActionLogState = {
18
+ entries: [],
19
+ total: 0,
20
+ };
21
+
22
+ @state()
23
+ accessor selectedEntityType: string = 'all';
24
+
25
+ private _autoRefreshHandler: () => void;
26
+
27
+ constructor() {
28
+ super();
29
+ const sub = appstate.actionLogStatePart
30
+ .select((s) => s)
31
+ .subscribe((s) => { this.actionLogState = s; });
32
+ this.rxSubscriptions.push(sub);
33
+
34
+ this._autoRefreshHandler = () => this.refresh();
35
+ document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
36
+ }
37
+
38
+ public override disconnectedCallback() {
39
+ super.disconnectedCallback();
40
+ document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
41
+ }
42
+
43
+ public static styles = [
44
+ cssManager.defaultStyles,
45
+ viewHostCss,
46
+ ];
47
+
48
+ public render(): TemplateResult {
49
+ const entityOptions = [
50
+ { option: 'All', key: 'all' },
51
+ { option: 'Connection', key: 'connection' },
52
+ { option: 'Secret', key: 'secret' },
53
+ { option: 'Pipeline', key: 'pipeline' },
54
+ ];
55
+
56
+ return html`
57
+ <div class="view-title">Action Log</div>
58
+ <div class="view-description">Audit trail of all operations performed in the system</div>
59
+ <div class="toolbar">
60
+ <dees-input-dropdown
61
+ .label=${'Entity Type'}
62
+ .options=${entityOptions}
63
+ .selectedOption=${entityOptions.find((o) => o.key === this.selectedEntityType)}
64
+ @selectedOption=${(e: CustomEvent) => {
65
+ this.selectedEntityType = e.detail.key;
66
+ this.refresh();
67
+ }}
68
+ ></dees-input-dropdown>
69
+ <dees-button @click=${() => this.refresh()}>Refresh</dees-button>
70
+ </div>
71
+ <dees-table
72
+ .heading1=${'Action Log'}
73
+ .heading2=${`${this.actionLogState.total} entries total`}
74
+ .data=${this.actionLogState.entries}
75
+ .displayFunction=${(item: any) => ({
76
+ Time: new Date(item.timestamp).toLocaleString(),
77
+ Action: item.actionType,
78
+ Entity: item.entityType,
79
+ Name: item.entityName,
80
+ Details: item.details,
81
+ User: item.username,
82
+ })}
83
+ .dataActions=${[]}
84
+ ></dees-table>
85
+ `;
86
+ }
87
+
88
+ async firstUpdated() {
89
+ await this.refresh();
90
+ }
91
+
92
+ private async refresh() {
93
+ const entityType = this.selectedEntityType === 'all'
94
+ ? undefined
95
+ : this.selectedEntityType as any;
96
+ await appstate.actionLogStatePart.dispatchAction(appstate.fetchActionLogAction, {
97
+ limit: 100,
98
+ entityType,
99
+ });
100
+ }
101
+ }
@@ -0,0 +1,209 @@
1
+ import * as plugins from '../../../plugins.js';
2
+ import * as interfaces from '../../../../ts_interfaces/index.js';
3
+ import * as appstate from '../../../appstate.js';
4
+ import { viewHostCss } from '../../shared/index.js';
5
+ import {
6
+ DeesElement,
7
+ customElement,
8
+ html,
9
+ state,
10
+ css,
11
+ cssManager,
12
+ type TemplateResult,
13
+ } from '@design.estate/dees-element';
14
+
15
+ @customElement('gitops-view-actions')
16
+ export class GitopsViewActions extends DeesElement {
17
+ @state()
18
+ accessor lastScanTimestamp: number = 0;
19
+
20
+ @state()
21
+ accessor isScanning: boolean = false;
22
+
23
+ @state()
24
+ accessor lastResult: {
25
+ connectionsScanned: number;
26
+ secretsFound: number;
27
+ errors: string[];
28
+ durationMs: number;
29
+ } | null = null;
30
+
31
+ @state()
32
+ accessor statusError: string = '';
33
+
34
+ public static styles = [
35
+ cssManager.defaultStyles,
36
+ viewHostCss,
37
+ css`
38
+ .action-cards {
39
+ display: grid;
40
+ grid-template-columns: 1fr;
41
+ gap: 24px;
42
+ max-width: 720px;
43
+ }
44
+ .action-card {
45
+ background: rgba(255, 255, 255, 0.04);
46
+ border: 1px solid rgba(255, 255, 255, 0.08);
47
+ border-radius: 12px;
48
+ padding: 28px;
49
+ }
50
+ .action-card-title {
51
+ font-size: 18px;
52
+ font-weight: 600;
53
+ margin-bottom: 8px;
54
+ }
55
+ .action-card-description {
56
+ font-size: 13px;
57
+ color: #999;
58
+ line-height: 1.5;
59
+ margin-bottom: 20px;
60
+ }
61
+ .info-grid {
62
+ display: grid;
63
+ grid-template-columns: 140px 1fr;
64
+ gap: 8px 16px;
65
+ margin-bottom: 20px;
66
+ font-size: 13px;
67
+ }
68
+ .info-label {
69
+ color: #888;
70
+ }
71
+ .info-value {
72
+ color: #ddd;
73
+ font-family: monospace;
74
+ }
75
+ .info-value.scanning {
76
+ color: #f0c040;
77
+ }
78
+ .info-value.error {
79
+ color: #ff6060;
80
+ }
81
+ .button-row {
82
+ display: flex;
83
+ gap: 12px;
84
+ align-items: center;
85
+ }
86
+ .errors-list {
87
+ margin-top: 12px;
88
+ max-height: 160px;
89
+ overflow-y: auto;
90
+ font-size: 12px;
91
+ color: #ff8080;
92
+ font-family: monospace;
93
+ line-height: 1.6;
94
+ background: rgba(255, 0, 0, 0.05);
95
+ border-radius: 6px;
96
+ padding: 8px 12px;
97
+ }
98
+ `,
99
+ ];
100
+
101
+ public render(): TemplateResult {
102
+ const lastScanFormatted = this.lastScanTimestamp
103
+ ? new Date(this.lastScanTimestamp).toLocaleString()
104
+ : 'Never';
105
+
106
+ return html`
107
+ <div class="view-title">Actions</div>
108
+ <div class="view-description">System actions and maintenance tasks</div>
109
+ <div class="action-cards">
110
+ <div class="action-card">
111
+ <div class="action-card-title">Secrets Cache Scan</div>
112
+ <div class="action-card-description">
113
+ Secrets are automatically scanned and cached every 24 hours.
114
+ Use "Force Full Scan" to trigger an immediate refresh of all secrets
115
+ across all connections, projects, and groups.
116
+ </div>
117
+ <div class="info-grid">
118
+ <div class="info-label">Status</div>
119
+ <div class="info-value ${this.isScanning ? 'scanning' : ''}">
120
+ ${this.isScanning ? 'Scanning...' : 'Idle'}
121
+ </div>
122
+ <div class="info-label">Last Scan</div>
123
+ <div class="info-value">${lastScanFormatted}</div>
124
+ ${this.lastResult ? html`
125
+ <div class="info-label">Connections</div>
126
+ <div class="info-value">${this.lastResult.connectionsScanned}</div>
127
+ <div class="info-label">Secrets Found</div>
128
+ <div class="info-value">${this.lastResult.secretsFound}</div>
129
+ <div class="info-label">Duration</div>
130
+ <div class="info-value">${(this.lastResult.durationMs / 1000).toFixed(1)}s</div>
131
+ ${this.lastResult.errors.length > 0 ? html`
132
+ <div class="info-label">Errors</div>
133
+ <div class="info-value error">${this.lastResult.errors.length}</div>
134
+ ` : ''}
135
+ ` : ''}
136
+ </div>
137
+ ${this.statusError ? html`
138
+ <div class="errors-list">${this.statusError}</div>
139
+ ` : ''}
140
+ ${this.lastResult?.errors?.length ? html`
141
+ <div class="errors-list">
142
+ ${this.lastResult.errors.map((e) => html`<div>${e}</div>`)}
143
+ </div>
144
+ ` : ''}
145
+ <div class="button-row">
146
+ <dees-button
147
+ .disabled=${this.isScanning}
148
+ @click=${() => this.forceScan()}
149
+ >Force Full Scan</dees-button>
150
+ <dees-button
151
+ @click=${() => this.refreshStatus()}
152
+ >Refresh Status</dees-button>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ `;
157
+ }
158
+
159
+ async firstUpdated() {
160
+ await this.refreshStatus();
161
+ }
162
+
163
+ private getIdentity(): interfaces.data.IIdentity | null {
164
+ return appstate.loginStatePart.getState().identity;
165
+ }
166
+
167
+ private async refreshStatus(): Promise<void> {
168
+ const identity = this.getIdentity();
169
+ if (!identity) return;
170
+
171
+ try {
172
+ this.statusError = '';
173
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
174
+ interfaces.requests.IReq_GetScanStatus
175
+ >('/typedrequest', 'getScanStatus');
176
+ const response = await typedRequest.fire({ identity });
177
+ this.lastScanTimestamp = response.lastScanTimestamp;
178
+ this.isScanning = response.isScanning;
179
+ this.lastResult = response.lastResult;
180
+ } catch (err) {
181
+ this.statusError = `Failed to get status: ${err}`;
182
+ }
183
+ }
184
+
185
+ private async forceScan(): Promise<void> {
186
+ const identity = this.getIdentity();
187
+ if (!identity) return;
188
+
189
+ try {
190
+ this.statusError = '';
191
+ this.isScanning = true;
192
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
193
+ interfaces.requests.IReq_ForceScanSecrets
194
+ >('/typedrequest', 'forceScanSecrets');
195
+ const response = await typedRequest.fire({ identity });
196
+ this.lastResult = {
197
+ connectionsScanned: response.connectionsScanned,
198
+ secretsFound: response.secretsFound,
199
+ errors: response.errors,
200
+ durationMs: response.durationMs,
201
+ };
202
+ this.lastScanTimestamp = Date.now();
203
+ this.isScanning = false;
204
+ } catch (err) {
205
+ this.statusError = `Scan failed: ${err}`;
206
+ this.isScanning = false;
207
+ }
208
+ }
209
+ }