@acorex-platform/module-help-desk-client 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-module-help-desk-client-acorex-platform-module-help-desk-client-OtDtf3iY.mjs +783 -0
- package/fesm2022/acorex-platform-module-help-desk-client-acorex-platform-module-help-desk-client-OtDtf3iY.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client-capture-screen.component-AyM-9U5W.mjs +28 -0
- package/fesm2022/acorex-platform-module-help-desk-client-capture-screen.component-AyM-9U5W.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client-contracts.mjs +1375 -0
- package/fesm2022/acorex-platform-module-help-desk-client-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client-download-log-file.command-eMaHHzLd.mjs +30 -0
- package/fesm2022/acorex-platform-module-help-desk-client-download-log-file.command-eMaHHzLd.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client-report-new-issue.component-C-vY_x_C.mjs +246 -0
- package/fesm2022/acorex-platform-module-help-desk-client-report-new-issue.component-C-vY_x_C.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client-show-report-issue.command-q2fqdnAS.mjs +23 -0
- package/fesm2022/acorex-platform-module-help-desk-client-show-report-issue.command-q2fqdnAS.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-help-desk-client.mjs +2 -0
- package/fesm2022/acorex-platform-module-help-desk-client.mjs.map +1 -0
- package/package.json +29 -0
- package/types/acorex-platform-module-help-desk-client-contracts.d.ts +149 -0
- package/types/acorex-platform-module-help-desk-client.d.ts +58 -0
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { computed, Injectable, inject, ApplicationRef, ViewContainerRef, NgModule } from '@angular/core';
|
|
3
|
+
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
4
|
+
import { AXPStatusProvider } from '@acorex-platform/framework-shared/core';
|
|
5
|
+
import { RootConfig, AXPCollaborationPermissionKeys, AXPHelpDeskMenuKeys } from '@acorex-platform/module-help-desk-client/contracts';
|
|
6
|
+
import * as i1 from '@acorex-platform/framework-client/core';
|
|
7
|
+
import { AXPDataGenerator, AXPEntityBroadcastService, AXPComponentSlotModule, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER } from '@acorex-platform/framework-client/core';
|
|
8
|
+
import { provideCommandSetups } from '@acorex-platform/framework-client/runtime';
|
|
9
|
+
import { AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
|
|
10
|
+
import { AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
|
|
11
|
+
import { AXPCommonPermissionGroupKeys, AXPCommonMenuKeys } from '@acorex-platform/module-common-client/contracts';
|
|
12
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
13
|
+
import { AXPopupService } from '@acorex/components/popup';
|
|
14
|
+
import { AXTranslationService } from '@acorex/core/translation';
|
|
15
|
+
import { AXToastService } from '@acorex/components/toast';
|
|
16
|
+
import html2canvas from 'html2canvas';
|
|
17
|
+
import { Subject, take } from 'rxjs';
|
|
18
|
+
|
|
19
|
+
const AXMLogCaptureService = signalStore({ providedIn: 'root' }, withState(() => {
|
|
20
|
+
const state = {
|
|
21
|
+
logs: [],
|
|
22
|
+
canCapture: false,
|
|
23
|
+
};
|
|
24
|
+
return state;
|
|
25
|
+
}), withComputed((store) => ({
|
|
26
|
+
canCaptureLog: computed(() => store.canCapture()),
|
|
27
|
+
consoleLogs: computed(() => store.logs()),
|
|
28
|
+
})), withMethods((store) => {
|
|
29
|
+
const startCapturingLog = () => {
|
|
30
|
+
patchState(store, { canCapture: true });
|
|
31
|
+
};
|
|
32
|
+
const finishCapturingLog = () => {
|
|
33
|
+
patchState(store, { canCapture: false });
|
|
34
|
+
};
|
|
35
|
+
const addConsoleLog = (message) => {
|
|
36
|
+
patchState(store, {
|
|
37
|
+
logs: [...store.logs(), { type: 'log', message, timeStamp: new Date().toISOString() }],
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const addConsoleError = (message) => {
|
|
41
|
+
patchState(store, {
|
|
42
|
+
logs: [...store.logs(), { type: 'error', message, timeStamp: new Date().toISOString() }],
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const addConsoleWarning = (message) => {
|
|
46
|
+
patchState(store, {
|
|
47
|
+
logs: [...store.logs(), { type: 'warning', message, timeStamp: new Date().toISOString() }],
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
startCapturingLog,
|
|
52
|
+
finishCapturingLog,
|
|
53
|
+
addConsoleLog,
|
|
54
|
+
addConsoleError,
|
|
55
|
+
addConsoleWarning,
|
|
56
|
+
};
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
//#region ---- Imports ----
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region ---- Reported Issues Status Provider ----
|
|
62
|
+
const status = (name, title, color, options = {}) => ({
|
|
63
|
+
name,
|
|
64
|
+
title,
|
|
65
|
+
color,
|
|
66
|
+
...options,
|
|
67
|
+
});
|
|
68
|
+
const workflowCommand = (action) => `${RootConfig.module.name}.${RootConfig.entities.reportedIssues.name}:${action}`;
|
|
69
|
+
/**
|
|
70
|
+
* Provides lifecycle status definitions for reported issues.
|
|
71
|
+
*/
|
|
72
|
+
class AXMReportedIssuesStatusProvider extends AXPStatusProvider {
|
|
73
|
+
constructor() {
|
|
74
|
+
super(...arguments);
|
|
75
|
+
this.key = 'help-desk.status.reported-issues';
|
|
76
|
+
this.statuses = [
|
|
77
|
+
status('new', '@help-desk:reported-issues.states.new', 'info', { isInitial: true, order: 1, generateView: true }),
|
|
78
|
+
status('in-progress', '@help-desk:reported-issues.states.in-progress', 'primary', { order: 2, generateView: true }),
|
|
79
|
+
status('pending', '@help-desk:reported-issues.states.pending', 'warning', { order: 3, generateView: true }),
|
|
80
|
+
status('resolved', '@help-desk:reported-issues.states.resolved', 'success', { order: 4, generateView: true }),
|
|
81
|
+
status('closed', '@help-desk:reported-issues.states.closed', 'neutral', { isFinal: true, order: 5, generateView: true }),
|
|
82
|
+
];
|
|
83
|
+
this.transitions = [
|
|
84
|
+
{ from: 'new', to: 'in-progress' },
|
|
85
|
+
{ from: 'in-progress', to: 'pending' },
|
|
86
|
+
{ from: 'in-progress', to: 'resolved' },
|
|
87
|
+
{ from: 'pending', to: 'in-progress' },
|
|
88
|
+
{ from: 'pending', to: 'resolved' },
|
|
89
|
+
{ from: 'resolved', to: 'closed' },
|
|
90
|
+
];
|
|
91
|
+
this.defaultStatus = 'new';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
|
|
96
|
+
//#region ---- Imports ----
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region ---- Manifest Definition ----
|
|
99
|
+
/**
|
|
100
|
+
* Help Desk Module Manifest.
|
|
101
|
+
* Defines module metadata, features, and provider references.
|
|
102
|
+
*/
|
|
103
|
+
const HelpDeskManifest = {
|
|
104
|
+
name: RootConfig.module.name,
|
|
105
|
+
version: '1.0.0',
|
|
106
|
+
title: RootConfig.module.title,
|
|
107
|
+
icon: RootConfig.module.icon,
|
|
108
|
+
i18n: RootConfig.config.i18n,
|
|
109
|
+
type: 'domain',
|
|
110
|
+
domain: 'operations',
|
|
111
|
+
// Module dependencies (optional)
|
|
112
|
+
};
|
|
113
|
+
//#endregion
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region ----- Permission Provider -----
|
|
117
|
+
/**
|
|
118
|
+
* Registers help desk capabilities into the shared Collaboration group.
|
|
119
|
+
*/
|
|
120
|
+
class AXMPermissionDefinitionProvider {
|
|
121
|
+
async define(context) {
|
|
122
|
+
const keys = AXPCollaborationPermissionKeys;
|
|
123
|
+
const groups = AXPCommonPermissionGroupKeys;
|
|
124
|
+
const P = '@common:collaboration.permissions';
|
|
125
|
+
const G = '@common:permission-groups';
|
|
126
|
+
context.addGroup(groups.Collaboration.Root, `${G}.collaboration.title`, `${G}.collaboration.description`, { order: 80 });
|
|
127
|
+
context
|
|
128
|
+
.addGroup(groups.Collaboration.HelpDesk, `${G}.collaboration-help-desk.title`, `${G}.collaboration-help-desk.description`, { parent: groups.Collaboration.Root, order: 40 })
|
|
129
|
+
.addPermission(keys.MaintainHelpDesk, `${P}.maintain-help-desk.title`, `${P}.maintain-help-desk.description`)
|
|
130
|
+
.endPermission()
|
|
131
|
+
.endGroup();
|
|
132
|
+
}
|
|
133
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
134
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMPermissionDefinitionProvider }); }
|
|
135
|
+
}
|
|
136
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMPermissionDefinitionProvider, decorators: [{
|
|
137
|
+
type: Injectable
|
|
138
|
+
}] });
|
|
139
|
+
|
|
140
|
+
class AXMMenuProvider {
|
|
141
|
+
constructor() {
|
|
142
|
+
this.entityService = inject(AXPEntityService);
|
|
143
|
+
}
|
|
144
|
+
async provide(context) {
|
|
145
|
+
const module = RootConfig.module;
|
|
146
|
+
const keys = AXPCollaborationPermissionKeys;
|
|
147
|
+
//#region ---- Configuration > Help Desk (Issue Types) ----
|
|
148
|
+
const helpDeskConfigMenu = context.find(AXPCommonMenuKeys.HelpDeskConfig);
|
|
149
|
+
if (!helpDeskConfigMenu.exists) {
|
|
150
|
+
context.find(AXPCommonMenuKeys.Configuration).addItems([
|
|
151
|
+
{
|
|
152
|
+
name: AXPCommonMenuKeys.HelpDeskConfig,
|
|
153
|
+
priority: 8940,
|
|
154
|
+
text: '@general:menus.help-desk.title',
|
|
155
|
+
icon: module.icon,
|
|
156
|
+
type: 'menu',
|
|
157
|
+
children: [],
|
|
158
|
+
policy: {
|
|
159
|
+
features: [module.name],
|
|
160
|
+
permissions: [keys.MaintainHelpDesk],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
]);
|
|
164
|
+
}
|
|
165
|
+
context.find(AXPCommonMenuKeys.HelpDeskConfig).addItems([
|
|
166
|
+
{
|
|
167
|
+
name: AXPHelpDeskMenuKeys.IssueTypes,
|
|
168
|
+
text: '@help-desk:issue-types.menus.issue-types.title',
|
|
169
|
+
path: this.entityService.createPath(module.name, RootConfig.entities.issueType.name),
|
|
170
|
+
icon: RootConfig.entities.issueType.icon,
|
|
171
|
+
priority: 1,
|
|
172
|
+
policy: {
|
|
173
|
+
features: [module.name],
|
|
174
|
+
permissions: [keys.MaintainHelpDesk],
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
]);
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region ---- Administration > Reported Issues ----
|
|
180
|
+
context.find(AXPCommonMenuKeys.Administration).addItems([
|
|
181
|
+
{
|
|
182
|
+
name: `${AXPHelpDeskMenuKeys.ReportedIssues}:divider`,
|
|
183
|
+
text: '',
|
|
184
|
+
type: 'break',
|
|
185
|
+
priority: 996,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: AXPHelpDeskMenuKeys.ReportedIssues,
|
|
189
|
+
text: '@help-desk:reported-issues.menus.reported-issues.title',
|
|
190
|
+
path: this.entityService.createPath(module.name, RootConfig.entities.reportedIssues.name),
|
|
191
|
+
icon: RootConfig.entities.reportedIssues.icon,
|
|
192
|
+
priority: 997,
|
|
193
|
+
policy: {
|
|
194
|
+
features: [module.name],
|
|
195
|
+
permissions: [keys.MaintainHelpDesk],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
]);
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region ---- Help Menu Extensions (Requests & Issues, Report Issue) ----
|
|
201
|
+
context.find(AXPCommonMenuKeys.Help).addItems([
|
|
202
|
+
{
|
|
203
|
+
name: AXPHelpDeskMenuKeys.Divider1,
|
|
204
|
+
text: '',
|
|
205
|
+
type: 'break',
|
|
206
|
+
priority: 900004,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: AXPHelpDeskMenuKeys.MyReportedIssues,
|
|
210
|
+
text: '@help-desk:my-reported-issues.menus.my-reported-issues.title',
|
|
211
|
+
icon: RootConfig.entities.reportedIssues.icon,
|
|
212
|
+
path: this.entityService.createPath(module.name, RootConfig.entities.reportedIssues.name),
|
|
213
|
+
priority: 900005,
|
|
214
|
+
policy: {
|
|
215
|
+
features: [module.name],
|
|
216
|
+
permissions: [keys.MaintainHelpDesk],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
//#endregion
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
class AXMSettingProvider {
|
|
225
|
+
async provide(context) {
|
|
226
|
+
// context
|
|
227
|
+
// // Add Form Template Group
|
|
228
|
+
// .addGroup('form-template', 'Form Template', 'Settings related to form templates.', RootConfig.module.icon)
|
|
229
|
+
// // Start Interface Section
|
|
230
|
+
// .addSection('interface', 'UI Interface', 'Customize the user interface for forms.')
|
|
231
|
+
// .addSetting({
|
|
232
|
+
// key: 'history-panel',
|
|
233
|
+
// title: 'Show History Panel',
|
|
234
|
+
// scope: 'U',
|
|
235
|
+
// isInherited: true,
|
|
236
|
+
// defaultValue: false,
|
|
237
|
+
// widget: {
|
|
238
|
+
// type: AXPWidgetsCatalog.toggle,
|
|
239
|
+
// },
|
|
240
|
+
// description: 'Enable or disable the history panel for forms.',
|
|
241
|
+
// validationRules: [
|
|
242
|
+
// {
|
|
243
|
+
// rule: 'required',
|
|
244
|
+
// },
|
|
245
|
+
// ],
|
|
246
|
+
// })
|
|
247
|
+
// .endSection()
|
|
248
|
+
// .endGroup();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const AXMCaptureScreenService = signalStore({ providedIn: 'root' }, withState(() => {
|
|
253
|
+
const state = {
|
|
254
|
+
loading: false,
|
|
255
|
+
captureMode: 'screenshot',
|
|
256
|
+
screenshotBlob: '',
|
|
257
|
+
videoBlob: '',
|
|
258
|
+
muted: false,
|
|
259
|
+
isRecording: false,
|
|
260
|
+
timer: {
|
|
261
|
+
second: 0,
|
|
262
|
+
minute: 0,
|
|
263
|
+
},
|
|
264
|
+
onFinish: undefined,
|
|
265
|
+
};
|
|
266
|
+
return state;
|
|
267
|
+
}), withMethods((store) => {
|
|
268
|
+
let interval;
|
|
269
|
+
let videoStream;
|
|
270
|
+
let audioStream;
|
|
271
|
+
let mediaRecorder;
|
|
272
|
+
let recordedChunks = [];
|
|
273
|
+
let componentRef;
|
|
274
|
+
const toastService = inject(AXToastService);
|
|
275
|
+
const translationService = inject(AXTranslationService);
|
|
276
|
+
const application = inject(ApplicationRef);
|
|
277
|
+
const logCaptureService = inject(AXMLogCaptureService);
|
|
278
|
+
const stopRecorderSubject = new Subject();
|
|
279
|
+
const recordStream = async () => {
|
|
280
|
+
logCaptureService.startCapturingLog();
|
|
281
|
+
mediaRecorder = await new MediaRecorder(videoStream, {
|
|
282
|
+
mimeType: 'video/mp4;codecs=avc1,mp4a.40.2',
|
|
283
|
+
});
|
|
284
|
+
patchState(store, { isRecording: true });
|
|
285
|
+
mediaRecorder.start();
|
|
286
|
+
startTimer();
|
|
287
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
288
|
+
recordedChunks.push(e.data);
|
|
289
|
+
};
|
|
290
|
+
mediaRecorder.onstop = () => {
|
|
291
|
+
stopRecorder();
|
|
292
|
+
};
|
|
293
|
+
videoStream.getVideoTracks()[0].onended = () => {
|
|
294
|
+
stopRecorder();
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
const finishRecording = async (result) => {
|
|
298
|
+
// if (store.onFinish() && result) {
|
|
299
|
+
// store.onFinish()?.(result);
|
|
300
|
+
// }
|
|
301
|
+
logCaptureService.finishCapturingLog();
|
|
302
|
+
store.onFinish()?.(result ?? false);
|
|
303
|
+
resetState();
|
|
304
|
+
componentRef.destroy();
|
|
305
|
+
};
|
|
306
|
+
const stopRecorder = async () => {
|
|
307
|
+
await stopRecorderSubject.pipe(take(1)).subscribe(async () => {
|
|
308
|
+
try {
|
|
309
|
+
if (mediaRecorder && videoStream?.active) {
|
|
310
|
+
await mediaRecorder.stop();
|
|
311
|
+
if (audioStream) {
|
|
312
|
+
audioStream.getTracks().forEach((track) => track.stop());
|
|
313
|
+
}
|
|
314
|
+
videoStream.getVideoTracks().forEach((track) => track.stop());
|
|
315
|
+
clearInterval(interval);
|
|
316
|
+
patchState(store, { isRecording: false, timer: { second: 0, minute: 0 } });
|
|
317
|
+
setTimeout(() => {
|
|
318
|
+
createVideoBlob();
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
console.error('Error stopping recorder:', error);
|
|
324
|
+
finishRecording(null);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
stopRecorderSubject.next();
|
|
328
|
+
};
|
|
329
|
+
const createVideoBlob = () => {
|
|
330
|
+
try {
|
|
331
|
+
if (recordedChunks.length > 0) {
|
|
332
|
+
const blob = new Blob(recordedChunks, {
|
|
333
|
+
type: recordedChunks[0].type,
|
|
334
|
+
});
|
|
335
|
+
finishRecording({ blob, type: 'video' });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
console.error('Error creating video blob:', error);
|
|
340
|
+
finishRecording(null);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
const startTimer = () => {
|
|
344
|
+
interval = setInterval(() => {
|
|
345
|
+
if (store.timer().minute === 5) {
|
|
346
|
+
stopRecorder();
|
|
347
|
+
setTimeout(async () => {
|
|
348
|
+
toastService.show({
|
|
349
|
+
color: 'warning',
|
|
350
|
+
content: await translationService.translateAsync('@help-desk:report-new-issue.components.report-new-issue-form.recording-time-limit'),
|
|
351
|
+
timeOut: 5000,
|
|
352
|
+
});
|
|
353
|
+
}, 100);
|
|
354
|
+
}
|
|
355
|
+
else if (store.timer().second === 59) {
|
|
356
|
+
patchState(store, { timer: { minute: ++store.timer().minute, second: 0 } });
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
patchState(store, { timer: { minute: store.timer().minute, second: ++store.timer().second } });
|
|
360
|
+
}
|
|
361
|
+
}, 1000);
|
|
362
|
+
};
|
|
363
|
+
const resetState = () => {
|
|
364
|
+
patchState(store, {
|
|
365
|
+
loading: false,
|
|
366
|
+
captureMode: 'screenshot',
|
|
367
|
+
screenshotBlob: '',
|
|
368
|
+
videoBlob: '',
|
|
369
|
+
muted: false,
|
|
370
|
+
isRecording: false,
|
|
371
|
+
timer: {
|
|
372
|
+
second: 0,
|
|
373
|
+
minute: 0,
|
|
374
|
+
},
|
|
375
|
+
onFinish: undefined,
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
return {
|
|
379
|
+
init: async (onFinish) => {
|
|
380
|
+
try {
|
|
381
|
+
const { AXMCaptureScreenComponent } = await import('./acorex-platform-module-help-desk-client-capture-screen.component-AyM-9U5W.mjs');
|
|
382
|
+
const viewContainerRef = application.components[0].injector.get(ViewContainerRef);
|
|
383
|
+
componentRef = viewContainerRef.createComponent(AXMCaptureScreenComponent);
|
|
384
|
+
document.body.appendChild(componentRef.location.nativeElement);
|
|
385
|
+
patchState(store, { onFinish });
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
console.error('Error initializing capture screen:', error);
|
|
389
|
+
onFinish?.({ blob: new Blob(), type: 'image' });
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
cancelClick() {
|
|
393
|
+
if (store.isRecording()) {
|
|
394
|
+
stopRecorder();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
this.changeCaptureMode();
|
|
398
|
+
finishRecording(null);
|
|
399
|
+
},
|
|
400
|
+
changeCaptureMode() {
|
|
401
|
+
patchState(store, {
|
|
402
|
+
captureMode: store.captureMode() === 'screenshot' ? 'video' : 'screenshot',
|
|
403
|
+
});
|
|
404
|
+
},
|
|
405
|
+
async mutedClick() {
|
|
406
|
+
const enabled = store.muted();
|
|
407
|
+
if (audioStream) {
|
|
408
|
+
audioStream.getTracks().forEach((track) => (track.enabled = enabled));
|
|
409
|
+
}
|
|
410
|
+
patchState(store, { muted: !enabled });
|
|
411
|
+
},
|
|
412
|
+
async screenshotClick() {
|
|
413
|
+
await patchState(store, { loading: true });
|
|
414
|
+
const captureElement = document.getElementsByTagName('body')[0];
|
|
415
|
+
setTimeout(() => {
|
|
416
|
+
html2canvas(captureElement)
|
|
417
|
+
.then(async (canvas) => {
|
|
418
|
+
try {
|
|
419
|
+
const blob = await new Promise((resolve, reject) => {
|
|
420
|
+
canvas.toBlob((nextBlob) => nextBlob ? resolve(nextBlob) : reject(new Error('Failed to create blob')), 'image/png');
|
|
421
|
+
});
|
|
422
|
+
finishRecording({ blob, type: 'image' });
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
console.error('Error creating screenshot:', error);
|
|
426
|
+
finishRecording(null);
|
|
427
|
+
}
|
|
428
|
+
})
|
|
429
|
+
.catch((error) => {
|
|
430
|
+
console.error('Error capturing screenshot:', error);
|
|
431
|
+
finishRecording(null);
|
|
432
|
+
})
|
|
433
|
+
.finally(() => {
|
|
434
|
+
patchState(store, { loading: false });
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
},
|
|
438
|
+
async recordScreenClick() {
|
|
439
|
+
if (!store.isRecording() && !videoStream?.active) {
|
|
440
|
+
try {
|
|
441
|
+
videoStream = await navigator.mediaDevices.getDisplayMedia({
|
|
442
|
+
video: { displaySurface: 'monitor' },
|
|
443
|
+
audio: true,
|
|
444
|
+
});
|
|
445
|
+
await this.getMicrophonePermission();
|
|
446
|
+
await recordStream();
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
console.error('Error starting screen recording:', error);
|
|
450
|
+
toastService.show({
|
|
451
|
+
color: 'warning',
|
|
452
|
+
content: await translationService.translateAsync('@help-desk:report-new-issue.components.report-new-issue-form.capture-screen-error'),
|
|
453
|
+
timeOut: 5000,
|
|
454
|
+
});
|
|
455
|
+
finishRecording(null);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
else if (mediaRecorder) {
|
|
459
|
+
stopRecorder();
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
async getMicrophonePermission() {
|
|
463
|
+
try {
|
|
464
|
+
audioStream = await navigator.mediaDevices.getUserMedia({
|
|
465
|
+
audio: {
|
|
466
|
+
echoCancellation: true,
|
|
467
|
+
noiseSuppression: true,
|
|
468
|
+
sampleRate: 44100,
|
|
469
|
+
autoGainControl: true,
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
if (audioStream && videoStream) {
|
|
473
|
+
videoStream.addTrack(audioStream.getTracks()[0]);
|
|
474
|
+
audioStream.getTracks()[0].enabled = !store.muted();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
console.error('Error getting microphone permission:', error);
|
|
479
|
+
toastService.show({
|
|
480
|
+
color: 'warning',
|
|
481
|
+
content: await translationService.translateAsync('@help-desk:report-new-issue.components.report-new-issue-form.get-microphone-error'),
|
|
482
|
+
timeOut: 5000,
|
|
483
|
+
});
|
|
484
|
+
audioStream = null;
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
}));
|
|
489
|
+
|
|
490
|
+
const AXMReportNewIssueViewModel = signalStore({ providedIn: 'root' }, withState(() => {
|
|
491
|
+
const state = {
|
|
492
|
+
id: AXPDataGenerator.uuid(),
|
|
493
|
+
data: {
|
|
494
|
+
title: '',
|
|
495
|
+
description: '',
|
|
496
|
+
issueType: {},
|
|
497
|
+
priority: {},
|
|
498
|
+
},
|
|
499
|
+
status: 'new',
|
|
500
|
+
media: [],
|
|
501
|
+
};
|
|
502
|
+
return state;
|
|
503
|
+
}), withComputed(({ status }) => ({
|
|
504
|
+
isRecording: computed(() => status() === 'recording'),
|
|
505
|
+
})), withMethods((store, popupService = inject(AXPopupService), captureScreenService = inject(AXMCaptureScreenService), logCaptureService = inject(AXMLogCaptureService), entityEvents = inject(AXPEntityBroadcastService), translateService = inject(AXTranslationService)) => {
|
|
506
|
+
const createMediaItem = (name, mediaUrl, type) => ({
|
|
507
|
+
id: (store.media().length + 1).toString(),
|
|
508
|
+
name: name,
|
|
509
|
+
type: type,
|
|
510
|
+
thumbnailUrl: mediaUrl,
|
|
511
|
+
url: mediaUrl,
|
|
512
|
+
});
|
|
513
|
+
return {
|
|
514
|
+
async startCapturing() {
|
|
515
|
+
patchState(store, { status: 'recording' });
|
|
516
|
+
captureScreenService.init(async (data) => {
|
|
517
|
+
try {
|
|
518
|
+
if (typeof data === 'object' && 'blob' in data) {
|
|
519
|
+
const newMedia = [];
|
|
520
|
+
const mediaUrl = await URL.createObjectURL(data.blob);
|
|
521
|
+
const fileName = `${new Date().toISOString()}.${data.type === 'image' ? 'png' : 'mp4'}`;
|
|
522
|
+
newMedia.push(createMediaItem(fileName, mediaUrl, data.type));
|
|
523
|
+
if (data.type === 'video') {
|
|
524
|
+
const data = JSON.stringify(await logCaptureService.logs());
|
|
525
|
+
const logFileName = `logs-${new Date().toLocaleDateString(translateService.getActiveLang())}.txt`;
|
|
526
|
+
const blobLogFile = await new Blob([data], { type: 'text/txt;charset=utf-8' });
|
|
527
|
+
const logFileMediaUrl = await URL.createObjectURL(blobLogFile);
|
|
528
|
+
newMedia.push(createMediaItem(logFileName, logFileMediaUrl, 'text'));
|
|
529
|
+
}
|
|
530
|
+
patchState(store, {
|
|
531
|
+
media: [...store.media(), ...newMedia],
|
|
532
|
+
status: 'recorded',
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
this.showPopup();
|
|
536
|
+
}
|
|
537
|
+
catch (error) {
|
|
538
|
+
console.error('Error capturing media:', error);
|
|
539
|
+
return undefined;
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
},
|
|
543
|
+
async showPopup() {
|
|
544
|
+
try {
|
|
545
|
+
const { AXMReportNewIssueComponent } = await import('./acorex-platform-module-help-desk-client-report-new-issue.component-C-vY_x_C.mjs');
|
|
546
|
+
const config = {
|
|
547
|
+
title: await translateService.translateAsync('@help-desk:report-new-issue.entities.report-new-issue.title'),
|
|
548
|
+
};
|
|
549
|
+
const result = await popupService.open(AXMReportNewIssueComponent, config);
|
|
550
|
+
if (result.data?.insertResult) {
|
|
551
|
+
entityEvents.publishLayoutRefresh('reported-issues');
|
|
552
|
+
patchState(store, { status: 'new' });
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
console.error('Error showing popup:', error);
|
|
557
|
+
patchState(store, { status: 'new' });
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
deleteCapturedItem(index) {
|
|
561
|
+
patchState(store, { media: store.media().filter((_, i) => i !== index) });
|
|
562
|
+
},
|
|
563
|
+
resetState() {
|
|
564
|
+
patchState(store, {
|
|
565
|
+
id: AXPDataGenerator.uuid(),
|
|
566
|
+
data: {
|
|
567
|
+
title: '',
|
|
568
|
+
description: '',
|
|
569
|
+
issueType: {},
|
|
570
|
+
priority: {},
|
|
571
|
+
},
|
|
572
|
+
status: 'new',
|
|
573
|
+
media: [],
|
|
574
|
+
});
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
}));
|
|
578
|
+
|
|
579
|
+
const CaptureScreenHookProvider = {
|
|
580
|
+
key: 'file-uploader.actions',
|
|
581
|
+
priority: 0,
|
|
582
|
+
execute: (payload) => {
|
|
583
|
+
const vm = inject(AXMReportNewIssueViewModel);
|
|
584
|
+
const isExcluded = Array.isArray(payload.excludePlugins) && payload.excludePlugins.includes('capture-screen');
|
|
585
|
+
// show if plugin is explicitly enabled or it's global and not excluded
|
|
586
|
+
const isEnabled = Array.isArray(payload.plugins) && payload.plugins.some(p => p.name === 'capture-screen');
|
|
587
|
+
if (!isEnabled && isExcluded) {
|
|
588
|
+
return payload;
|
|
589
|
+
}
|
|
590
|
+
payload.actions = [
|
|
591
|
+
...payload.actions,
|
|
592
|
+
{
|
|
593
|
+
plugin: 'capture-screen',
|
|
594
|
+
global: false,
|
|
595
|
+
textKey: '@help-desk:report-new-issue.components.report-new-issue-form.capture-screen',
|
|
596
|
+
icon: 'fa-light fa-video',
|
|
597
|
+
run: async () => {
|
|
598
|
+
vm.startCapturing();
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
];
|
|
602
|
+
return payload;
|
|
603
|
+
},
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
//#endregion
|
|
607
|
+
//#region ---- Helpers ----
|
|
608
|
+
const comingSoon = (messageKey) => ({
|
|
609
|
+
name: 'auth:profile-coming-soon',
|
|
610
|
+
options: { messageKey },
|
|
611
|
+
});
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region ---- Help desk profile sections ----
|
|
614
|
+
/** Contributes help desk sections to the user profile hub. */
|
|
615
|
+
const HelpDeskProfileSectionsHookProvider = {
|
|
616
|
+
key: 'profile-page.sections',
|
|
617
|
+
priority: 10,
|
|
618
|
+
execute: (payload) => {
|
|
619
|
+
if (payload.groupId && payload.groupId !== 'requests') {
|
|
620
|
+
return payload;
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
...payload,
|
|
624
|
+
sections: [
|
|
625
|
+
...payload.sections,
|
|
626
|
+
{
|
|
627
|
+
id: 'my-tickets',
|
|
628
|
+
groupId: 'requests',
|
|
629
|
+
title: '@help-desk:profile-page.sections.my-tickets.title',
|
|
630
|
+
description: '@help-desk:profile-page.sections.my-tickets.description',
|
|
631
|
+
icon: 'far fa-ticket',
|
|
632
|
+
priority: 10,
|
|
633
|
+
layout: { colSpan: 6 },
|
|
634
|
+
actions: [
|
|
635
|
+
{
|
|
636
|
+
name: 'view-my-tickets',
|
|
637
|
+
title: '@help-desk:profile-page.sections.my-tickets.actions.manage',
|
|
638
|
+
icon: 'far fa-arrow-right',
|
|
639
|
+
command: comingSoon('@help-desk:profile-page.commands.view-my-tickets.coming-soon'),
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
},
|
|
643
|
+
],
|
|
644
|
+
};
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
//#endregion
|
|
648
|
+
|
|
649
|
+
class AXMHelpDeskModule {
|
|
650
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMHelpDeskModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
651
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMHelpDeskModule, imports: [i1.AXPComponentSlotModule] }); }
|
|
652
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMHelpDeskModule, providers: [
|
|
653
|
+
// Module-specific providers (not part of manifest system)
|
|
654
|
+
{
|
|
655
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
656
|
+
useClass: AXMReportedIssuesStatusProvider,
|
|
657
|
+
multi: true,
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
661
|
+
useValue: CaptureScreenHookProvider,
|
|
662
|
+
multi: true,
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
666
|
+
useValue: HelpDeskProfileSectionsHookProvider,
|
|
667
|
+
multi: true,
|
|
668
|
+
},
|
|
669
|
+
// Module Manifest Provider
|
|
670
|
+
{
|
|
671
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
672
|
+
useValue: HelpDeskManifest,
|
|
673
|
+
multi: true,
|
|
674
|
+
},
|
|
675
|
+
// Provider references (now using tokens)
|
|
676
|
+
{
|
|
677
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
678
|
+
useClass: AXMPermissionDefinitionProvider,
|
|
679
|
+
multi: true,
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
provide: AXP_MENU_PROVIDER,
|
|
683
|
+
useClass: AXMMenuProvider,
|
|
684
|
+
multi: true,
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
688
|
+
useClass: AXMSettingProvider,
|
|
689
|
+
multi: true,
|
|
690
|
+
},
|
|
691
|
+
provideCommandSetups([
|
|
692
|
+
{
|
|
693
|
+
key: 'show-report-issue',
|
|
694
|
+
command: () => import('./acorex-platform-module-help-desk-client-show-report-issue.command-q2fqdnAS.mjs').then((c) => c.AXMShowReportIssueCommand),
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
key: 'download-log-file',
|
|
698
|
+
command: () => import('./acorex-platform-module-help-desk-client-download-log-file.command-eMaHHzLd.mjs').then((c) => c.AXMDownloadLogFileCommand),
|
|
699
|
+
},
|
|
700
|
+
]),
|
|
701
|
+
], imports: [AXPComponentSlotModule.forChild({
|
|
702
|
+
// 'file-uploader-widget-actions': [
|
|
703
|
+
// {
|
|
704
|
+
// name: 'capture-screen-actions',
|
|
705
|
+
// component: AXPCaptureScreenWidgetExtensionComponent,
|
|
706
|
+
// },
|
|
707
|
+
// ],
|
|
708
|
+
})] }); }
|
|
709
|
+
}
|
|
710
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMHelpDeskModule, decorators: [{
|
|
711
|
+
type: NgModule,
|
|
712
|
+
args: [{
|
|
713
|
+
imports: [
|
|
714
|
+
AXPComponentSlotModule.forChild({
|
|
715
|
+
// 'file-uploader-widget-actions': [
|
|
716
|
+
// {
|
|
717
|
+
// name: 'capture-screen-actions',
|
|
718
|
+
// component: AXPCaptureScreenWidgetExtensionComponent,
|
|
719
|
+
// },
|
|
720
|
+
// ],
|
|
721
|
+
}),
|
|
722
|
+
],
|
|
723
|
+
exports: [],
|
|
724
|
+
declarations: [],
|
|
725
|
+
providers: [
|
|
726
|
+
// Module-specific providers (not part of manifest system)
|
|
727
|
+
{
|
|
728
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
729
|
+
useClass: AXMReportedIssuesStatusProvider,
|
|
730
|
+
multi: true,
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
734
|
+
useValue: CaptureScreenHookProvider,
|
|
735
|
+
multi: true,
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
739
|
+
useValue: HelpDeskProfileSectionsHookProvider,
|
|
740
|
+
multi: true,
|
|
741
|
+
},
|
|
742
|
+
// Module Manifest Provider
|
|
743
|
+
{
|
|
744
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
745
|
+
useValue: HelpDeskManifest,
|
|
746
|
+
multi: true,
|
|
747
|
+
},
|
|
748
|
+
// Provider references (now using tokens)
|
|
749
|
+
{
|
|
750
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
751
|
+
useClass: AXMPermissionDefinitionProvider,
|
|
752
|
+
multi: true,
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
provide: AXP_MENU_PROVIDER,
|
|
756
|
+
useClass: AXMMenuProvider,
|
|
757
|
+
multi: true,
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
761
|
+
useClass: AXMSettingProvider,
|
|
762
|
+
multi: true,
|
|
763
|
+
},
|
|
764
|
+
provideCommandSetups([
|
|
765
|
+
{
|
|
766
|
+
key: 'show-report-issue',
|
|
767
|
+
command: () => import('./acorex-platform-module-help-desk-client-show-report-issue.command-q2fqdnAS.mjs').then((c) => c.AXMShowReportIssueCommand),
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
key: 'download-log-file',
|
|
771
|
+
command: () => import('./acorex-platform-module-help-desk-client-download-log-file.command-eMaHHzLd.mjs').then((c) => c.AXMDownloadLogFileCommand),
|
|
772
|
+
},
|
|
773
|
+
]),
|
|
774
|
+
],
|
|
775
|
+
}]
|
|
776
|
+
}] });
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Generated bundle index. Do not edit.
|
|
780
|
+
*/
|
|
781
|
+
|
|
782
|
+
export { AXMReportNewIssueViewModel as A, AXMLogCaptureService as a, AXMCaptureScreenService as b, AXMHelpDeskModule as c, AXMMenuProvider as d, AXMPermissionDefinitionProvider as e, AXMReportedIssuesStatusProvider as f, AXMSettingProvider as g };
|
|
783
|
+
//# sourceMappingURL=acorex-platform-module-help-desk-client-acorex-platform-module-help-desk-client-OtDtf3iY.mjs.map
|