@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,1251 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as interfaces from '../ts_interfaces/index.js';
3
+
4
+ // ============================================================================
5
+ // Smartstate instance
6
+ // ============================================================================
7
+ export const appState = new plugins.domtools.plugins.smartstate.Smartstate();
8
+
9
+ // ============================================================================
10
+ // State Part Interfaces
11
+ // ============================================================================
12
+
13
+ export interface ILoginState {
14
+ identity: interfaces.data.IIdentity | null;
15
+ isLoggedIn: boolean;
16
+ }
17
+
18
+ export interface IConnectionsState {
19
+ connections: interfaces.data.IProviderConnection[];
20
+ activeConnectionId: string | null;
21
+ }
22
+
23
+ export interface IDataState {
24
+ projects: interfaces.data.IProject[];
25
+ groups: interfaces.data.IGroup[];
26
+ secrets: interfaces.data.ISecret[];
27
+ pipelines: interfaces.data.IPipeline[];
28
+ pipelineJobs: interfaces.data.IPipelineJob[];
29
+ currentJobLog: string;
30
+ }
31
+
32
+ export interface IActionLogState {
33
+ entries: interfaces.data.IActionLogEntry[];
34
+ total: number;
35
+ }
36
+
37
+ export interface INavigationContext {
38
+ connectionId?: string;
39
+ scope?: 'project' | 'group';
40
+ scopeId?: string;
41
+ projectId?: string;
42
+ }
43
+
44
+ export interface IUiState {
45
+ activeView: string;
46
+ autoRefresh: boolean;
47
+ refreshInterval: number;
48
+ navigationContext?: INavigationContext;
49
+ }
50
+
51
+ // ============================================================================
52
+ // State Parts
53
+ // ============================================================================
54
+
55
+ export const loginStatePart = await appState.getStatePart<ILoginState>(
56
+ 'login',
57
+ {
58
+ identity: null,
59
+ isLoggedIn: false,
60
+ },
61
+ 'persistent',
62
+ );
63
+
64
+ export const connectionsStatePart = await appState.getStatePart<IConnectionsState>(
65
+ 'connections',
66
+ {
67
+ connections: [],
68
+ activeConnectionId: null,
69
+ },
70
+ 'soft',
71
+ );
72
+
73
+ export const dataStatePart = await appState.getStatePart<IDataState>(
74
+ 'data',
75
+ {
76
+ projects: [],
77
+ groups: [],
78
+ secrets: [],
79
+ pipelines: [],
80
+ pipelineJobs: [],
81
+ currentJobLog: '',
82
+ },
83
+ 'soft',
84
+ );
85
+
86
+ export const actionLogStatePart = await appState.getStatePart<IActionLogState>(
87
+ 'actionLog',
88
+ {
89
+ entries: [],
90
+ total: 0,
91
+ },
92
+ 'soft',
93
+ );
94
+
95
+ export const uiStatePart = await appState.getStatePart<IUiState>(
96
+ 'ui',
97
+ {
98
+ activeView: 'overview',
99
+ autoRefresh: true,
100
+ refreshInterval: 30000,
101
+ },
102
+ );
103
+
104
+ // ============================================================================
105
+ // Helpers
106
+ // ============================================================================
107
+
108
+ interface IActionContext {
109
+ identity: interfaces.data.IIdentity | null;
110
+ }
111
+
112
+ const getActionContext = (): IActionContext => {
113
+ return { identity: loginStatePart.getState().identity };
114
+ };
115
+
116
+ // ============================================================================
117
+ // Login Actions
118
+ // ============================================================================
119
+
120
+ export const loginAction = loginStatePart.createAction<{
121
+ username: string;
122
+ password: string;
123
+ }>(async (statePartArg, dataArg) => {
124
+ try {
125
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
126
+ interfaces.requests.IReq_AdminLogin
127
+ >('/typedrequest', 'adminLogin');
128
+
129
+ const response = await typedRequest.fire({
130
+ username: dataArg.username,
131
+ password: dataArg.password,
132
+ });
133
+
134
+ return {
135
+ identity: response.identity || null,
136
+ isLoggedIn: !!response.identity,
137
+ };
138
+ } catch (err) {
139
+ console.error('Login failed:', err);
140
+ return { identity: null, isLoggedIn: false };
141
+ }
142
+ });
143
+
144
+ export const logoutAction = loginStatePart.createAction(async (_statePartArg) => {
145
+ const context = getActionContext();
146
+ try {
147
+ if (context.identity) {
148
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
149
+ interfaces.requests.IReq_AdminLogout
150
+ >('/typedrequest', 'adminLogout');
151
+ await typedRequest.fire({ identity: context.identity });
152
+ }
153
+ } catch (err) {
154
+ console.error('Logout error:', err);
155
+ }
156
+ return { identity: null, isLoggedIn: false };
157
+ });
158
+
159
+ // ============================================================================
160
+ // Connections Actions
161
+ // ============================================================================
162
+
163
+ export const fetchConnectionsAction = connectionsStatePart.createAction(async (statePartArg) => {
164
+ const context = getActionContext();
165
+ try {
166
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
167
+ interfaces.requests.IReq_GetConnections
168
+ >('/typedrequest', 'getConnections');
169
+ const response = await typedRequest.fire({ identity: context.identity! });
170
+ return { ...statePartArg.getState(), connections: response.connections };
171
+ } catch (err) {
172
+ console.error('Failed to fetch connections:', err);
173
+ return statePartArg.getState();
174
+ }
175
+ });
176
+
177
+ export const createConnectionAction = connectionsStatePart.createAction<{
178
+ name: string;
179
+ providerType: interfaces.data.TProviderType;
180
+ baseUrl: string;
181
+ token: string;
182
+ groupFilter?: string;
183
+ }>(async (statePartArg, dataArg) => {
184
+ const context = getActionContext();
185
+ try {
186
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
187
+ interfaces.requests.IReq_CreateConnection
188
+ >('/typedrequest', 'createConnection');
189
+ await typedRequest.fire({
190
+ identity: context.identity!,
191
+ ...dataArg,
192
+ });
193
+ // Re-fetch
194
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
195
+ interfaces.requests.IReq_GetConnections
196
+ >('/typedrequest', 'getConnections');
197
+ const listResp = await listReq.fire({ identity: context.identity! });
198
+ return { ...statePartArg.getState(), connections: listResp.connections };
199
+ } catch (err) {
200
+ console.error('Failed to create connection:', err);
201
+ return statePartArg.getState();
202
+ }
203
+ });
204
+
205
+ export const testConnectionAction = connectionsStatePart.createAction<{
206
+ connectionId: string;
207
+ }>(async (statePartArg, dataArg) => {
208
+ const context = getActionContext();
209
+ try {
210
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
211
+ interfaces.requests.IReq_TestConnection
212
+ >('/typedrequest', 'testConnection');
213
+ const result = await typedRequest.fire({
214
+ identity: context.identity!,
215
+ connectionId: dataArg.connectionId,
216
+ });
217
+ // Re-fetch to get updated status
218
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
219
+ interfaces.requests.IReq_GetConnections
220
+ >('/typedrequest', 'getConnections');
221
+ const listResp = await listReq.fire({ identity: context.identity! });
222
+ return { ...statePartArg.getState(), connections: listResp.connections };
223
+ } catch (err) {
224
+ console.error('Failed to test connection:', err);
225
+ return statePartArg.getState();
226
+ }
227
+ });
228
+
229
+ export const deleteConnectionAction = connectionsStatePart.createAction<{
230
+ connectionId: string;
231
+ }>(async (statePartArg, dataArg) => {
232
+ const context = getActionContext();
233
+ try {
234
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
235
+ interfaces.requests.IReq_DeleteConnection
236
+ >('/typedrequest', 'deleteConnection');
237
+ await typedRequest.fire({
238
+ identity: context.identity!,
239
+ connectionId: dataArg.connectionId,
240
+ });
241
+ const state = statePartArg.getState();
242
+ return {
243
+ ...state,
244
+ connections: state.connections.filter((c) => c.id !== dataArg.connectionId),
245
+ activeConnectionId: state.activeConnectionId === dataArg.connectionId ? null : state.activeConnectionId,
246
+ };
247
+ } catch (err) {
248
+ console.error('Failed to delete connection:', err);
249
+ return statePartArg.getState();
250
+ }
251
+ });
252
+
253
+ export const pauseConnectionAction = connectionsStatePart.createAction<{
254
+ connectionId: string;
255
+ paused: boolean;
256
+ }>(async (statePartArg, dataArg) => {
257
+ const context = getActionContext();
258
+ try {
259
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
260
+ interfaces.requests.IReq_PauseConnection
261
+ >('/typedrequest', 'pauseConnection');
262
+ await typedRequest.fire({
263
+ identity: context.identity!,
264
+ ...dataArg,
265
+ });
266
+ // Re-fetch to get updated status
267
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
268
+ interfaces.requests.IReq_GetConnections
269
+ >('/typedrequest', 'getConnections');
270
+ const listResp = await listReq.fire({ identity: context.identity! });
271
+ return { ...statePartArg.getState(), connections: listResp.connections };
272
+ } catch (err) {
273
+ console.error('Failed to pause/resume connection:', err);
274
+ return statePartArg.getState();
275
+ }
276
+ });
277
+
278
+ export const updateConnectionAction = connectionsStatePart.createAction<{
279
+ connectionId: string;
280
+ name?: string;
281
+ baseUrl?: string;
282
+ token?: string;
283
+ groupFilter?: string;
284
+ }>(async (statePartArg, dataArg) => {
285
+ const context = getActionContext();
286
+ try {
287
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
288
+ interfaces.requests.IReq_UpdateConnection
289
+ >('/typedrequest', 'updateConnection');
290
+ await typedRequest.fire({
291
+ identity: context.identity!,
292
+ ...dataArg,
293
+ });
294
+ // Re-fetch to get updated data
295
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
296
+ interfaces.requests.IReq_GetConnections
297
+ >('/typedrequest', 'getConnections');
298
+ const listResp = await listReq.fire({ identity: context.identity! });
299
+ return { ...statePartArg.getState(), connections: listResp.connections };
300
+ } catch (err) {
301
+ console.error('Failed to update connection:', err);
302
+ return statePartArg.getState();
303
+ }
304
+ });
305
+
306
+ // ============================================================================
307
+ // Projects Actions
308
+ // ============================================================================
309
+
310
+ export const fetchProjectsAction = dataStatePart.createAction<{
311
+ connectionId: string;
312
+ search?: string;
313
+ }>(async (statePartArg, dataArg) => {
314
+ const context = getActionContext();
315
+ try {
316
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
317
+ interfaces.requests.IReq_GetProjects
318
+ >('/typedrequest', 'getProjects');
319
+ const response = await typedRequest.fire({
320
+ identity: context.identity!,
321
+ connectionId: dataArg.connectionId,
322
+ search: dataArg.search,
323
+ });
324
+ return { ...statePartArg.getState(), projects: response.projects };
325
+ } catch (err) {
326
+ console.error('Failed to fetch projects:', err);
327
+ return statePartArg.getState();
328
+ }
329
+ });
330
+
331
+ // ============================================================================
332
+ // Groups Actions
333
+ // ============================================================================
334
+
335
+ export const fetchGroupsAction = dataStatePart.createAction<{
336
+ connectionId: string;
337
+ search?: string;
338
+ }>(async (statePartArg, dataArg) => {
339
+ const context = getActionContext();
340
+ try {
341
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
342
+ interfaces.requests.IReq_GetGroups
343
+ >('/typedrequest', 'getGroups');
344
+ const response = await typedRequest.fire({
345
+ identity: context.identity!,
346
+ connectionId: dataArg.connectionId,
347
+ search: dataArg.search,
348
+ });
349
+ return { ...statePartArg.getState(), groups: response.groups };
350
+ } catch (err) {
351
+ console.error('Failed to fetch groups:', err);
352
+ return statePartArg.getState();
353
+ }
354
+ });
355
+
356
+ // ============================================================================
357
+ // Secrets Actions
358
+ // ============================================================================
359
+
360
+ export const fetchSecretsAction = dataStatePart.createAction<{
361
+ connectionId: string;
362
+ scope: 'project' | 'group';
363
+ scopeId: string;
364
+ }>(async (statePartArg, dataArg) => {
365
+ const context = getActionContext();
366
+ try {
367
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
368
+ interfaces.requests.IReq_GetSecrets
369
+ >('/typedrequest', 'getSecrets');
370
+ const response = await typedRequest.fire({
371
+ identity: context.identity!,
372
+ connectionId: dataArg.connectionId,
373
+ scope: dataArg.scope,
374
+ scopeId: dataArg.scopeId,
375
+ });
376
+ return { ...statePartArg.getState(), secrets: response.secrets };
377
+ } catch (err) {
378
+ console.error('Failed to fetch secrets:', err);
379
+ return statePartArg.getState();
380
+ }
381
+ });
382
+
383
+ export const fetchAllSecretsAction = dataStatePart.createAction<{
384
+ connectionId: string;
385
+ scope?: 'project' | 'group';
386
+ }>(async (statePartArg, dataArg) => {
387
+ const context = getActionContext();
388
+ try {
389
+ // When no scope specified, fetch both project and group secrets in parallel
390
+ const scopes: Array<'project' | 'group'> = dataArg.scope ? [dataArg.scope] : ['project', 'group'];
391
+ const results = await Promise.all(
392
+ scopes.map(async (scope) => {
393
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
394
+ interfaces.requests.IReq_GetAllSecrets
395
+ >('/typedrequest', 'getAllSecrets');
396
+ const response = await typedRequest.fire({
397
+ identity: context.identity!,
398
+ connectionId: dataArg.connectionId,
399
+ scope,
400
+ });
401
+ return response.secrets;
402
+ }),
403
+ );
404
+ return { ...statePartArg.getState(), secrets: results.flat() };
405
+ } catch (err) {
406
+ console.error('Failed to fetch all secrets:', err);
407
+ return statePartArg.getState();
408
+ }
409
+ });
410
+
411
+ export const createSecretAction = dataStatePart.createAction<{
412
+ connectionId: string;
413
+ scope: 'project' | 'group';
414
+ scopeId: string;
415
+ key: string;
416
+ value: string;
417
+ }>(async (statePartArg, dataArg) => {
418
+ const context = getActionContext();
419
+ try {
420
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
421
+ interfaces.requests.IReq_CreateSecret
422
+ >('/typedrequest', 'createSecret');
423
+ await typedRequest.fire({
424
+ identity: context.identity!,
425
+ ...dataArg,
426
+ });
427
+ // Re-fetch only the affected entity's secrets and merge
428
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
429
+ interfaces.requests.IReq_GetSecrets
430
+ >('/typedrequest', 'getSecrets');
431
+ const listResp = await listReq.fire({
432
+ identity: context.identity!,
433
+ connectionId: dataArg.connectionId,
434
+ scope: dataArg.scope,
435
+ scopeId: dataArg.scopeId,
436
+ });
437
+ const state = statePartArg.getState();
438
+ const otherSecrets = state.secrets.filter(
439
+ (s) => !(s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
440
+ );
441
+ return { ...state, secrets: [...otherSecrets, ...listResp.secrets] };
442
+ } catch (err) {
443
+ console.error('Failed to create secret:', err);
444
+ return statePartArg.getState();
445
+ }
446
+ });
447
+
448
+ export const updateSecretAction = dataStatePart.createAction<{
449
+ connectionId: string;
450
+ scope: 'project' | 'group';
451
+ scopeId: string;
452
+ key: string;
453
+ value: string;
454
+ }>(async (statePartArg, dataArg) => {
455
+ const context = getActionContext();
456
+ try {
457
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
458
+ interfaces.requests.IReq_UpdateSecret
459
+ >('/typedrequest', 'updateSecret');
460
+ await typedRequest.fire({
461
+ identity: context.identity!,
462
+ ...dataArg,
463
+ });
464
+ // Re-fetch only the affected entity's secrets and merge
465
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
466
+ interfaces.requests.IReq_GetSecrets
467
+ >('/typedrequest', 'getSecrets');
468
+ const listResp = await listReq.fire({
469
+ identity: context.identity!,
470
+ connectionId: dataArg.connectionId,
471
+ scope: dataArg.scope,
472
+ scopeId: dataArg.scopeId,
473
+ });
474
+ const state = statePartArg.getState();
475
+ const otherSecrets = state.secrets.filter(
476
+ (s) => !(s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
477
+ );
478
+ return { ...state, secrets: [...otherSecrets, ...listResp.secrets] };
479
+ } catch (err) {
480
+ console.error('Failed to update secret:', err);
481
+ return statePartArg.getState();
482
+ }
483
+ });
484
+
485
+ export const deleteSecretAction = dataStatePart.createAction<{
486
+ connectionId: string;
487
+ scope: 'project' | 'group';
488
+ scopeId: string;
489
+ key: string;
490
+ }>(async (statePartArg, dataArg) => {
491
+ const context = getActionContext();
492
+ try {
493
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
494
+ interfaces.requests.IReq_DeleteSecret
495
+ >('/typedrequest', 'deleteSecret');
496
+ await typedRequest.fire({
497
+ identity: context.identity!,
498
+ ...dataArg,
499
+ });
500
+ const state = statePartArg.getState();
501
+ return {
502
+ ...state,
503
+ secrets: state.secrets.filter(
504
+ (s) => !(s.key === dataArg.key && s.scopeId === dataArg.scopeId && s.scope === dataArg.scope),
505
+ ),
506
+ };
507
+ } catch (err) {
508
+ console.error('Failed to delete secret:', err);
509
+ return statePartArg.getState();
510
+ }
511
+ });
512
+
513
+ // ============================================================================
514
+ // Pipelines Actions
515
+ // ============================================================================
516
+
517
+ export const fetchPipelinesAction = dataStatePart.createAction<{
518
+ connectionId: string;
519
+ projectId?: string;
520
+ viewMode?: 'current' | 'project' | 'group' | 'error';
521
+ groupId?: string;
522
+ status?: string;
523
+ sortBy?: 'created' | 'duration' | 'status';
524
+ timeRange?: '1h' | '6h' | '1d' | '3d' | '7d' | '30d';
525
+ }>(async (statePartArg, dataArg) => {
526
+ const context = getActionContext();
527
+ try {
528
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
529
+ interfaces.requests.IReq_GetPipelines
530
+ >('/typedrequest', 'getPipelines');
531
+ const response = await typedRequest.fire({
532
+ identity: context.identity!,
533
+ connectionId: dataArg.connectionId,
534
+ projectId: dataArg.projectId,
535
+ viewMode: dataArg.viewMode,
536
+ groupId: dataArg.groupId,
537
+ status: dataArg.status,
538
+ sortBy: dataArg.sortBy,
539
+ timeRange: dataArg.timeRange,
540
+ });
541
+ return { ...statePartArg.getState(), pipelines: response.pipelines };
542
+ } catch (err) {
543
+ console.error('Failed to fetch pipelines:', err);
544
+ return statePartArg.getState();
545
+ }
546
+ });
547
+
548
+ export const fetchPipelineJobsAction = dataStatePart.createAction<{
549
+ connectionId: string;
550
+ projectId: string;
551
+ pipelineId: string;
552
+ }>(async (statePartArg, dataArg) => {
553
+ const context = getActionContext();
554
+ try {
555
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
556
+ interfaces.requests.IReq_GetPipelineJobs
557
+ >('/typedrequest', 'getPipelineJobs');
558
+ const response = await typedRequest.fire({
559
+ identity: context.identity!,
560
+ connectionId: dataArg.connectionId,
561
+ projectId: dataArg.projectId,
562
+ pipelineId: dataArg.pipelineId,
563
+ });
564
+ return { ...statePartArg.getState(), pipelineJobs: response.jobs };
565
+ } catch (err) {
566
+ console.error('Failed to fetch pipeline jobs:', err);
567
+ return statePartArg.getState();
568
+ }
569
+ });
570
+
571
+ export const retryPipelineAction = dataStatePart.createAction<{
572
+ connectionId: string;
573
+ projectId: string;
574
+ pipelineId: string;
575
+ }>(async (statePartArg, dataArg) => {
576
+ const context = getActionContext();
577
+ try {
578
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
579
+ interfaces.requests.IReq_RetryPipeline
580
+ >('/typedrequest', 'retryPipeline');
581
+ await typedRequest.fire({
582
+ identity: context.identity!,
583
+ ...dataArg,
584
+ });
585
+ // Re-fetch pipelines
586
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
587
+ interfaces.requests.IReq_GetPipelines
588
+ >('/typedrequest', 'getPipelines');
589
+ const listResp = await listReq.fire({
590
+ identity: context.identity!,
591
+ connectionId: dataArg.connectionId,
592
+ projectId: dataArg.projectId,
593
+ });
594
+ return { ...statePartArg.getState(), pipelines: listResp.pipelines };
595
+ } catch (err) {
596
+ console.error('Failed to retry pipeline:', err);
597
+ return statePartArg.getState();
598
+ }
599
+ });
600
+
601
+ export const cancelPipelineAction = dataStatePart.createAction<{
602
+ connectionId: string;
603
+ projectId: string;
604
+ pipelineId: string;
605
+ }>(async (statePartArg, dataArg) => {
606
+ const context = getActionContext();
607
+ try {
608
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
609
+ interfaces.requests.IReq_CancelPipeline
610
+ >('/typedrequest', 'cancelPipeline');
611
+ await typedRequest.fire({
612
+ identity: context.identity!,
613
+ ...dataArg,
614
+ });
615
+ // Re-fetch pipelines
616
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
617
+ interfaces.requests.IReq_GetPipelines
618
+ >('/typedrequest', 'getPipelines');
619
+ const listResp = await listReq.fire({
620
+ identity: context.identity!,
621
+ connectionId: dataArg.connectionId,
622
+ projectId: dataArg.projectId,
623
+ });
624
+ return { ...statePartArg.getState(), pipelines: listResp.pipelines };
625
+ } catch (err) {
626
+ console.error('Failed to cancel pipeline:', err);
627
+ return statePartArg.getState();
628
+ }
629
+ });
630
+
631
+ // ============================================================================
632
+ // Logs Actions
633
+ // ============================================================================
634
+
635
+ export const fetchJobLogAction = dataStatePart.createAction<{
636
+ connectionId: string;
637
+ projectId: string;
638
+ jobId: string;
639
+ }>(async (statePartArg, dataArg) => {
640
+ const context = getActionContext();
641
+ try {
642
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
643
+ interfaces.requests.IReq_GetJobLog
644
+ >('/typedrequest', 'getJobLog');
645
+ const response = await typedRequest.fire({
646
+ identity: context.identity!,
647
+ ...dataArg,
648
+ });
649
+ return { ...statePartArg.getState(), currentJobLog: response.log };
650
+ } catch (err) {
651
+ console.error('Failed to fetch job log:', err);
652
+ return statePartArg.getState();
653
+ }
654
+ });
655
+
656
+ // ============================================================================
657
+ // Action Log Actions
658
+ // ============================================================================
659
+
660
+ export const fetchActionLogAction = actionLogStatePart.createAction<{
661
+ limit?: number;
662
+ offset?: number;
663
+ entityType?: interfaces.data.TActionEntity;
664
+ } | null>(async (statePartArg, dataArg) => {
665
+ const context = getActionContext();
666
+ try {
667
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
668
+ interfaces.requests.IReq_GetActionLog
669
+ >('/typedrequest', 'getActionLog');
670
+ const response = await typedRequest.fire({
671
+ identity: context.identity!,
672
+ limit: dataArg?.limit,
673
+ offset: dataArg?.offset,
674
+ entityType: dataArg?.entityType,
675
+ });
676
+ return { entries: response.entries, total: response.total };
677
+ } catch (err) {
678
+ console.error('Failed to fetch action log:', err);
679
+ return statePartArg.getState();
680
+ }
681
+ });
682
+
683
+ // ============================================================================
684
+ // UI Actions
685
+ // ============================================================================
686
+
687
+ export const setActiveViewAction = uiStatePart.createAction<{
688
+ view: string;
689
+ navigationContext?: INavigationContext;
690
+ }>(
691
+ async (statePartArg, dataArg) => {
692
+ return {
693
+ ...statePartArg.getState(),
694
+ activeView: dataArg.view,
695
+ navigationContext: dataArg.navigationContext,
696
+ };
697
+ },
698
+ );
699
+
700
+ export const clearNavigationContextAction = uiStatePart.createAction(
701
+ async (statePartArg) => {
702
+ return { ...statePartArg.getState(), navigationContext: undefined };
703
+ },
704
+ );
705
+
706
+ export const toggleAutoRefreshAction = uiStatePart.createAction(async (statePartArg) => {
707
+ const state = statePartArg.getState();
708
+ return { ...state, autoRefresh: !state.autoRefresh };
709
+ });
710
+
711
+ export const setRefreshIntervalAction = uiStatePart.createAction<{ interval: number }>(
712
+ async (statePartArg, dataArg) => {
713
+ return { ...statePartArg.getState(), refreshInterval: dataArg.interval };
714
+ },
715
+ );
716
+
717
+ // ============================================================================
718
+ // Managed Secrets State
719
+ // ============================================================================
720
+
721
+ export interface IManagedSecretsState {
722
+ managedSecrets: interfaces.data.IManagedSecret[];
723
+ }
724
+
725
+ export const managedSecretsStatePart = await appState.getStatePart<IManagedSecretsState>(
726
+ 'managedSecrets',
727
+ { managedSecrets: [] },
728
+ 'soft',
729
+ );
730
+
731
+ export const fetchManagedSecretsAction = managedSecretsStatePart.createAction(
732
+ async (statePartArg) => {
733
+ const context = getActionContext();
734
+ try {
735
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
736
+ interfaces.requests.IReq_GetManagedSecrets
737
+ >('/typedrequest', 'getManagedSecrets');
738
+ const response = await typedRequest.fire({ identity: context.identity! });
739
+ return { managedSecrets: response.managedSecrets };
740
+ } catch (err) {
741
+ console.error('Failed to fetch managed secrets:', err);
742
+ return statePartArg.getState();
743
+ }
744
+ },
745
+ );
746
+
747
+ export const createManagedSecretAction = managedSecretsStatePart.createAction<{
748
+ key: string;
749
+ value: string;
750
+ description?: string;
751
+ targets: interfaces.data.IManagedSecretTarget[];
752
+ }>(async (statePartArg, dataArg) => {
753
+ const context = getActionContext();
754
+ try {
755
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
756
+ interfaces.requests.IReq_CreateManagedSecret
757
+ >('/typedrequest', 'createManagedSecret');
758
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
759
+ // Re-fetch
760
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
761
+ interfaces.requests.IReq_GetManagedSecrets
762
+ >('/typedrequest', 'getManagedSecrets');
763
+ const listResp = await listReq.fire({ identity: context.identity! });
764
+ return { managedSecrets: listResp.managedSecrets };
765
+ } catch (err) {
766
+ console.error('Failed to create managed secret:', err);
767
+ return statePartArg.getState();
768
+ }
769
+ });
770
+
771
+ export const updateManagedSecretAction = managedSecretsStatePart.createAction<{
772
+ managedSecretId: string;
773
+ value?: string;
774
+ description?: string;
775
+ targets?: interfaces.data.IManagedSecretTarget[];
776
+ }>(async (statePartArg, dataArg) => {
777
+ const context = getActionContext();
778
+ try {
779
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
780
+ interfaces.requests.IReq_UpdateManagedSecret
781
+ >('/typedrequest', 'updateManagedSecret');
782
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
783
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
784
+ interfaces.requests.IReq_GetManagedSecrets
785
+ >('/typedrequest', 'getManagedSecrets');
786
+ const listResp = await listReq.fire({ identity: context.identity! });
787
+ return { managedSecrets: listResp.managedSecrets };
788
+ } catch (err) {
789
+ console.error('Failed to update managed secret:', err);
790
+ return statePartArg.getState();
791
+ }
792
+ });
793
+
794
+ export const deleteManagedSecretAction = managedSecretsStatePart.createAction<{
795
+ managedSecretId: string;
796
+ }>(async (statePartArg, dataArg) => {
797
+ const context = getActionContext();
798
+ try {
799
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
800
+ interfaces.requests.IReq_DeleteManagedSecret
801
+ >('/typedrequest', 'deleteManagedSecret');
802
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
803
+ const state = statePartArg.getState();
804
+ return {
805
+ managedSecrets: state.managedSecrets.filter((s) => s.id !== dataArg.managedSecretId),
806
+ };
807
+ } catch (err) {
808
+ console.error('Failed to delete managed secret:', err);
809
+ return statePartArg.getState();
810
+ }
811
+ });
812
+
813
+ export const pushManagedSecretAction = managedSecretsStatePart.createAction<{
814
+ managedSecretId: string;
815
+ }>(async (statePartArg, dataArg) => {
816
+ const context = getActionContext();
817
+ try {
818
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
819
+ interfaces.requests.IReq_PushManagedSecret
820
+ >('/typedrequest', 'pushManagedSecret');
821
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
822
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
823
+ interfaces.requests.IReq_GetManagedSecrets
824
+ >('/typedrequest', 'getManagedSecrets');
825
+ const listResp = await listReq.fire({ identity: context.identity! });
826
+ return { managedSecrets: listResp.managedSecrets };
827
+ } catch (err) {
828
+ console.error('Failed to push managed secret:', err);
829
+ return statePartArg.getState();
830
+ }
831
+ });
832
+
833
+ export const pushAllManagedSecretsAction = managedSecretsStatePart.createAction(
834
+ async (statePartArg) => {
835
+ const context = getActionContext();
836
+ try {
837
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
838
+ interfaces.requests.IReq_PushAllManagedSecrets
839
+ >('/typedrequest', 'pushAllManagedSecrets');
840
+ await typedRequest.fire({ identity: context.identity! });
841
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
842
+ interfaces.requests.IReq_GetManagedSecrets
843
+ >('/typedrequest', 'getManagedSecrets');
844
+ const listResp = await listReq.fire({ identity: context.identity! });
845
+ return { managedSecrets: listResp.managedSecrets };
846
+ } catch (err) {
847
+ console.error('Failed to push all managed secrets:', err);
848
+ return statePartArg.getState();
849
+ }
850
+ },
851
+ );
852
+
853
+ // ============================================================================
854
+ // Sync State
855
+ // ============================================================================
856
+
857
+ export interface ISyncState {
858
+ configs: interfaces.data.ISyncConfig[];
859
+ repoStatuses: interfaces.data.ISyncRepoStatus[];
860
+ }
861
+
862
+ export const syncStatePart = await appState.getStatePart<ISyncState>(
863
+ 'sync',
864
+ { configs: [], repoStatuses: [] },
865
+ 'soft',
866
+ );
867
+
868
+ export const fetchSyncConfigsAction = syncStatePart.createAction(async (statePartArg) => {
869
+ const context = getActionContext();
870
+ try {
871
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
872
+ interfaces.requests.IReq_GetSyncConfigs
873
+ >('/typedrequest', 'getSyncConfigs');
874
+ const response = await typedRequest.fire({ identity: context.identity! });
875
+ return { ...statePartArg.getState(), configs: response.configs };
876
+ } catch (err) {
877
+ console.error('Failed to fetch sync configs:', err);
878
+ return statePartArg.getState();
879
+ }
880
+ });
881
+
882
+ export const createSyncConfigAction = syncStatePart.createAction<{
883
+ name: string;
884
+ sourceConnectionId: string;
885
+ targetConnectionId: string;
886
+ targetGroupOffset?: string;
887
+ intervalMinutes?: number;
888
+ enforceDelete?: boolean;
889
+ enforceGroupDelete?: boolean;
890
+ addMirrorHint?: boolean;
891
+ useGroupAvatarsForProjects?: boolean;
892
+ }>(async (statePartArg, dataArg) => {
893
+ const context = getActionContext();
894
+ try {
895
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
896
+ interfaces.requests.IReq_CreateSyncConfig
897
+ >('/typedrequest', 'createSyncConfig');
898
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
899
+ // Re-fetch
900
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
901
+ interfaces.requests.IReq_GetSyncConfigs
902
+ >('/typedrequest', 'getSyncConfigs');
903
+ const listResp = await listReq.fire({ identity: context.identity! });
904
+ return { ...statePartArg.getState(), configs: listResp.configs };
905
+ } catch (err) {
906
+ console.error('Failed to create sync config:', err);
907
+ return statePartArg.getState();
908
+ }
909
+ });
910
+
911
+ export const updateSyncConfigAction = syncStatePart.createAction<{
912
+ syncConfigId: string;
913
+ name?: string;
914
+ targetGroupOffset?: string;
915
+ intervalMinutes?: number;
916
+ enforceDelete?: boolean;
917
+ enforceGroupDelete?: boolean;
918
+ addMirrorHint?: boolean;
919
+ useGroupAvatarsForProjects?: boolean;
920
+ }>(async (statePartArg, dataArg) => {
921
+ const context = getActionContext();
922
+ try {
923
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
924
+ interfaces.requests.IReq_UpdateSyncConfig
925
+ >('/typedrequest', 'updateSyncConfig');
926
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
927
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
928
+ interfaces.requests.IReq_GetSyncConfigs
929
+ >('/typedrequest', 'getSyncConfigs');
930
+ const listResp = await listReq.fire({ identity: context.identity! });
931
+ return { ...statePartArg.getState(), configs: listResp.configs };
932
+ } catch (err) {
933
+ console.error('Failed to update sync config:', err);
934
+ return statePartArg.getState();
935
+ }
936
+ });
937
+
938
+ export const deleteSyncConfigAction = syncStatePart.createAction<{
939
+ syncConfigId: string;
940
+ }>(async (statePartArg, dataArg) => {
941
+ const context = getActionContext();
942
+ try {
943
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
944
+ interfaces.requests.IReq_DeleteSyncConfig
945
+ >('/typedrequest', 'deleteSyncConfig');
946
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
947
+ const state = statePartArg.getState();
948
+ return { ...state, configs: state.configs.filter((c) => c.id !== dataArg.syncConfigId) };
949
+ } catch (err) {
950
+ console.error('Failed to delete sync config:', err);
951
+ return statePartArg.getState();
952
+ }
953
+ });
954
+
955
+ export const pauseSyncConfigAction = syncStatePart.createAction<{
956
+ syncConfigId: string;
957
+ paused: boolean;
958
+ }>(async (statePartArg, dataArg) => {
959
+ const context = getActionContext();
960
+ try {
961
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
962
+ interfaces.requests.IReq_PauseSyncConfig
963
+ >('/typedrequest', 'pauseSyncConfig');
964
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
965
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
966
+ interfaces.requests.IReq_GetSyncConfigs
967
+ >('/typedrequest', 'getSyncConfigs');
968
+ const listResp = await listReq.fire({ identity: context.identity! });
969
+ return { ...statePartArg.getState(), configs: listResp.configs };
970
+ } catch (err) {
971
+ console.error('Failed to pause/resume sync config:', err);
972
+ return statePartArg.getState();
973
+ }
974
+ });
975
+
976
+ export const triggerSyncAction = syncStatePart.createAction<{
977
+ syncConfigId: string;
978
+ }>(async (statePartArg, dataArg) => {
979
+ const context = getActionContext();
980
+ try {
981
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
982
+ interfaces.requests.IReq_TriggerSync
983
+ >('/typedrequest', 'triggerSync');
984
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
985
+ return statePartArg.getState();
986
+ } catch (err) {
987
+ console.error('Failed to trigger sync:', err);
988
+ return statePartArg.getState();
989
+ }
990
+ });
991
+
992
+ export const fetchSyncRepoStatusesAction = syncStatePart.createAction<{
993
+ syncConfigId: string;
994
+ }>(async (statePartArg, dataArg) => {
995
+ const context = getActionContext();
996
+ try {
997
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
998
+ interfaces.requests.IReq_GetSyncRepoStatuses
999
+ >('/typedrequest', 'getSyncRepoStatuses');
1000
+ const response = await typedRequest.fire({ identity: context.identity!, ...dataArg });
1001
+ return { ...statePartArg.getState(), repoStatuses: response.statuses };
1002
+ } catch (err) {
1003
+ console.error('Failed to fetch sync repo statuses:', err);
1004
+ return statePartArg.getState();
1005
+ }
1006
+ });
1007
+
1008
+ // ============================================================================
1009
+ // Sync Log — TypedSocket client for server-push entries
1010
+ // ============================================================================
1011
+
1012
+ export async function fetchSyncLogs(limit = 200): Promise<interfaces.data.ISyncLogEntry[]> {
1013
+ const identity = loginStatePart.getState().identity;
1014
+ if (!identity) throw new Error('Not logged in');
1015
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1016
+ interfaces.requests.IReq_GetSyncLogs
1017
+ >('/typedrequest', 'getSyncLogs');
1018
+ const response = await typedRequest.fire({ identity, limit });
1019
+ return response.logs;
1020
+ }
1021
+
1022
+ let syncLogSocketInitialized = false;
1023
+
1024
+ /**
1025
+ * Create a TypedSocket client that handles server-push sync log entries.
1026
+ * Dispatches 'gitops-sync-log-entry' custom events on document.
1027
+ * Call once after login.
1028
+ */
1029
+ export async function initSyncLogSocket(): Promise<void> {
1030
+ if (syncLogSocketInitialized) return;
1031
+ syncLogSocketInitialized = true;
1032
+
1033
+ try {
1034
+ const typedrouter = new plugins.domtools.plugins.typedrequest.TypedRouter();
1035
+
1036
+ typedrouter.addTypedHandler(
1037
+ new plugins.domtools.plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushSyncLog>(
1038
+ 'pushSyncLog',
1039
+ async (dataArg) => {
1040
+ document.dispatchEvent(
1041
+ new CustomEvent('gitops-sync-log-entry', { detail: dataArg.entry }),
1042
+ );
1043
+ return {};
1044
+ },
1045
+ ),
1046
+ );
1047
+
1048
+ const typedsocketClient = await plugins.typedsocket.TypedSocket.createClient(
1049
+ typedrouter,
1050
+ plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl(),
1051
+ { autoReconnect: true },
1052
+ );
1053
+ await typedsocketClient.setTag('syncLogClient', {});
1054
+ } catch (err) {
1055
+ console.error('Failed to init sync log TypedSocket client:', err);
1056
+ syncLogSocketInitialized = false;
1057
+ }
1058
+ }
1059
+
1060
+ // ============================================================================
1061
+ // Preview Helper
1062
+ // ============================================================================
1063
+
1064
+ export async function previewSync(syncConfigId: string): Promise<{
1065
+ mappings: Array<{ sourceFullPath: string; targetFullPath: string }>;
1066
+ deletions: string[];
1067
+ groupDeletions: string[];
1068
+ }> {
1069
+ const identity = loginStatePart.getState().identity;
1070
+ if (!identity) throw new Error('Not logged in');
1071
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1072
+ interfaces.requests.IReq_PreviewSync
1073
+ >('/typedrequest', 'previewSync');
1074
+ const response = await typedRequest.fire({ identity, syncConfigId });
1075
+ return { mappings: response.mappings, deletions: response.deletions, groupDeletions: response.groupDeletions };
1076
+ }
1077
+
1078
+ // ============================================================================
1079
+ // Jobs State
1080
+ // ============================================================================
1081
+
1082
+ export interface IJobsState {
1083
+ jobs: interfaces.data.IJobConfig[];
1084
+ }
1085
+
1086
+ export const jobsStatePart = await appState.getStatePart<IJobsState>(
1087
+ 'jobs',
1088
+ { jobs: [] },
1089
+ 'soft',
1090
+ );
1091
+
1092
+ export const fetchJobsAction = jobsStatePart.createAction(async (statePartArg) => {
1093
+ const context = getActionContext();
1094
+ try {
1095
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1096
+ interfaces.requests.IReq_GetJobs
1097
+ >('/typedrequest', 'getJobs');
1098
+ const response = await typedRequest.fire({ identity: context.identity! });
1099
+ return { jobs: response.jobs };
1100
+ } catch (err) {
1101
+ console.error('Failed to fetch jobs:', err);
1102
+ return statePartArg.getState();
1103
+ }
1104
+ });
1105
+
1106
+ export const createJobAction = jobsStatePart.createAction<{
1107
+ name: string;
1108
+ jobType: interfaces.data.TJobType;
1109
+ intervalMinutes: number;
1110
+ autoBookstackDocsConfig?: interfaces.data.IAutoBookstackDocsConfig;
1111
+ }>(async (statePartArg, dataArg) => {
1112
+ const context = getActionContext();
1113
+ try {
1114
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1115
+ interfaces.requests.IReq_CreateJob
1116
+ >('/typedrequest', 'createJob');
1117
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
1118
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
1119
+ interfaces.requests.IReq_GetJobs
1120
+ >('/typedrequest', 'getJobs');
1121
+ const listResp = await listReq.fire({ identity: context.identity! });
1122
+ return { jobs: listResp.jobs };
1123
+ } catch (err) {
1124
+ console.error('Failed to create job:', err);
1125
+ return statePartArg.getState();
1126
+ }
1127
+ });
1128
+
1129
+ export const updateJobAction = jobsStatePart.createAction<{
1130
+ jobId: string;
1131
+ name?: string;
1132
+ intervalMinutes?: number;
1133
+ autoBookstackDocsConfig?: interfaces.data.IAutoBookstackDocsConfig;
1134
+ }>(async (statePartArg, dataArg) => {
1135
+ const context = getActionContext();
1136
+ try {
1137
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1138
+ interfaces.requests.IReq_UpdateJob
1139
+ >('/typedrequest', 'updateJob');
1140
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
1141
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
1142
+ interfaces.requests.IReq_GetJobs
1143
+ >('/typedrequest', 'getJobs');
1144
+ const listResp = await listReq.fire({ identity: context.identity! });
1145
+ return { jobs: listResp.jobs };
1146
+ } catch (err) {
1147
+ console.error('Failed to update job:', err);
1148
+ return statePartArg.getState();
1149
+ }
1150
+ });
1151
+
1152
+ export const deleteJobAction = jobsStatePart.createAction<{ jobId: string }>(
1153
+ async (statePartArg, dataArg) => {
1154
+ const context = getActionContext();
1155
+ try {
1156
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1157
+ interfaces.requests.IReq_DeleteJob
1158
+ >('/typedrequest', 'deleteJob');
1159
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
1160
+ return {
1161
+ jobs: statePartArg.getState().jobs.filter((j) => j.id !== dataArg.jobId),
1162
+ };
1163
+ } catch (err) {
1164
+ console.error('Failed to delete job:', err);
1165
+ return statePartArg.getState();
1166
+ }
1167
+ },
1168
+ );
1169
+
1170
+ export const pauseJobAction = jobsStatePart.createAction<{
1171
+ jobId: string;
1172
+ paused: boolean;
1173
+ }>(async (statePartArg, dataArg) => {
1174
+ const context = getActionContext();
1175
+ try {
1176
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1177
+ interfaces.requests.IReq_PauseJob
1178
+ >('/typedrequest', 'pauseJob');
1179
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
1180
+ const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
1181
+ interfaces.requests.IReq_GetJobs
1182
+ >('/typedrequest', 'getJobs');
1183
+ const listResp = await listReq.fire({ identity: context.identity! });
1184
+ return { jobs: listResp.jobs };
1185
+ } catch (err) {
1186
+ console.error('Failed to pause/resume job:', err);
1187
+ return statePartArg.getState();
1188
+ }
1189
+ });
1190
+
1191
+ export const triggerJobAction = jobsStatePart.createAction<{ jobId: string }>(
1192
+ async (statePartArg, dataArg) => {
1193
+ const context = getActionContext();
1194
+ try {
1195
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1196
+ interfaces.requests.IReq_TriggerJob
1197
+ >('/typedrequest', 'triggerJob');
1198
+ await typedRequest.fire({ identity: context.identity!, ...dataArg });
1199
+ } catch (err) {
1200
+ console.error('Failed to trigger job:', err);
1201
+ }
1202
+ return statePartArg.getState();
1203
+ },
1204
+ );
1205
+
1206
+ // ============================================================================
1207
+ // Job Log Helpers (pull + push, mirrors Sync Log pattern)
1208
+ // ============================================================================
1209
+
1210
+ export async function fetchJobLogs(limit = 200): Promise<interfaces.data.IJobLogEntry[]> {
1211
+ const identity = loginStatePart.getState().identity;
1212
+ if (!identity) return [];
1213
+ const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
1214
+ interfaces.requests.IReq_GetJobLogs
1215
+ >('/typedrequest', 'getJobLogs');
1216
+ const response = await typedRequest.fire({ identity, limit });
1217
+ return response.logs;
1218
+ }
1219
+
1220
+ let jobLogSocketInitialized = false;
1221
+
1222
+ export async function initJobLogSocket(): Promise<void> {
1223
+ if (jobLogSocketInitialized) return;
1224
+ jobLogSocketInitialized = true;
1225
+
1226
+ try {
1227
+ const typedrouter = new plugins.domtools.plugins.typedrequest.TypedRouter();
1228
+
1229
+ typedrouter.addTypedHandler(
1230
+ new plugins.domtools.plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushJobLog>(
1231
+ 'pushJobLog',
1232
+ async (dataArg) => {
1233
+ document.dispatchEvent(
1234
+ new CustomEvent('gitops-job-log-entry', { detail: dataArg.entry }),
1235
+ );
1236
+ return {};
1237
+ },
1238
+ ),
1239
+ );
1240
+
1241
+ const typedsocketClient = await plugins.typedsocket.TypedSocket.createClient(
1242
+ typedrouter,
1243
+ plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl(),
1244
+ { autoReconnect: true },
1245
+ );
1246
+ await typedsocketClient.setTag('jobLogClient', {});
1247
+ } catch (err) {
1248
+ console.error('Failed to init job log TypedSocket client:', err);
1249
+ jobLogSocketInitialized = false;
1250
+ }
1251
+ }