@commandgarden/cli 2.12.1 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +58 -28
- package/node_modules/@commandgarden/app/dist/client/assets/{Slides-CHeVcB9K.js → Slides-DWQmJfkp.js} +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/{index-DR1TjI6k.js → index-C8yqRQk-.js} +37 -37
- package/node_modules/@commandgarden/app/dist/client/assets/index-rHqHbsBw.css +1 -0
- package/node_modules/@commandgarden/app/dist/client/index.html +19 -19
- package/node_modules/@commandgarden/app/dist/server/journal/journal.service.d.ts +2 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.service.js +54 -24
- package/node_modules/@commandgarden/app/dist/server/journal/journal.types.d.ts +8 -0
- package/node_modules/@commandgarden/app/dist/server/main.js +1 -1
- package/node_modules/@commandgarden/app/dist/server/routes/audit.js +27 -16
- package/node_modules/@commandgarden/app/dist/server/routes/config.js +8 -2
- package/node_modules/@commandgarden/app/dist/server/routes/connectors.js +37 -26
- package/node_modules/@commandgarden/app/dist/server/routes/run.js +3 -4
- package/node_modules/@commandgarden/app/dist/server/routes/status.js +2 -1
- package/node_modules/@commandgarden/app/dist/server/routes/utils.d.ts +2 -0
- package/node_modules/@commandgarden/app/dist/server/routes/utils.js +4 -0
- package/node_modules/@commandgarden/app/dist/server/store.js +53 -53
- package/node_modules/@commandgarden/app/package.json +42 -42
- package/node_modules/@commandgarden/chrome/dist/content-script.js.map +1 -1
- package/node_modules/@commandgarden/chrome/dist/manifest.json +26 -26
- package/node_modules/@commandgarden/chrome/dist/popup.html +218 -218
- package/node_modules/@commandgarden/chrome/dist/popup.js.map +1 -1
- package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +1 -1
- package/node_modules/@commandgarden/chrome/package.json +26 -26
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.eval.js +100 -100
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.yaml +71 -71
- package/node_modules/@commandgarden/daemon/connectors/gcs-kb-content.yaml +61 -61
- package/node_modules/@commandgarden/daemon/connectors/gcs-kb-pages.yaml +54 -54
- package/node_modules/@commandgarden/daemon/connectors/jira-my-tickets.eval.js +115 -115
- package/node_modules/@commandgarden/daemon/connectors/jira-my-tickets.yaml +54 -54
- package/node_modules/@commandgarden/daemon/connectors/lib/msal-token.js +20 -20
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.eval.js +204 -204
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.yaml +42 -42
- package/node_modules/@commandgarden/daemon/connectors/saba-pending-training.eval.js +94 -94
- package/node_modules/@commandgarden/daemon/connectors/saba-pending-training.yaml +34 -34
- package/node_modules/@commandgarden/daemon/connectors/socket-security-news.yaml +63 -63
- package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.eval.js +437 -437
- package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.yaml +53 -53
- package/node_modules/@commandgarden/daemon/connectors/teams-rooms-availability.eval.js +547 -547
- package/node_modules/@commandgarden/daemon/connectors/teams-rooms-availability.yaml +48 -48
- package/node_modules/@commandgarden/daemon/connectors/timetracking-projects.eval.js +52 -52
- package/node_modules/@commandgarden/daemon/connectors/timetracking-projects.yaml +42 -42
- package/node_modules/@commandgarden/daemon/connectors/timetracking-report.eval.js +81 -81
- package/node_modules/@commandgarden/daemon/connectors/timetracking-report.yaml +52 -52
- package/node_modules/@commandgarden/daemon/connectors/tldrsec-newsletter.eval.js +27 -27
- package/node_modules/@commandgarden/daemon/connectors/tldrsec-newsletter.yaml +38 -38
- package/node_modules/@commandgarden/daemon/connectors/tokenmaster-clients-list.yaml +55 -55
- package/node_modules/@commandgarden/daemon/dist/audit-store.js +8 -8
- package/node_modules/@commandgarden/daemon/dist/auth.d.ts +1 -0
- package/node_modules/@commandgarden/daemon/dist/auth.d.ts.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/auth.js +10 -0
- package/node_modules/@commandgarden/daemon/dist/auth.js.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/main.js +12 -5
- package/node_modules/@commandgarden/daemon/dist/main.js.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/server.d.ts.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/server.js +10 -0
- package/node_modules/@commandgarden/daemon/dist/server.js.map +1 -1
- package/node_modules/@commandgarden/daemon/package.json +32 -32
- package/node_modules/@commandgarden/shared/dist/daemon-client.d.ts +5 -1
- package/node_modules/@commandgarden/shared/dist/daemon-client.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/daemon-client.js +32 -14
- package/node_modules/@commandgarden/shared/dist/daemon-client.js.map +1 -1
- package/node_modules/@commandgarden/shared/package.json +32 -32
- package/package.json +58 -58
- package/node_modules/@commandgarden/app/dist/client/assets/index-CDD2bVHm.css +0 -1
- package/node_modules/@commandgarden/app/dist/server/daemon-client.test.js +0 -47
- package/node_modules/@commandgarden/app/dist/server/routes/routes.test.js +0 -137
- package/node_modules/@commandgarden/app/dist/server/store.test.js +0 -59
- package/node_modules/@commandgarden/chrome/dist/fetch-interceptor.js +0 -44
- package/node_modules/@commandgarden/daemon/dist/cdp-client.d.ts +0 -24
- package/node_modules/@commandgarden/daemon/dist/cdp-client.d.ts.map +0 -1
- package/node_modules/@commandgarden/daemon/dist/cdp-client.js +0 -150
- package/node_modules/@commandgarden/daemon/dist/cdp-client.js.map +0 -1
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
site: teams
|
|
2
|
-
name: rooms-availability
|
|
3
|
-
version: "1.0"
|
|
4
|
-
description: "Meeting-room free/busy timeline for multiple rooms on a given day (Teams/Outlook calendar)"
|
|
5
|
-
access: read
|
|
6
|
-
cdp: true
|
|
7
|
-
|
|
8
|
-
domains:
|
|
9
|
-
- "outlook.cloud.microsoft.mcas.ms"
|
|
10
|
-
capabilities:
|
|
11
|
-
- navigate
|
|
12
|
-
- js_evaluate
|
|
13
|
-
|
|
14
|
-
args:
|
|
15
|
-
- name: rooms
|
|
16
|
-
type: string
|
|
17
|
-
required: true
|
|
18
|
-
help: "Comma-separated room names, emails, or name:email pairs (e.g. 'MBTMY The Vista:RES-RERE-M6VJ7ZUW@mercedes-benz.com,MBTMY The Cliffside:res-rere-m6vjl2tw@mercedes-benz.com' for batch mode, or 'MBTMY The Vista,res-rere-m6vj7zuw@mercedes-benz.com' for sequential)"
|
|
19
|
-
- name: date
|
|
20
|
-
type: string
|
|
21
|
-
required: false
|
|
22
|
-
help: "Day to check in YYYY-MM-DD format (default: today)"
|
|
23
|
-
pattern: "^\\d{4}-\\d{2}-\\d{2}$"
|
|
24
|
-
|
|
25
|
-
columns:
|
|
26
|
-
- name: roomName
|
|
27
|
-
type: string
|
|
28
|
-
- name: roomEmail
|
|
29
|
-
type: string
|
|
30
|
-
- name: date
|
|
31
|
-
type: string
|
|
32
|
-
- name: state
|
|
33
|
-
type: string
|
|
34
|
-
- name: start
|
|
35
|
-
type: string
|
|
36
|
-
- name: end
|
|
37
|
-
type: string
|
|
38
|
-
- name: durationMin
|
|
39
|
-
type: number
|
|
40
|
-
|
|
41
|
-
pipeline:
|
|
42
|
-
- step: navigate
|
|
43
|
-
url: "https://outlook.cloud.microsoft.mcas.ms/calendar/deeplink/compose"
|
|
44
|
-
- step: wait
|
|
45
|
-
selector: "body"
|
|
46
|
-
timeout: 30000
|
|
47
|
-
- step: js_evaluate
|
|
48
|
-
file: teams-rooms-availability.eval.js
|
|
1
|
+
site: teams
|
|
2
|
+
name: rooms-availability
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "Meeting-room free/busy timeline for multiple rooms on a given day (Teams/Outlook calendar)"
|
|
5
|
+
access: read
|
|
6
|
+
cdp: true
|
|
7
|
+
|
|
8
|
+
domains:
|
|
9
|
+
- "outlook.cloud.microsoft.mcas.ms"
|
|
10
|
+
capabilities:
|
|
11
|
+
- navigate
|
|
12
|
+
- js_evaluate
|
|
13
|
+
|
|
14
|
+
args:
|
|
15
|
+
- name: rooms
|
|
16
|
+
type: string
|
|
17
|
+
required: true
|
|
18
|
+
help: "Comma-separated room names, emails, or name:email pairs (e.g. 'MBTMY The Vista:RES-RERE-M6VJ7ZUW@mercedes-benz.com,MBTMY The Cliffside:res-rere-m6vjl2tw@mercedes-benz.com' for batch mode, or 'MBTMY The Vista,res-rere-m6vj7zuw@mercedes-benz.com' for sequential)"
|
|
19
|
+
- name: date
|
|
20
|
+
type: string
|
|
21
|
+
required: false
|
|
22
|
+
help: "Day to check in YYYY-MM-DD format (default: today)"
|
|
23
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$"
|
|
24
|
+
|
|
25
|
+
columns:
|
|
26
|
+
- name: roomName
|
|
27
|
+
type: string
|
|
28
|
+
- name: roomEmail
|
|
29
|
+
type: string
|
|
30
|
+
- name: date
|
|
31
|
+
type: string
|
|
32
|
+
- name: state
|
|
33
|
+
type: string
|
|
34
|
+
- name: start
|
|
35
|
+
type: string
|
|
36
|
+
- name: end
|
|
37
|
+
type: string
|
|
38
|
+
- name: durationMin
|
|
39
|
+
type: number
|
|
40
|
+
|
|
41
|
+
pipeline:
|
|
42
|
+
- step: navigate
|
|
43
|
+
url: "https://outlook.cloud.microsoft.mcas.ms/calendar/deeplink/compose"
|
|
44
|
+
- step: wait
|
|
45
|
+
selector: "body"
|
|
46
|
+
timeout: 30000
|
|
47
|
+
- step: js_evaluate
|
|
48
|
+
file: teams-rooms-availability.eval.js
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
// Runs in page context via js_evaluate step.
|
|
2
|
-
// Fetches the Projects API to list all available projects and activities.
|
|
3
|
-
//
|
|
4
|
-
// Template variables interpolated before execution:
|
|
5
|
-
// ${{ args.month | default("") }}
|
|
6
|
-
|
|
7
|
-
// Poll for MSAL token (handles SSO redirects + MFA)
|
|
8
|
-
// Canonical source: connectors/lib/msal-token.js
|
|
9
|
-
const __deadline = Date.now() + 60000;
|
|
10
|
-
let token;
|
|
11
|
-
while (Date.now() < __deadline) {
|
|
12
|
-
const k = Object.keys(sessionStorage).find(x => x.includes('accesstoken'));
|
|
13
|
-
if (k) {
|
|
14
|
-
try {
|
|
15
|
-
const tokenData = JSON.parse(sessionStorage.getItem(k));
|
|
16
|
-
if (Number(tokenData.expiresOn) > Math.floor(Date.now() / 1000) + 30) {
|
|
17
|
-
token = tokenData.secret;
|
|
18
|
-
break;
|
|
19
|
-
}
|
|
20
|
-
} catch (_) {}
|
|
21
|
-
}
|
|
22
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
23
|
-
}
|
|
24
|
-
if (!token) throw new Error('No valid MSAL access token after 60s — log in and retry');
|
|
25
|
-
|
|
26
|
-
let month = '${{ args.month | default("") }}';
|
|
27
|
-
if (!month) {
|
|
28
|
-
const now = new Date();
|
|
29
|
-
month = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const resp = await fetch(
|
|
33
|
-
'https://mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net/api/Projects?date=' + month + '-01',
|
|
34
|
-
{ headers: { Authorization: 'Bearer ' + token, Accept: 'application/json' } }
|
|
35
|
-
);
|
|
36
|
-
if (!resp.ok) throw new Error('Projects API returned HTTP ' + resp.status);
|
|
37
|
-
|
|
38
|
-
const projects = await resp.json();
|
|
39
|
-
const rows = [];
|
|
40
|
-
for (const p of projects) {
|
|
41
|
-
for (const act of p.activities || []) {
|
|
42
|
-
rows.push({
|
|
43
|
-
projectId: p.mserp_projectid || null,
|
|
44
|
-
projectName: p.mserp_projectname || null,
|
|
45
|
-
activityNumber: act.mserp_activitynumber || null,
|
|
46
|
-
activityName: act.mserp_description || null,
|
|
47
|
-
category: act.mserp_category || null,
|
|
48
|
-
linePropertyId: act.mserp_linepropertyid || null,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return rows;
|
|
1
|
+
// Runs in page context via js_evaluate step.
|
|
2
|
+
// Fetches the Projects API to list all available projects and activities.
|
|
3
|
+
//
|
|
4
|
+
// Template variables interpolated before execution:
|
|
5
|
+
// ${{ args.month | default("") }}
|
|
6
|
+
|
|
7
|
+
// Poll for MSAL token (handles SSO redirects + MFA)
|
|
8
|
+
// Canonical source: connectors/lib/msal-token.js
|
|
9
|
+
const __deadline = Date.now() + 60000;
|
|
10
|
+
let token;
|
|
11
|
+
while (Date.now() < __deadline) {
|
|
12
|
+
const k = Object.keys(sessionStorage).find(x => x.includes('accesstoken'));
|
|
13
|
+
if (k) {
|
|
14
|
+
try {
|
|
15
|
+
const tokenData = JSON.parse(sessionStorage.getItem(k));
|
|
16
|
+
if (Number(tokenData.expiresOn) > Math.floor(Date.now() / 1000) + 30) {
|
|
17
|
+
token = tokenData.secret;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
} catch (_) {}
|
|
21
|
+
}
|
|
22
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
23
|
+
}
|
|
24
|
+
if (!token) throw new Error('No valid MSAL access token after 60s — log in and retry');
|
|
25
|
+
|
|
26
|
+
let month = '${{ args.month | default("") }}';
|
|
27
|
+
if (!month) {
|
|
28
|
+
const now = new Date();
|
|
29
|
+
month = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const resp = await fetch(
|
|
33
|
+
'https://mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net/api/Projects?date=' + month + '-01',
|
|
34
|
+
{ headers: { Authorization: 'Bearer ' + token, Accept: 'application/json' } }
|
|
35
|
+
);
|
|
36
|
+
if (!resp.ok) throw new Error('Projects API returned HTTP ' + resp.status);
|
|
37
|
+
|
|
38
|
+
const projects = await resp.json();
|
|
39
|
+
const rows = [];
|
|
40
|
+
for (const p of projects) {
|
|
41
|
+
for (const act of p.activities || []) {
|
|
42
|
+
rows.push({
|
|
43
|
+
projectId: p.mserp_projectid || null,
|
|
44
|
+
projectName: p.mserp_projectname || null,
|
|
45
|
+
activityNumber: act.mserp_activitynumber || null,
|
|
46
|
+
activityName: act.mserp_description || null,
|
|
47
|
+
category: act.mserp_category || null,
|
|
48
|
+
linePropertyId: act.mserp_linepropertyid || null,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return rows;
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
site: timetracking
|
|
2
|
-
name: projects
|
|
3
|
-
version: "1.0"
|
|
4
|
-
description: "List all available projects and activities for the current user"
|
|
5
|
-
access: read
|
|
6
|
-
|
|
7
|
-
domains:
|
|
8
|
-
- "timetracking.mercedes-benz-techinnovation.com"
|
|
9
|
-
- "mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net"
|
|
10
|
-
capabilities:
|
|
11
|
-
- navigate
|
|
12
|
-
- js_evaluate
|
|
13
|
-
|
|
14
|
-
args:
|
|
15
|
-
- name: month
|
|
16
|
-
type: string
|
|
17
|
-
required: false
|
|
18
|
-
help: "Month in YYYY-MM format (default: current month)"
|
|
19
|
-
pattern: "^\\d{4}-\\d{2}$"
|
|
20
|
-
|
|
21
|
-
columns:
|
|
22
|
-
- name: projectId
|
|
23
|
-
type: string
|
|
24
|
-
- name: projectName
|
|
25
|
-
type: string
|
|
26
|
-
- name: activityNumber
|
|
27
|
-
type: string
|
|
28
|
-
- name: activityName
|
|
29
|
-
type: string
|
|
30
|
-
- name: category
|
|
31
|
-
type: string
|
|
32
|
-
- name: linePropertyId
|
|
33
|
-
type: string
|
|
34
|
-
|
|
35
|
-
pipeline:
|
|
36
|
-
- step: navigate
|
|
37
|
-
url: "https://timetracking.mercedes-benz-techinnovation.com/"
|
|
38
|
-
- step: wait
|
|
39
|
-
selector: "body"
|
|
40
|
-
timeout: 10000
|
|
41
|
-
- step: js_evaluate
|
|
42
|
-
file: timetracking-projects.eval.js
|
|
1
|
+
site: timetracking
|
|
2
|
+
name: projects
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "List all available projects and activities for the current user"
|
|
5
|
+
access: read
|
|
6
|
+
|
|
7
|
+
domains:
|
|
8
|
+
- "timetracking.mercedes-benz-techinnovation.com"
|
|
9
|
+
- "mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net"
|
|
10
|
+
capabilities:
|
|
11
|
+
- navigate
|
|
12
|
+
- js_evaluate
|
|
13
|
+
|
|
14
|
+
args:
|
|
15
|
+
- name: month
|
|
16
|
+
type: string
|
|
17
|
+
required: false
|
|
18
|
+
help: "Month in YYYY-MM format (default: current month)"
|
|
19
|
+
pattern: "^\\d{4}-\\d{2}$"
|
|
20
|
+
|
|
21
|
+
columns:
|
|
22
|
+
- name: projectId
|
|
23
|
+
type: string
|
|
24
|
+
- name: projectName
|
|
25
|
+
type: string
|
|
26
|
+
- name: activityNumber
|
|
27
|
+
type: string
|
|
28
|
+
- name: activityName
|
|
29
|
+
type: string
|
|
30
|
+
- name: category
|
|
31
|
+
type: string
|
|
32
|
+
- name: linePropertyId
|
|
33
|
+
type: string
|
|
34
|
+
|
|
35
|
+
pipeline:
|
|
36
|
+
- step: navigate
|
|
37
|
+
url: "https://timetracking.mercedes-benz-techinnovation.com/"
|
|
38
|
+
- step: wait
|
|
39
|
+
selector: "body"
|
|
40
|
+
timeout: 10000
|
|
41
|
+
- step: js_evaluate
|
|
42
|
+
file: timetracking-projects.eval.js
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
// Runs in page context via js_evaluate step.
|
|
2
|
-
// Reads the MSAL access token from sessionStorage, fetches the ReportFAK API,
|
|
3
|
-
// and flattens day objects into one row per booking line.
|
|
4
|
-
//
|
|
5
|
-
// SSO/MFA: polls sessionStorage for up to 60s, giving the user time to
|
|
6
|
-
// complete login and get redirected back to the app.
|
|
7
|
-
//
|
|
8
|
-
// Template variables interpolated before execution:
|
|
9
|
-
// ${{ args.month | default("") }}
|
|
10
|
-
|
|
11
|
-
// Poll for MSAL token (handles SSO redirects + MFA)
|
|
12
|
-
// Canonical source: connectors/lib/msal-token.js
|
|
13
|
-
const __deadline = Date.now() + 60000;
|
|
14
|
-
let token;
|
|
15
|
-
while (Date.now() < __deadline) {
|
|
16
|
-
const k = Object.keys(sessionStorage).find(x => x.includes('accesstoken'));
|
|
17
|
-
if (k) {
|
|
18
|
-
try {
|
|
19
|
-
const tokenData = JSON.parse(sessionStorage.getItem(k));
|
|
20
|
-
if (Number(tokenData.expiresOn) > Math.floor(Date.now() / 1000) + 30) {
|
|
21
|
-
token = tokenData.secret;
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
} catch (_) {}
|
|
25
|
-
}
|
|
26
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
27
|
-
}
|
|
28
|
-
if (!token) throw new Error('No valid MSAL access token after 60s — log in and retry');
|
|
29
|
-
|
|
30
|
-
let month = '${{ args.month | default("") }}';
|
|
31
|
-
if (!month) {
|
|
32
|
-
const now = new Date();
|
|
33
|
-
month = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const apiBase = 'https://mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net/api/';
|
|
37
|
-
const authHeaders = { Authorization: 'Bearer ' + token, Accept: 'application/json' };
|
|
38
|
-
|
|
39
|
-
const [resp, projResp] = await Promise.all([
|
|
40
|
-
fetch(apiBase + 'ReportFAK?date=' + month + '-01', { headers: authHeaders }),
|
|
41
|
-
fetch(apiBase + 'Projects?date=' + month + '-01', { headers: authHeaders }).catch(() => null),
|
|
42
|
-
]);
|
|
43
|
-
if (!resp.ok) throw new Error('ReportFAK returned HTTP ' + resp.status);
|
|
44
|
-
|
|
45
|
-
const projectNames = new Map();
|
|
46
|
-
const activityNames = new Map(); // key: "projectId\0activityNumber" → description
|
|
47
|
-
if (projResp && projResp.ok) {
|
|
48
|
-
for (const p of await projResp.json()) {
|
|
49
|
-
projectNames.set(p.mserp_projectid, p.mserp_projectname);
|
|
50
|
-
for (const act of p.activities || []) {
|
|
51
|
-
if (act.mserp_activitynumber && act.mserp_description) {
|
|
52
|
-
activityNames.set(act.mserp_projectid + '\0' + act.mserp_activitynumber, act.mserp_description);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const days = await resp.json();
|
|
59
|
-
const rows = [];
|
|
60
|
-
for (const day of days) {
|
|
61
|
-
const header = day.calendarHeader || {};
|
|
62
|
-
const dayDate = (day.date || '').slice(0, 10);
|
|
63
|
-
for (const line of day.calendarLines || []) {
|
|
64
|
-
const pid = line.mserp_projectid || null;
|
|
65
|
-
const actNum = line.mserp_activitynumber || null;
|
|
66
|
-
rows.push({
|
|
67
|
-
month: month,
|
|
68
|
-
date: dayDate,
|
|
69
|
-
projectId: pid,
|
|
70
|
-
projectName: projectNames.get(pid) || null,
|
|
71
|
-
category: line.mserp_category || null,
|
|
72
|
-
activity: actNum,
|
|
73
|
-
activityName: (pid && actNum) ? (activityNames.get(pid + '\0' + actNum) || null) : null,
|
|
74
|
-
hours: typeof line.mserp_hours === 'number' ? line.mserp_hours : null,
|
|
75
|
-
status: header.status || null,
|
|
76
|
-
journalId: line.mserp_journalid || null,
|
|
77
|
-
lineNumber: typeof line.mserp_linenumber === 'number' ? line.mserp_linenumber : null,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return rows;
|
|
1
|
+
// Runs in page context via js_evaluate step.
|
|
2
|
+
// Reads the MSAL access token from sessionStorage, fetches the ReportFAK API,
|
|
3
|
+
// and flattens day objects into one row per booking line.
|
|
4
|
+
//
|
|
5
|
+
// SSO/MFA: polls sessionStorage for up to 60s, giving the user time to
|
|
6
|
+
// complete login and get redirected back to the app.
|
|
7
|
+
//
|
|
8
|
+
// Template variables interpolated before execution:
|
|
9
|
+
// ${{ args.month | default("") }}
|
|
10
|
+
|
|
11
|
+
// Poll for MSAL token (handles SSO redirects + MFA)
|
|
12
|
+
// Canonical source: connectors/lib/msal-token.js
|
|
13
|
+
const __deadline = Date.now() + 60000;
|
|
14
|
+
let token;
|
|
15
|
+
while (Date.now() < __deadline) {
|
|
16
|
+
const k = Object.keys(sessionStorage).find(x => x.includes('accesstoken'));
|
|
17
|
+
if (k) {
|
|
18
|
+
try {
|
|
19
|
+
const tokenData = JSON.parse(sessionStorage.getItem(k));
|
|
20
|
+
if (Number(tokenData.expiresOn) > Math.floor(Date.now() / 1000) + 30) {
|
|
21
|
+
token = tokenData.secret;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
} catch (_) {}
|
|
25
|
+
}
|
|
26
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
27
|
+
}
|
|
28
|
+
if (!token) throw new Error('No valid MSAL access token after 60s — log in and retry');
|
|
29
|
+
|
|
30
|
+
let month = '${{ args.month | default("") }}';
|
|
31
|
+
if (!month) {
|
|
32
|
+
const now = new Date();
|
|
33
|
+
month = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const apiBase = 'https://mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net/api/';
|
|
37
|
+
const authHeaders = { Authorization: 'Bearer ' + token, Accept: 'application/json' };
|
|
38
|
+
|
|
39
|
+
const [resp, projResp] = await Promise.all([
|
|
40
|
+
fetch(apiBase + 'ReportFAK?date=' + month + '-01', { headers: authHeaders }),
|
|
41
|
+
fetch(apiBase + 'Projects?date=' + month + '-01', { headers: authHeaders }).catch(() => null),
|
|
42
|
+
]);
|
|
43
|
+
if (!resp.ok) throw new Error('ReportFAK returned HTTP ' + resp.status);
|
|
44
|
+
|
|
45
|
+
const projectNames = new Map();
|
|
46
|
+
const activityNames = new Map(); // key: "projectId\0activityNumber" → description
|
|
47
|
+
if (projResp && projResp.ok) {
|
|
48
|
+
for (const p of await projResp.json()) {
|
|
49
|
+
projectNames.set(p.mserp_projectid, p.mserp_projectname);
|
|
50
|
+
for (const act of p.activities || []) {
|
|
51
|
+
if (act.mserp_activitynumber && act.mserp_description) {
|
|
52
|
+
activityNames.set(act.mserp_projectid + '\0' + act.mserp_activitynumber, act.mserp_description);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const days = await resp.json();
|
|
59
|
+
const rows = [];
|
|
60
|
+
for (const day of days) {
|
|
61
|
+
const header = day.calendarHeader || {};
|
|
62
|
+
const dayDate = (day.date || '').slice(0, 10);
|
|
63
|
+
for (const line of day.calendarLines || []) {
|
|
64
|
+
const pid = line.mserp_projectid || null;
|
|
65
|
+
const actNum = line.mserp_activitynumber || null;
|
|
66
|
+
rows.push({
|
|
67
|
+
month: month,
|
|
68
|
+
date: dayDate,
|
|
69
|
+
projectId: pid,
|
|
70
|
+
projectName: projectNames.get(pid) || null,
|
|
71
|
+
category: line.mserp_category || null,
|
|
72
|
+
activity: actNum,
|
|
73
|
+
activityName: (pid && actNum) ? (activityNames.get(pid + '\0' + actNum) || null) : null,
|
|
74
|
+
hours: typeof line.mserp_hours === 'number' ? line.mserp_hours : null,
|
|
75
|
+
status: header.status || null,
|
|
76
|
+
journalId: line.mserp_journalid || null,
|
|
77
|
+
lineNumber: typeof line.mserp_linenumber === 'number' ? line.mserp_linenumber : null,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return rows;
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
site: timetracking
|
|
2
|
-
name: report
|
|
3
|
-
version: "1.0"
|
|
4
|
-
description: "MBTI Time Tracking monthly report — one row per booking line"
|
|
5
|
-
access: read
|
|
6
|
-
|
|
7
|
-
domains:
|
|
8
|
-
- "timetracking.mercedes-benz-techinnovation.com"
|
|
9
|
-
- "mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net"
|
|
10
|
-
capabilities:
|
|
11
|
-
- navigate
|
|
12
|
-
- js_evaluate
|
|
13
|
-
|
|
14
|
-
args:
|
|
15
|
-
- name: month
|
|
16
|
-
type: string
|
|
17
|
-
required: false
|
|
18
|
-
help: "Month in YYYY-MM format (default: current month)"
|
|
19
|
-
pattern: "^\\d{4}-\\d{2}$"
|
|
20
|
-
|
|
21
|
-
columns:
|
|
22
|
-
- name: month
|
|
23
|
-
type: string
|
|
24
|
-
- name: date
|
|
25
|
-
type: string
|
|
26
|
-
- name: projectId
|
|
27
|
-
type: string
|
|
28
|
-
- name: projectName
|
|
29
|
-
type: string
|
|
30
|
-
- name: category
|
|
31
|
-
type: string
|
|
32
|
-
- name: activity
|
|
33
|
-
type: string
|
|
34
|
-
- name: activityName
|
|
35
|
-
type: string
|
|
36
|
-
- name: hours
|
|
37
|
-
type: number
|
|
38
|
-
- name: status
|
|
39
|
-
type: string
|
|
40
|
-
- name: journalId
|
|
41
|
-
type: string
|
|
42
|
-
- name: lineNumber
|
|
43
|
-
type: number
|
|
44
|
-
|
|
45
|
-
pipeline:
|
|
46
|
-
- step: navigate
|
|
47
|
-
url: "https://timetracking.mercedes-benz-techinnovation.com/"
|
|
48
|
-
- step: wait
|
|
49
|
-
selector: "body"
|
|
50
|
-
timeout: 10000
|
|
51
|
-
- step: js_evaluate
|
|
52
|
-
file: timetracking-report.eval.js
|
|
1
|
+
site: timetracking
|
|
2
|
+
name: report
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "MBTI Time Tracking monthly report — one row per booking line"
|
|
5
|
+
access: read
|
|
6
|
+
|
|
7
|
+
domains:
|
|
8
|
+
- "timetracking.mercedes-benz-techinnovation.com"
|
|
9
|
+
- "mbti-bam-wzde-prd-ejdchtb0g9afexhr.a01.azurefd.net"
|
|
10
|
+
capabilities:
|
|
11
|
+
- navigate
|
|
12
|
+
- js_evaluate
|
|
13
|
+
|
|
14
|
+
args:
|
|
15
|
+
- name: month
|
|
16
|
+
type: string
|
|
17
|
+
required: false
|
|
18
|
+
help: "Month in YYYY-MM format (default: current month)"
|
|
19
|
+
pattern: "^\\d{4}-\\d{2}$"
|
|
20
|
+
|
|
21
|
+
columns:
|
|
22
|
+
- name: month
|
|
23
|
+
type: string
|
|
24
|
+
- name: date
|
|
25
|
+
type: string
|
|
26
|
+
- name: projectId
|
|
27
|
+
type: string
|
|
28
|
+
- name: projectName
|
|
29
|
+
type: string
|
|
30
|
+
- name: category
|
|
31
|
+
type: string
|
|
32
|
+
- name: activity
|
|
33
|
+
type: string
|
|
34
|
+
- name: activityName
|
|
35
|
+
type: string
|
|
36
|
+
- name: hours
|
|
37
|
+
type: number
|
|
38
|
+
- name: status
|
|
39
|
+
type: string
|
|
40
|
+
- name: journalId
|
|
41
|
+
type: string
|
|
42
|
+
- name: lineNumber
|
|
43
|
+
type: number
|
|
44
|
+
|
|
45
|
+
pipeline:
|
|
46
|
+
- step: navigate
|
|
47
|
+
url: "https://timetracking.mercedes-benz-techinnovation.com/"
|
|
48
|
+
- step: wait
|
|
49
|
+
selector: "body"
|
|
50
|
+
timeout: 10000
|
|
51
|
+
- step: js_evaluate
|
|
52
|
+
file: timetracking-report.eval.js
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
// tldrsec-newsletter.eval.js
|
|
2
|
-
// Extracts newsletter posts from Remix's __remixContext embedded JSON.
|
|
3
|
-
// Returns an array of flattened post objects for the pipeline.
|
|
4
|
-
// NOTE: No IIFE — evaluateInPage wraps this in AsyncFunction already.
|
|
5
|
-
|
|
6
|
-
const ctx = window.__remixContext;
|
|
7
|
-
if (!ctx) throw new Error('__remixContext not found');
|
|
8
|
-
|
|
9
|
-
const loaderData = ctx.state?.loaderData;
|
|
10
|
-
if (!loaderData) throw new Error('loaderData not found in __remixContext');
|
|
11
|
-
|
|
12
|
-
// The route key for the tag/category page
|
|
13
|
-
const categoryData = loaderData['routes/t/$category'];
|
|
14
|
-
if (!categoryData) throw new Error('routes/t/$category loader data not found');
|
|
15
|
-
|
|
16
|
-
const posts = categoryData.paginatedPosts?.posts;
|
|
17
|
-
if (!Array.isArray(posts)) throw new Error('paginatedPosts.posts is not an array');
|
|
18
|
-
|
|
19
|
-
return posts.map((p) => ({
|
|
20
|
-
title: p.web_title || p.meta_default_title || '',
|
|
21
|
-
slug: p.slug || '',
|
|
22
|
-
url: 'https://tldrsec.com/p/' + (p.slug || ''),
|
|
23
|
-
publishedAt: p.override_scheduled_at || p.created_at || '',
|
|
24
|
-
excerpt: p.web_subtitle || p.meta_default_description || '',
|
|
25
|
-
authors: (p.authors || []).map((a) => a.name).join(', '),
|
|
26
|
-
tags: (p.content_tags || []).map((t) => t.display).join(', '),
|
|
27
|
-
}));
|
|
1
|
+
// tldrsec-newsletter.eval.js
|
|
2
|
+
// Extracts newsletter posts from Remix's __remixContext embedded JSON.
|
|
3
|
+
// Returns an array of flattened post objects for the pipeline.
|
|
4
|
+
// NOTE: No IIFE — evaluateInPage wraps this in AsyncFunction already.
|
|
5
|
+
|
|
6
|
+
const ctx = window.__remixContext;
|
|
7
|
+
if (!ctx) throw new Error('__remixContext not found');
|
|
8
|
+
|
|
9
|
+
const loaderData = ctx.state?.loaderData;
|
|
10
|
+
if (!loaderData) throw new Error('loaderData not found in __remixContext');
|
|
11
|
+
|
|
12
|
+
// The route key for the tag/category page
|
|
13
|
+
const categoryData = loaderData['routes/t/$category'];
|
|
14
|
+
if (!categoryData) throw new Error('routes/t/$category loader data not found');
|
|
15
|
+
|
|
16
|
+
const posts = categoryData.paginatedPosts?.posts;
|
|
17
|
+
if (!Array.isArray(posts)) throw new Error('paginatedPosts.posts is not an array');
|
|
18
|
+
|
|
19
|
+
return posts.map((p) => ({
|
|
20
|
+
title: p.web_title || p.meta_default_title || '',
|
|
21
|
+
slug: p.slug || '',
|
|
22
|
+
url: 'https://tldrsec.com/p/' + (p.slug || ''),
|
|
23
|
+
publishedAt: p.override_scheduled_at || p.created_at || '',
|
|
24
|
+
excerpt: p.web_subtitle || p.meta_default_description || '',
|
|
25
|
+
authors: (p.authors || []).map((a) => a.name).join(', '),
|
|
26
|
+
tags: (p.content_tags || []).map((t) => t.display).join(', '),
|
|
27
|
+
}));
|