@tenderprompt/cli 0.1.11 → 0.1.12
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/README.md +9 -8
- package/dist/index.js +128 -266
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ tender app analytics suggestions artifact_123 --range 30d --json
|
|
|
169
169
|
|
|
170
170
|
tender app analytics charts templates --json
|
|
171
171
|
|
|
172
|
-
tender app analytics
|
|
172
|
+
tender app analytics properties list artifact_123 --json
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
Safe write previews:
|
|
@@ -177,7 +177,7 @@ Safe write previews:
|
|
|
177
177
|
```bash
|
|
178
178
|
tender app analytics dashboards artifact_123 --create "Agent dashboard" --dry-run --json
|
|
179
179
|
|
|
180
|
-
tender app analytics
|
|
180
|
+
tender app analytics properties activate artifact_123 \
|
|
181
181
|
--event signup_started \
|
|
182
182
|
--property plan \
|
|
183
183
|
--type dimension \
|
|
@@ -217,11 +217,12 @@ inspection. For example, inspect where the app calls
|
|
|
217
217
|
`__TP_ANALYTICS.invoke(...)`, propose a chart spec, validate it with
|
|
218
218
|
`analytics query`, and only then create a saved chart.
|
|
219
219
|
Use `charts templates --json` for reusable chart shapes; adapt any placeholders
|
|
220
|
-
to observed events, paths, or
|
|
221
|
-
Property group-bys and property metrics need
|
|
222
|
-
and `charts update` activate
|
|
223
|
-
|
|
224
|
-
`
|
|
220
|
+
to observed events, paths, or queryable property keys before querying or saving.
|
|
221
|
+
Property group-bys and property metrics need the custom event property to be
|
|
222
|
+
available for dashboard queries; `charts create` and `charts update` activate
|
|
223
|
+
missing properties automatically when the spec includes an `event_name = ...`
|
|
224
|
+
filter. `analytics query` is read-only, so use
|
|
225
|
+
`properties activate` first when trying an ad hoc property query. When a
|
|
225
226
|
query fails for a missing dashboard-query property, the CLI prints the exact
|
|
226
227
|
activation commands to run and does not perform that write automatically.
|
|
227
228
|
|
|
@@ -237,7 +238,7 @@ activation commands to run and does not perform that write automatically.
|
|
|
237
238
|
remote URLs.
|
|
238
239
|
- Analytics commands use tenant/artifact-scoped API routes. They do not expose
|
|
239
240
|
raw query credentials or raw SQL.
|
|
240
|
-
-
|
|
241
|
+
- Dashboard-query property activation is an explicit analytics write and remains
|
|
241
242
|
tenant/artifact-scoped.
|
|
242
243
|
- Raw analytics event export is intentionally not available; exports are bounded
|
|
243
244
|
catalog metadata or validated aggregate query rows.
|
package/dist/index.js
CHANGED
|
@@ -213,10 +213,10 @@ Commands:
|
|
|
213
213
|
Update a saved chart title or spec
|
|
214
214
|
tender app analytics charts delete <app-id>
|
|
215
215
|
Delete a saved chart
|
|
216
|
-
tender app analytics
|
|
217
|
-
List
|
|
218
|
-
tender app analytics
|
|
219
|
-
|
|
216
|
+
tender app analytics properties list <app-id>
|
|
217
|
+
List properties available to dashboard queries
|
|
218
|
+
tender app analytics properties activate <app-id>
|
|
219
|
+
Make a custom event property queryable
|
|
220
220
|
tender app context fetch <app-id>
|
|
221
221
|
Fetch AGENTS.md, skills, and Tender App scaffold files
|
|
222
222
|
tender app context status <app-id>
|
|
@@ -255,8 +255,8 @@ Examples:
|
|
|
255
255
|
tender app analytics charts list artifact_123 --dashboard analytics_dashboard_123 --json
|
|
256
256
|
tender app analytics charts update artifact_123 --chart analytics_chart_123 --title "Signup funnel" --spec funnel.json --dry-run --json
|
|
257
257
|
tender app analytics charts delete artifact_123 --chart analytics_chart_123 --dry-run --json
|
|
258
|
-
tender app analytics
|
|
259
|
-
tender app analytics
|
|
258
|
+
tender app analytics properties list artifact_123 --json
|
|
259
|
+
tender app analytics properties activate artifact_123 --event signup_started --property plan --type dimension --dry-run --json
|
|
260
260
|
tender app context fetch artifact_123 --dir ./widget --dry-run --json
|
|
261
261
|
tender app context status artifact_123 --dir ./widget --json
|
|
262
262
|
tender app context refresh artifact_123 --dir ./widget --dry-run --json
|
|
@@ -294,8 +294,8 @@ Commands:
|
|
|
294
294
|
tender app analytics charts list <app-id> List saved charts in one dashboard
|
|
295
295
|
tender app analytics charts update <app-id> Update a saved chart
|
|
296
296
|
tender app analytics charts delete <app-id> Delete a saved chart
|
|
297
|
-
tender app analytics
|
|
298
|
-
tender app analytics
|
|
297
|
+
tender app analytics properties list <app-id> List queryable custom event properties
|
|
298
|
+
tender app analytics properties activate <app-id> Make a property queryable
|
|
299
299
|
|
|
300
300
|
Examples:
|
|
301
301
|
tender app analytics summary artifact_123 --range 30d --json
|
|
@@ -311,8 +311,8 @@ Examples:
|
|
|
311
311
|
tender app analytics charts list artifact_123 --dashboard analytics_dashboard_123 --json
|
|
312
312
|
tender app analytics charts update artifact_123 --chart analytics_chart_123 --title "Signup funnel" --spec funnel.json --dry-run --json
|
|
313
313
|
tender app analytics charts delete artifact_123 --chart analytics_chart_123 --dry-run --json
|
|
314
|
-
tender app analytics
|
|
315
|
-
tender app analytics
|
|
314
|
+
tender app analytics properties list artifact_123 --json
|
|
315
|
+
tender app analytics properties activate artifact_123 --event signup_started --property plan --type dimension --dry-run --json`;
|
|
316
316
|
}
|
|
317
317
|
function analyticsSummaryHelp() {
|
|
318
318
|
return `Usage: tender app analytics summary <app-id> [--range <7d|30d|90d|YYYY-MM-DD..YYYY-MM-DD>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
@@ -388,7 +388,7 @@ Examples:
|
|
|
388
388
|
function analyticsChartsCreateHelp() {
|
|
389
389
|
return `Usage: tender app analytics charts create <app-id> --dashboard <dashboard-id> --title <title> --spec <file|-> [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
390
390
|
|
|
391
|
-
Property charts automatically
|
|
391
|
+
Property charts automatically make required custom event properties queryable before
|
|
392
392
|
saving when the spec has an event_name = filter.
|
|
393
393
|
|
|
394
394
|
Examples:
|
|
@@ -406,7 +406,7 @@ function analyticsChartsUpdateHelp() {
|
|
|
406
406
|
|
|
407
407
|
At least one of --title or --spec is required. When one is omitted, the CLI reads
|
|
408
408
|
the existing saved chart and keeps that value.
|
|
409
|
-
Property charts automatically
|
|
409
|
+
Property charts automatically make required custom event properties queryable before
|
|
410
410
|
saving when the spec has an event_name = filter.
|
|
411
411
|
|
|
412
412
|
Examples:
|
|
@@ -421,19 +421,19 @@ Examples:
|
|
|
421
421
|
tender app analytics charts delete artifact_123 --chart analytics_chart_123 --dry-run --json
|
|
422
422
|
tender app analytics charts delete artifact_123 --chart analytics_chart_123 --json`;
|
|
423
423
|
}
|
|
424
|
-
function
|
|
425
|
-
return `Usage: tender app analytics
|
|
424
|
+
function analyticsPropertiesListHelp() {
|
|
425
|
+
return `Usage: tender app analytics properties list <app-id> [--event <event-name>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
426
426
|
|
|
427
427
|
Examples:
|
|
428
|
-
tender app analytics
|
|
429
|
-
tender app analytics
|
|
428
|
+
tender app analytics properties list artifact_123 --json
|
|
429
|
+
tender app analytics properties list artifact_123 --event signup_started --json`;
|
|
430
430
|
}
|
|
431
|
-
function
|
|
432
|
-
return `Usage: tender app analytics
|
|
431
|
+
function analyticsPropertiesActivateHelp() {
|
|
432
|
+
return `Usage: tender app analytics properties activate <app-id> --event <event-name> --property <property-key> --type <dimension|metric> [--label <label>] [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
433
433
|
|
|
434
434
|
Examples:
|
|
435
|
-
tender app analytics
|
|
436
|
-
tender app analytics
|
|
435
|
+
tender app analytics properties activate artifact_123 --event signup_started --property plan --type dimension --dry-run --json
|
|
436
|
+
tender app analytics properties activate artifact_123 --event score_saved --property score --type metric --json`;
|
|
437
437
|
}
|
|
438
438
|
function artifactsListHelp() {
|
|
439
439
|
return `Usage: tender app list [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
@@ -816,8 +816,8 @@ function tenderCliCapabilities() {
|
|
|
816
816
|
"tender app analytics charts templates --json",
|
|
817
817
|
"tender app analytics query <artifact-id> --spec chart.json --json",
|
|
818
818
|
"tender app analytics export query <artifact-id> --spec chart.json --format csv",
|
|
819
|
-
"tender app analytics
|
|
820
|
-
"tender app analytics
|
|
819
|
+
"tender app analytics properties list <artifact-id> --json",
|
|
820
|
+
"tender app analytics properties activate <artifact-id> --event <event-name> --property <property-key> --type dimension --dry-run --json",
|
|
821
821
|
"tender app analytics dashboards <artifact-id> --create \"Agent dashboard\" --dry-run --json",
|
|
822
822
|
"tender app analytics charts create <artifact-id> --dashboard <dashboard-id> --title <title> --spec chart.json --dry-run --json",
|
|
823
823
|
"tender app analytics charts list <artifact-id> --dashboard <dashboard-id> --json",
|
|
@@ -827,8 +827,8 @@ function tenderCliCapabilities() {
|
|
|
827
827
|
notes: [
|
|
828
828
|
"Combine CLI capabilities with local source inspection of analytics calls.",
|
|
829
829
|
"Validate chart specs with query before creating or updating saved charts.",
|
|
830
|
-
"Property chart create/update commands automatically
|
|
831
|
-
"Ad hoc query is read-only; if it reports a missing property
|
|
830
|
+
"Property chart create/update commands automatically make missing custom event properties queryable when the spec has an event_name = filter.",
|
|
831
|
+
"Ad hoc query is read-only; if it reports a missing dashboard-query property, activate the property first or save the chart through charts create/update.",
|
|
832
832
|
"Use list before writes so agents can avoid duplicates and explain the exact chart they are changing.",
|
|
833
833
|
],
|
|
834
834
|
},
|
|
@@ -886,14 +886,14 @@ function tenderCliCapabilities() {
|
|
|
886
886
|
writes: false,
|
|
887
887
|
},
|
|
888
888
|
{
|
|
889
|
-
command: "tender app analytics
|
|
890
|
-
purpose: "List
|
|
889
|
+
command: "tender app analytics properties list <artifact-id> --json",
|
|
890
|
+
purpose: "List custom event properties available to dashboard queries.",
|
|
891
891
|
requiresAuth: true,
|
|
892
892
|
writes: false,
|
|
893
893
|
},
|
|
894
894
|
{
|
|
895
|
-
command: "tender app analytics
|
|
896
|
-
purpose: "Preview or activate the
|
|
895
|
+
command: "tender app analytics properties activate <artifact-id> --event <event-name> --property <property-key> --type <dimension|metric> --dry-run --json",
|
|
896
|
+
purpose: "Preview or activate the custom event property needed for a property group-by or property metric chart.",
|
|
897
897
|
requiresAuth: true,
|
|
898
898
|
writes: true,
|
|
899
899
|
dryRun: true,
|
|
@@ -2938,13 +2938,13 @@ function analyticsChartTemplates() {
|
|
|
2938
2938
|
id: "property_breakdown",
|
|
2939
2939
|
title: "Property breakdown",
|
|
2940
2940
|
visualization: "bar",
|
|
2941
|
-
purpose: "Compare a
|
|
2941
|
+
purpose: "Compare a queryable dimension property observed in events.",
|
|
2942
2942
|
usableAsIs: false,
|
|
2943
2943
|
placeholders: {
|
|
2944
|
-
property: "<
|
|
2944
|
+
property: "<queryable_dimension_property>",
|
|
2945
2945
|
},
|
|
2946
2946
|
adaptWith: [
|
|
2947
|
-
"Use a property key
|
|
2947
|
+
"Use a queryable property key from capabilities chartSpec.groupBy, such as property:plan.",
|
|
2948
2948
|
"Choose stable categorical properties with enough observations to compare.",
|
|
2949
2949
|
],
|
|
2950
2950
|
spec: {
|
|
@@ -2952,7 +2952,7 @@ function analyticsChartTemplates() {
|
|
|
2952
2952
|
dataset: "events",
|
|
2953
2953
|
visualization: "bar",
|
|
2954
2954
|
metric: { name: "custom_event_count" },
|
|
2955
|
-
groupBy: [{ field: "property:<
|
|
2955
|
+
groupBy: [{ field: "property:<queryable_dimension_property>" }],
|
|
2956
2956
|
filters: [],
|
|
2957
2957
|
range: { preset: "30d" },
|
|
2958
2958
|
sort: [{ field: "value", direction: "desc" }],
|
|
@@ -2966,17 +2966,17 @@ function analyticsChartTemplates() {
|
|
|
2966
2966
|
purpose: "Track an observed numeric event property over time.",
|
|
2967
2967
|
usableAsIs: false,
|
|
2968
2968
|
placeholders: {
|
|
2969
|
-
metric: "avg:<
|
|
2969
|
+
metric: "avg:<queryable_metric_property>",
|
|
2970
2970
|
},
|
|
2971
2971
|
adaptWith: [
|
|
2972
|
-
"Use a numeric property key
|
|
2972
|
+
"Use a queryable numeric property key from capabilities chartSpec.metrics.",
|
|
2973
2973
|
"Prefer averages for scores, durations, quantities, or ordinal values.",
|
|
2974
2974
|
],
|
|
2975
2975
|
spec: {
|
|
2976
2976
|
version: 1,
|
|
2977
2977
|
dataset: "events",
|
|
2978
2978
|
visualization: "line",
|
|
2979
|
-
metric: { name: "avg:<
|
|
2979
|
+
metric: { name: "avg:<queryable_metric_property>" },
|
|
2980
2980
|
groupBy: [{ field: "day" }],
|
|
2981
2981
|
filters: [],
|
|
2982
2982
|
range: { preset: "30d" },
|
|
@@ -3019,7 +3019,7 @@ function runAnalyticsChartsTemplates(command, io) {
|
|
|
3019
3019
|
templates,
|
|
3020
3020
|
next: [
|
|
3021
3021
|
"Run tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json.",
|
|
3022
|
-
"Choose a template and replace placeholders with observed events, paths, or
|
|
3022
|
+
"Choose a template and replace placeholders with observed events, paths, or queryable property keys.",
|
|
3023
3023
|
"Validate with tender app analytics query <artifact-id> --spec chart.json --json.",
|
|
3024
3024
|
"Preview saved writes with tender app analytics dashboards ... --dry-run and charts create ... --dry-run.",
|
|
3025
3025
|
],
|
|
@@ -3206,13 +3206,13 @@ function parseAnalyticsChartsDeleteArgs(args) {
|
|
|
3206
3206
|
...parsed,
|
|
3207
3207
|
};
|
|
3208
3208
|
}
|
|
3209
|
-
function
|
|
3209
|
+
function parseAnalyticsPropertiesListArgs(args) {
|
|
3210
3210
|
if (args.includes("--help") || args.includes("-h")) {
|
|
3211
|
-
return { command: "help", topic: "app analytics
|
|
3211
|
+
return { command: "help", topic: "app analytics properties list" };
|
|
3212
3212
|
}
|
|
3213
3213
|
const artifactId = args[0];
|
|
3214
3214
|
if (!artifactId || artifactId.startsWith("-")) {
|
|
3215
|
-
throw new TenderCliUsageError("app id is required. Example: tender app analytics
|
|
3215
|
+
throw new TenderCliUsageError("app id is required. Example: tender app analytics properties list <app-id> --json");
|
|
3216
3216
|
}
|
|
3217
3217
|
const parsed = parseAnalyticsCommonArgs(args, 1);
|
|
3218
3218
|
let eventName = null;
|
|
@@ -3223,28 +3223,27 @@ function parseAnalyticsPropertySlotsListArgs(args) {
|
|
|
3223
3223
|
index += 1;
|
|
3224
3224
|
continue;
|
|
3225
3225
|
}
|
|
3226
|
-
throw new TenderCliUsageError(`Unknown analytics
|
|
3226
|
+
throw new TenderCliUsageError(`Unknown analytics properties list option: ${arg}`);
|
|
3227
3227
|
}
|
|
3228
3228
|
return {
|
|
3229
|
-
command: "app analytics
|
|
3229
|
+
command: "app analytics properties list",
|
|
3230
3230
|
artifactId,
|
|
3231
3231
|
eventName,
|
|
3232
3232
|
...parsed,
|
|
3233
3233
|
};
|
|
3234
3234
|
}
|
|
3235
|
-
function
|
|
3235
|
+
function parseAnalyticsPropertiesActivateArgs(args) {
|
|
3236
3236
|
if (args.includes("--help") || args.includes("-h")) {
|
|
3237
|
-
return { command: "help", topic: "app analytics
|
|
3237
|
+
return { command: "help", topic: "app analytics properties activate" };
|
|
3238
3238
|
}
|
|
3239
3239
|
const artifactId = args[0];
|
|
3240
3240
|
if (!artifactId || artifactId.startsWith("-")) {
|
|
3241
|
-
throw new TenderCliUsageError("app id is required. Example: tender app analytics
|
|
3241
|
+
throw new TenderCliUsageError("app id is required. Example: tender app analytics properties activate <app-id> --event <event-name> --property <property-key> --type dimension --json");
|
|
3242
3242
|
}
|
|
3243
3243
|
const parsed = parseAnalyticsCommonArgs(args, 1);
|
|
3244
3244
|
let eventName = null;
|
|
3245
3245
|
let propertyKey = null;
|
|
3246
|
-
let
|
|
3247
|
-
let slotName = null;
|
|
3246
|
+
let propertyType = null;
|
|
3248
3247
|
let label = null;
|
|
3249
3248
|
let dryRun = false;
|
|
3250
3249
|
for (let index = 0; index < parsed.remaining.length; index += 1) {
|
|
@@ -3264,12 +3263,7 @@ function parseAnalyticsPropertySlotsActivateArgs(args) {
|
|
|
3264
3263
|
if (value !== "dimension" && value !== "metric") {
|
|
3265
3264
|
throw new TenderCliUsageError("--type must be dimension or metric.");
|
|
3266
3265
|
}
|
|
3267
|
-
|
|
3268
|
-
index += 1;
|
|
3269
|
-
continue;
|
|
3270
|
-
}
|
|
3271
|
-
if (arg === "--slot") {
|
|
3272
|
-
slotName = parseRequiredFlagValue(parsed.remaining[index + 1], "--slot");
|
|
3266
|
+
propertyType = value;
|
|
3273
3267
|
index += 1;
|
|
3274
3268
|
continue;
|
|
3275
3269
|
}
|
|
@@ -3282,18 +3276,17 @@ function parseAnalyticsPropertySlotsActivateArgs(args) {
|
|
|
3282
3276
|
dryRun = true;
|
|
3283
3277
|
continue;
|
|
3284
3278
|
}
|
|
3285
|
-
throw new TenderCliUsageError(`Unknown analytics
|
|
3279
|
+
throw new TenderCliUsageError(`Unknown analytics properties activate option: ${arg}`);
|
|
3286
3280
|
}
|
|
3287
|
-
if (!eventName || !propertyKey || !
|
|
3288
|
-
throw new TenderCliUsageError("--event, --property, and --type are required. Example: tender app analytics
|
|
3281
|
+
if (!eventName || !propertyKey || !propertyType) {
|
|
3282
|
+
throw new TenderCliUsageError("--event, --property, and --type are required. Example: tender app analytics properties activate artifact_123 --event signup_started --property plan --type dimension --json");
|
|
3289
3283
|
}
|
|
3290
3284
|
return {
|
|
3291
|
-
command: "app analytics
|
|
3285
|
+
command: "app analytics properties activate",
|
|
3292
3286
|
artifactId,
|
|
3293
3287
|
eventName,
|
|
3294
3288
|
propertyKey,
|
|
3295
|
-
|
|
3296
|
-
slotName,
|
|
3289
|
+
propertyType,
|
|
3297
3290
|
label,
|
|
3298
3291
|
dryRun,
|
|
3299
3292
|
...parsed,
|
|
@@ -3383,21 +3376,21 @@ function parseTenderArgs(args) {
|
|
|
3383
3376
|
return parseAnalyticsDashboardsArgs(resourceArgs.slice(3));
|
|
3384
3377
|
}
|
|
3385
3378
|
if (resourceArgs[1] === "analytics" &&
|
|
3386
|
-
resourceArgs[2] === "
|
|
3379
|
+
resourceArgs[2] === "properties" &&
|
|
3387
3380
|
(resourceArgs[3] === undefined ||
|
|
3388
3381
|
resourceArgs[3] === "--help" ||
|
|
3389
3382
|
resourceArgs[3] === "-h")) {
|
|
3390
|
-
return { command: "help", topic: "app analytics
|
|
3383
|
+
return { command: "help", topic: "app analytics properties list" };
|
|
3391
3384
|
}
|
|
3392
3385
|
if (resourceArgs[1] === "analytics" &&
|
|
3393
|
-
resourceArgs[2] === "
|
|
3386
|
+
resourceArgs[2] === "properties" &&
|
|
3394
3387
|
resourceArgs[3] === "list") {
|
|
3395
|
-
return
|
|
3388
|
+
return parseAnalyticsPropertiesListArgs(resourceArgs.slice(4));
|
|
3396
3389
|
}
|
|
3397
3390
|
if (resourceArgs[1] === "analytics" &&
|
|
3398
|
-
resourceArgs[2] === "
|
|
3391
|
+
resourceArgs[2] === "properties" &&
|
|
3399
3392
|
resourceArgs[3] === "activate") {
|
|
3400
|
-
return
|
|
3393
|
+
return parseAnalyticsPropertiesActivateArgs(resourceArgs.slice(4));
|
|
3401
3394
|
}
|
|
3402
3395
|
if (resourceArgs[1] === "analytics" &&
|
|
3403
3396
|
resourceArgs[2] === "export" &&
|
|
@@ -3859,8 +3852,8 @@ function analyticsCorrectedExample(artifactId, analyticsPath) {
|
|
|
3859
3852
|
if (analyticsPath === "suggestions") {
|
|
3860
3853
|
return `tender app analytics suggestions ${artifactId} --range 30d --json`;
|
|
3861
3854
|
}
|
|
3862
|
-
if (analyticsPath === "
|
|
3863
|
-
return `tender app analytics
|
|
3855
|
+
if (analyticsPath === "properties") {
|
|
3856
|
+
return `tender app analytics properties list ${artifactId} --json`;
|
|
3864
3857
|
}
|
|
3865
3858
|
if (analyticsPath === "dashboards") {
|
|
3866
3859
|
return `tender app analytics dashboards ${artifactId} --json`;
|
|
@@ -3877,6 +3870,10 @@ function readCliStringField(record, field) {
|
|
|
3877
3870
|
const value = record[field];
|
|
3878
3871
|
return typeof value === "string" ? value : null;
|
|
3879
3872
|
}
|
|
3873
|
+
function readCliBooleanField(record, field) {
|
|
3874
|
+
const value = record[field];
|
|
3875
|
+
return typeof value === "boolean" ? value : false;
|
|
3876
|
+
}
|
|
3880
3877
|
function readAnalyticsDashboardRecords(payload) {
|
|
3881
3878
|
return Array.isArray(payload.dashboards)
|
|
3882
3879
|
? payload.dashboards.filter(isCliJsonRecord)
|
|
@@ -3912,9 +3909,9 @@ function readAnalyticsChartSpec(chart) {
|
|
|
3912
3909
|
function readAnalyticsChartLayout(chart) {
|
|
3913
3910
|
return isCliJsonRecord(chart.layout) ? chart.layout : {};
|
|
3914
3911
|
}
|
|
3915
|
-
function
|
|
3916
|
-
return Array.isArray(payload.
|
|
3917
|
-
? payload.
|
|
3912
|
+
function readAnalyticsPropertyRecords(payload) {
|
|
3913
|
+
return Array.isArray(payload.properties)
|
|
3914
|
+
? payload.properties.filter(isCliJsonRecord)
|
|
3918
3915
|
: [];
|
|
3919
3916
|
}
|
|
3920
3917
|
function readAnalyticsSpecEventNameFilter(spec) {
|
|
@@ -3940,34 +3937,34 @@ function readAnalyticsSpecGroupField(spec) {
|
|
|
3940
3937
|
const [group] = spec.groupBy.filter(isCliJsonRecord);
|
|
3941
3938
|
return group ? readCliStringField(group, "field") : null;
|
|
3942
3939
|
}
|
|
3943
|
-
function
|
|
3940
|
+
function readRequiredAnalyticsPropertiesFromSpec(spec) {
|
|
3944
3941
|
const eventName = readAnalyticsSpecEventNameFilter(spec);
|
|
3945
3942
|
const requirements = [];
|
|
3946
3943
|
const groupField = readAnalyticsSpecGroupField(spec);
|
|
3947
3944
|
if (groupField?.startsWith("property:")) {
|
|
3948
3945
|
if (!eventName) {
|
|
3949
|
-
throw new TenderCliUsageError("Property group-by chart specs require an event_name = filter so the CLI can
|
|
3946
|
+
throw new TenderCliUsageError("Property group-by chart specs require an event_name = filter so the CLI can make the property available to dashboard queries.");
|
|
3950
3947
|
}
|
|
3951
3948
|
requirements.push({
|
|
3952
3949
|
eventName,
|
|
3953
3950
|
propertyKey: groupField.slice("property:".length),
|
|
3954
|
-
|
|
3951
|
+
propertyType: "dimension",
|
|
3955
3952
|
});
|
|
3956
3953
|
}
|
|
3957
3954
|
const metricName = readAnalyticsSpecMetricName(spec);
|
|
3958
3955
|
if (metricName?.startsWith("sum:") || metricName?.startsWith("avg:")) {
|
|
3959
3956
|
if (!eventName) {
|
|
3960
|
-
throw new TenderCliUsageError("Property metric chart specs require an event_name = filter so the CLI can
|
|
3957
|
+
throw new TenderCliUsageError("Property metric chart specs require an event_name = filter so the CLI can make the property available to dashboard queries.");
|
|
3961
3958
|
}
|
|
3962
3959
|
requirements.push({
|
|
3963
3960
|
eventName,
|
|
3964
3961
|
propertyKey: metricName.slice(metricName.indexOf(":") + 1),
|
|
3965
|
-
|
|
3962
|
+
propertyType: "metric",
|
|
3966
3963
|
});
|
|
3967
3964
|
}
|
|
3968
3965
|
const seen = new Set();
|
|
3969
3966
|
return requirements.filter((requirement) => {
|
|
3970
|
-
const key = `${requirement.
|
|
3967
|
+
const key = `${requirement.propertyType}:${requirement.eventName}:${requirement.propertyKey}`;
|
|
3971
3968
|
if (seen.has(key)) {
|
|
3972
3969
|
return false;
|
|
3973
3970
|
}
|
|
@@ -3975,107 +3972,22 @@ function readRequiredAnalyticsPropertySlotsFromSpec(spec) {
|
|
|
3975
3972
|
return true;
|
|
3976
3973
|
});
|
|
3977
3974
|
}
|
|
3978
|
-
function
|
|
3979
|
-
return slotType === "dimension"
|
|
3980
|
-
? Array.from({ length: 13 }, (_, index) => `blob${index + 8}`)
|
|
3981
|
-
: Array.from({ length: 19 }, (_, index) => `double${index + 2}`);
|
|
3982
|
-
}
|
|
3983
|
-
function isValidAnalyticsPropertySlotName(input) {
|
|
3984
|
-
return analyticsPropertySlotNames(input.slotType).includes(input.slotName);
|
|
3985
|
-
}
|
|
3986
|
-
function findExistingAnalyticsPropertySlot(input) {
|
|
3987
|
-
return (input.propertySlots.find((slot) => readCliStringField(slot, "status") === "active" &&
|
|
3988
|
-
readCliStringField(slot, "eventName") === input.requirement.eventName &&
|
|
3989
|
-
readCliStringField(slot, "propertyKey") === input.requirement.propertyKey &&
|
|
3990
|
-
readCliStringField(slot, "slotType") === input.requirement.slotType) ?? null);
|
|
3991
|
-
}
|
|
3992
|
-
function chooseAnalyticsPropertySlotName(input) {
|
|
3993
|
-
if (input.requestedSlotName) {
|
|
3994
|
-
if (!isValidAnalyticsPropertySlotName({
|
|
3995
|
-
slotType: input.requirement.slotType,
|
|
3996
|
-
slotName: input.requestedSlotName,
|
|
3997
|
-
})) {
|
|
3998
|
-
throw new TenderCliUsageError(`--slot must be a valid ${input.requirement.slotType} analytics slot.`);
|
|
3999
|
-
}
|
|
4000
|
-
const conflictingSlot = input.propertySlots.find((slot) => readCliStringField(slot, "status") === "active" &&
|
|
4001
|
-
readCliStringField(slot, "eventName") === input.requirement.eventName &&
|
|
4002
|
-
readCliStringField(slot, "slotType") === input.requirement.slotType &&
|
|
4003
|
-
readCliStringField(slot, "slotName") === input.requestedSlotName &&
|
|
4004
|
-
readCliStringField(slot, "propertyKey") !== input.requirement.propertyKey);
|
|
4005
|
-
if (conflictingSlot) {
|
|
4006
|
-
throw new TenderCliUsageError(`--slot ${input.requestedSlotName} is already active for another ${input.requirement.slotType} property on ${input.requirement.eventName}.`);
|
|
4007
|
-
}
|
|
4008
|
-
return input.requestedSlotName;
|
|
4009
|
-
}
|
|
4010
|
-
const usedSlots = new Set(input.propertySlots
|
|
4011
|
-
.filter((slot) => readCliStringField(slot, "status") === "active" &&
|
|
4012
|
-
readCliStringField(slot, "eventName") === input.requirement.eventName &&
|
|
4013
|
-
readCliStringField(slot, "slotType") === input.requirement.slotType)
|
|
4014
|
-
.map((slot) => readCliStringField(slot, "slotName"))
|
|
4015
|
-
.filter((slotName) => Boolean(slotName)));
|
|
4016
|
-
const slotName = analyticsPropertySlotNames(input.requirement.slotType).find((candidate) => !usedSlots.has(candidate));
|
|
4017
|
-
if (!slotName) {
|
|
4018
|
-
throw new Error("analytics_property_slots_full");
|
|
4019
|
-
}
|
|
4020
|
-
return slotName;
|
|
4021
|
-
}
|
|
4022
|
-
async function fetchAnalyticsPropertySlots(input) {
|
|
4023
|
-
const payload = await requestAnalyticsApi({
|
|
4024
|
-
artifactId: input.command.artifactId,
|
|
4025
|
-
analyticsPath: "property-slots",
|
|
4026
|
-
method: "GET",
|
|
4027
|
-
baseUrl: input.credentials.baseUrl,
|
|
4028
|
-
token: input.credentials.token,
|
|
4029
|
-
fetcher: input.runtime.fetcher ?? fetch,
|
|
4030
|
-
});
|
|
4031
|
-
return { payload, propertySlots: readAnalyticsPropertySlotRecords(payload) };
|
|
4032
|
-
}
|
|
4033
|
-
async function ensureAnalyticsPropertySlots(input) {
|
|
3975
|
+
async function ensureAnalyticsProperties(input) {
|
|
4034
3976
|
if (input.requirements.length === 0) {
|
|
4035
3977
|
return [];
|
|
4036
3978
|
}
|
|
4037
|
-
const { propertySlots } = await fetchAnalyticsPropertySlots({
|
|
4038
|
-
command: input.command,
|
|
4039
|
-
credentials: input.credentials,
|
|
4040
|
-
runtime: input.runtime,
|
|
4041
|
-
});
|
|
4042
3979
|
const plan = [];
|
|
4043
3980
|
for (const requirement of input.requirements) {
|
|
4044
|
-
const existing = findExistingAnalyticsPropertySlot({
|
|
4045
|
-
propertySlots,
|
|
4046
|
-
requirement,
|
|
4047
|
-
});
|
|
4048
|
-
if (existing) {
|
|
4049
|
-
plan.push({
|
|
4050
|
-
...requirement,
|
|
4051
|
-
slotName: readCliStringField(existing, "slotName") ?? "",
|
|
4052
|
-
label: readCliStringField(existing, "label") ?? requirement.propertyKey,
|
|
4053
|
-
status: "existing",
|
|
4054
|
-
propertySlot: existing,
|
|
4055
|
-
});
|
|
4056
|
-
continue;
|
|
4057
|
-
}
|
|
4058
|
-
const slotName = chooseAnalyticsPropertySlotName({
|
|
4059
|
-
propertySlots,
|
|
4060
|
-
requirement,
|
|
4061
|
-
});
|
|
4062
3981
|
const body = {
|
|
4063
3982
|
eventName: requirement.eventName,
|
|
4064
3983
|
propertyKey: requirement.propertyKey,
|
|
4065
|
-
|
|
4066
|
-
slotName,
|
|
3984
|
+
propertyType: requirement.propertyType,
|
|
4067
3985
|
label: requirement.propertyKey,
|
|
3986
|
+
dryRun: input.dryRun,
|
|
4068
3987
|
};
|
|
4069
|
-
if (input.dryRun) {
|
|
4070
|
-
plan.push({
|
|
4071
|
-
...body,
|
|
4072
|
-
status: "planned",
|
|
4073
|
-
});
|
|
4074
|
-
continue;
|
|
4075
|
-
}
|
|
4076
3988
|
const payload = await requestAnalyticsApi({
|
|
4077
3989
|
artifactId: input.command.artifactId,
|
|
4078
|
-
analyticsPath: "
|
|
3990
|
+
analyticsPath: "properties",
|
|
4079
3991
|
method: "POST",
|
|
4080
3992
|
baseUrl: input.credentials.baseUrl,
|
|
4081
3993
|
token: input.credentials.token,
|
|
@@ -4083,17 +3995,16 @@ async function ensureAnalyticsPropertySlots(input) {
|
|
|
4083
3995
|
body,
|
|
4084
3996
|
});
|
|
4085
3997
|
plan.push({
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
status: "active",
|
|
3998
|
+
eventName: requirement.eventName,
|
|
3999
|
+
propertyKey: requirement.propertyKey,
|
|
4000
|
+
propertyType: requirement.propertyType,
|
|
4001
|
+
label: requirement.propertyKey,
|
|
4002
|
+
status: readCliBooleanField(payload, "alreadyActive")
|
|
4003
|
+
? "existing"
|
|
4004
|
+
: input.dryRun
|
|
4005
|
+
? "planned"
|
|
4006
|
+
: "activated",
|
|
4007
|
+
property: payload.property,
|
|
4097
4008
|
});
|
|
4098
4009
|
}
|
|
4099
4010
|
return plan;
|
|
@@ -4108,12 +4019,12 @@ function analyticsCommandAuthFlags(command) {
|
|
|
4108
4019
|
}
|
|
4109
4020
|
return flags;
|
|
4110
4021
|
}
|
|
4111
|
-
function
|
|
4022
|
+
function analyticsPropertyActivationCommand(input) {
|
|
4112
4023
|
return [
|
|
4113
4024
|
"tender",
|
|
4114
4025
|
"app",
|
|
4115
4026
|
"analytics",
|
|
4116
|
-
"
|
|
4027
|
+
"properties",
|
|
4117
4028
|
"activate",
|
|
4118
4029
|
shellQuote(input.command.artifactId),
|
|
4119
4030
|
"--event",
|
|
@@ -4121,16 +4032,16 @@ function analyticsPropertySlotActivationCommand(input) {
|
|
|
4121
4032
|
"--property",
|
|
4122
4033
|
shellQuote(input.requirement.propertyKey),
|
|
4123
4034
|
"--type",
|
|
4124
|
-
input.requirement.
|
|
4035
|
+
input.requirement.propertyType,
|
|
4125
4036
|
...(input.dryRun ? ["--dry-run"] : []),
|
|
4126
4037
|
...analyticsCommandAuthFlags(input.command),
|
|
4127
4038
|
"--json",
|
|
4128
4039
|
].join(" ");
|
|
4129
4040
|
}
|
|
4130
|
-
function
|
|
4041
|
+
function createAnalyticsPropertyGuidance(input) {
|
|
4131
4042
|
let requirements;
|
|
4132
4043
|
try {
|
|
4133
|
-
requirements =
|
|
4044
|
+
requirements = readRequiredAnalyticsPropertiesFromSpec(input.spec);
|
|
4134
4045
|
}
|
|
4135
4046
|
catch {
|
|
4136
4047
|
return null;
|
|
@@ -4142,11 +4053,11 @@ function createAnalyticsPropertySlotGuidance(input) {
|
|
|
4142
4053
|
"To make this chart available for dashboard queries, activate the custom event property first:",
|
|
4143
4054
|
];
|
|
4144
4055
|
for (const requirement of requirements) {
|
|
4145
|
-
lines.push(
|
|
4056
|
+
lines.push(analyticsPropertyActivationCommand({
|
|
4146
4057
|
command: input.command,
|
|
4147
4058
|
requirement,
|
|
4148
4059
|
dryRun: true,
|
|
4149
|
-
}),
|
|
4060
|
+
}), analyticsPropertyActivationCommand({
|
|
4150
4061
|
command: input.command,
|
|
4151
4062
|
requirement,
|
|
4152
4063
|
dryRun: false,
|
|
@@ -4172,8 +4083,8 @@ async function requestAnalyticsQueryWithPropertyGuidance(input) {
|
|
|
4172
4083
|
}
|
|
4173
4084
|
catch (error) {
|
|
4174
4085
|
if (error instanceof TenderCliAnalyticsApiError &&
|
|
4175
|
-
error.reasonCode === "
|
|
4176
|
-
const guidance =
|
|
4086
|
+
error.reasonCode === "analytics_property_not_queryable") {
|
|
4087
|
+
const guidance = createAnalyticsPropertyGuidance({
|
|
4177
4088
|
command: input.command,
|
|
4178
4089
|
spec: input.spec,
|
|
4179
4090
|
});
|
|
@@ -6380,93 +6291,43 @@ async function runAnalyticsExportQuery(command, io, runtime) {
|
|
|
6380
6291
|
io.stdout(JSON.stringify(payload, null, 2));
|
|
6381
6292
|
return 0;
|
|
6382
6293
|
}
|
|
6383
|
-
async function
|
|
6294
|
+
async function runAnalyticsPropertiesList(command, io, runtime) {
|
|
6384
6295
|
const credentials = await resolveAnalyticsCredentials(command, runtime);
|
|
6385
6296
|
const payload = await requestAnalyticsApi({
|
|
6386
6297
|
artifactId: command.artifactId,
|
|
6387
|
-
analyticsPath: "
|
|
6298
|
+
analyticsPath: "properties",
|
|
6388
6299
|
method: "GET",
|
|
6389
6300
|
baseUrl: credentials.baseUrl,
|
|
6390
6301
|
token: credentials.token,
|
|
6391
6302
|
fetcher: runtime.fetcher ?? fetch,
|
|
6392
6303
|
});
|
|
6393
|
-
const
|
|
6394
|
-
readCliStringField(
|
|
6304
|
+
const properties = readAnalyticsPropertyRecords(payload).filter((property) => !command.eventName ||
|
|
6305
|
+
readCliStringField(property, "eventName") === command.eventName);
|
|
6395
6306
|
printAnalyticsPayload(command, io, {
|
|
6396
6307
|
ok: true,
|
|
6397
6308
|
command: command.command,
|
|
6398
6309
|
artifactId: command.artifactId,
|
|
6399
6310
|
eventName: command.eventName,
|
|
6400
|
-
|
|
6311
|
+
properties,
|
|
6401
6312
|
}, [
|
|
6402
6313
|
`app_id: ${command.artifactId}`,
|
|
6403
6314
|
command.eventName ? `event: ${command.eventName}` : "event: all",
|
|
6404
|
-
`
|
|
6315
|
+
`properties: ${properties.length}`,
|
|
6405
6316
|
]);
|
|
6406
6317
|
return 0;
|
|
6407
6318
|
}
|
|
6408
|
-
async function
|
|
6319
|
+
async function runAnalyticsPropertiesActivate(command, io, runtime) {
|
|
6409
6320
|
const credentials = await resolveAnalyticsCredentials(command, runtime);
|
|
6410
|
-
const requirement = {
|
|
6411
|
-
eventName: command.eventName,
|
|
6412
|
-
propertyKey: command.propertyKey,
|
|
6413
|
-
slotType: command.slotType,
|
|
6414
|
-
};
|
|
6415
|
-
const { propertySlots } = await fetchAnalyticsPropertySlots({
|
|
6416
|
-
command,
|
|
6417
|
-
credentials,
|
|
6418
|
-
runtime,
|
|
6419
|
-
});
|
|
6420
|
-
const existing = findExistingAnalyticsPropertySlot({
|
|
6421
|
-
propertySlots,
|
|
6422
|
-
requirement,
|
|
6423
|
-
});
|
|
6424
|
-
if (existing) {
|
|
6425
|
-
const payload = {
|
|
6426
|
-
ok: true,
|
|
6427
|
-
command: command.command,
|
|
6428
|
-
artifactId: command.artifactId,
|
|
6429
|
-
alreadyActive: true,
|
|
6430
|
-
propertySlot: existing,
|
|
6431
|
-
};
|
|
6432
|
-
printAnalyticsPayload(command, io, payload, [
|
|
6433
|
-
`app_id: ${command.artifactId}`,
|
|
6434
|
-
"already_active: true",
|
|
6435
|
-
`slot_name: ${readCliStringField(existing, "slotName") ?? ""}`,
|
|
6436
|
-
]);
|
|
6437
|
-
return 0;
|
|
6438
|
-
}
|
|
6439
|
-
const slotName = chooseAnalyticsPropertySlotName({
|
|
6440
|
-
propertySlots,
|
|
6441
|
-
requirement,
|
|
6442
|
-
requestedSlotName: command.slotName,
|
|
6443
|
-
});
|
|
6444
6321
|
const request = {
|
|
6445
6322
|
eventName: command.eventName,
|
|
6446
6323
|
propertyKey: command.propertyKey,
|
|
6447
|
-
|
|
6448
|
-
slotName,
|
|
6324
|
+
propertyType: command.propertyType,
|
|
6449
6325
|
label: command.label ?? command.propertyKey,
|
|
6326
|
+
dryRun: command.dryRun,
|
|
6450
6327
|
};
|
|
6451
|
-
if (command.dryRun) {
|
|
6452
|
-
printAnalyticsPayload(command, io, {
|
|
6453
|
-
ok: true,
|
|
6454
|
-
command: command.command,
|
|
6455
|
-
dryRun: true,
|
|
6456
|
-
artifactId: command.artifactId,
|
|
6457
|
-
request,
|
|
6458
|
-
}, [
|
|
6459
|
-
`app_id: ${command.artifactId}`,
|
|
6460
|
-
`event: ${command.eventName}`,
|
|
6461
|
-
`property: ${command.propertyKey}`,
|
|
6462
|
-
`slot_name: ${slotName}`,
|
|
6463
|
-
"dry_run: true",
|
|
6464
|
-
]);
|
|
6465
|
-
return 0;
|
|
6466
|
-
}
|
|
6467
6328
|
const payload = await requestAnalyticsApi({
|
|
6468
6329
|
artifactId: command.artifactId,
|
|
6469
|
-
analyticsPath: "
|
|
6330
|
+
analyticsPath: "properties",
|
|
6470
6331
|
method: "POST",
|
|
6471
6332
|
baseUrl: credentials.baseUrl,
|
|
6472
6333
|
token: credentials.token,
|
|
@@ -6477,7 +6338,8 @@ async function runAnalyticsPropertySlotsActivate(command, io, runtime) {
|
|
|
6477
6338
|
`app_id: ${command.artifactId}`,
|
|
6478
6339
|
`event: ${command.eventName}`,
|
|
6479
6340
|
`property: ${command.propertyKey}`,
|
|
6480
|
-
`
|
|
6341
|
+
`type: ${command.propertyType}`,
|
|
6342
|
+
...(command.dryRun ? ["dry_run: true"] : []),
|
|
6481
6343
|
]);
|
|
6482
6344
|
return 0;
|
|
6483
6345
|
}
|
|
@@ -6492,16 +6354,16 @@ async function runAnalyticsChartsCreate(command, io, runtime) {
|
|
|
6492
6354
|
spec,
|
|
6493
6355
|
layout: {},
|
|
6494
6356
|
};
|
|
6495
|
-
const
|
|
6496
|
-
const credentials = !command.dryRun ||
|
|
6357
|
+
const requiredProperties = readRequiredAnalyticsPropertiesFromSpec(spec);
|
|
6358
|
+
const credentials = !command.dryRun || requiredProperties.length > 0
|
|
6497
6359
|
? await resolveAnalyticsCredentials(command, runtime)
|
|
6498
6360
|
: null;
|
|
6499
|
-
const
|
|
6500
|
-
? await
|
|
6361
|
+
const properties = credentials
|
|
6362
|
+
? await ensureAnalyticsProperties({
|
|
6501
6363
|
command,
|
|
6502
6364
|
credentials,
|
|
6503
6365
|
runtime,
|
|
6504
|
-
requirements:
|
|
6366
|
+
requirements: requiredProperties,
|
|
6505
6367
|
dryRun: command.dryRun,
|
|
6506
6368
|
})
|
|
6507
6369
|
: [];
|
|
@@ -6510,7 +6372,7 @@ async function runAnalyticsChartsCreate(command, io, runtime) {
|
|
|
6510
6372
|
ok: true,
|
|
6511
6373
|
dryRun: true,
|
|
6512
6374
|
artifactId: command.artifactId,
|
|
6513
|
-
|
|
6375
|
+
properties,
|
|
6514
6376
|
request: body,
|
|
6515
6377
|
};
|
|
6516
6378
|
printAnalyticsPayload(command, io, payload, [
|
|
@@ -6533,10 +6395,10 @@ async function runAnalyticsChartsCreate(command, io, runtime) {
|
|
|
6533
6395
|
fetcher: runtime.fetcher ?? fetch,
|
|
6534
6396
|
body,
|
|
6535
6397
|
});
|
|
6536
|
-
printAnalyticsPayload(command, io, { ...payload,
|
|
6398
|
+
printAnalyticsPayload(command, io, { ...payload, properties }, [
|
|
6537
6399
|
`app_id: ${command.artifactId}`,
|
|
6538
6400
|
`chart_id: ${String(payload.chart?.id ?? "")}`,
|
|
6539
|
-
`
|
|
6401
|
+
`properties: ${properties.length}`,
|
|
6540
6402
|
]);
|
|
6541
6403
|
return 0;
|
|
6542
6404
|
}
|
|
@@ -6583,11 +6445,11 @@ async function runAnalyticsChartsUpdate(command, io, runtime) {
|
|
|
6583
6445
|
spec,
|
|
6584
6446
|
layout: readAnalyticsChartLayout(existing.chart),
|
|
6585
6447
|
};
|
|
6586
|
-
const
|
|
6448
|
+
const properties = await ensureAnalyticsProperties({
|
|
6587
6449
|
command,
|
|
6588
6450
|
credentials,
|
|
6589
6451
|
runtime,
|
|
6590
|
-
requirements:
|
|
6452
|
+
requirements: readRequiredAnalyticsPropertiesFromSpec(spec),
|
|
6591
6453
|
dryRun: command.dryRun,
|
|
6592
6454
|
});
|
|
6593
6455
|
const dashboardId = readCliStringField(existing.dashboard, "id");
|
|
@@ -6599,7 +6461,7 @@ async function runAnalyticsChartsUpdate(command, io, runtime) {
|
|
|
6599
6461
|
chartId: command.chartId,
|
|
6600
6462
|
dashboardId,
|
|
6601
6463
|
currentChart: existing.chart,
|
|
6602
|
-
|
|
6464
|
+
properties,
|
|
6603
6465
|
request: body,
|
|
6604
6466
|
}, [
|
|
6605
6467
|
`app_id: ${command.artifactId}`,
|
|
@@ -6619,11 +6481,11 @@ async function runAnalyticsChartsUpdate(command, io, runtime) {
|
|
|
6619
6481
|
fetcher: runtime.fetcher ?? fetch,
|
|
6620
6482
|
body,
|
|
6621
6483
|
});
|
|
6622
|
-
printAnalyticsPayload(command, io, { ...payload,
|
|
6484
|
+
printAnalyticsPayload(command, io, { ...payload, properties }, [
|
|
6623
6485
|
`app_id: ${command.artifactId}`,
|
|
6624
6486
|
`chart_id: ${command.chartId}`,
|
|
6625
6487
|
`title: ${String(payload.chart?.title ?? title)}`,
|
|
6626
|
-
`
|
|
6488
|
+
`properties: ${properties.length}`,
|
|
6627
6489
|
]);
|
|
6628
6490
|
return 0;
|
|
6629
6491
|
}
|
|
@@ -6792,11 +6654,11 @@ export async function runTenderCli(args, io = {
|
|
|
6792
6654
|
else if (command.topic === "app analytics charts delete") {
|
|
6793
6655
|
io.stdout(analyticsChartsDeleteHelp());
|
|
6794
6656
|
}
|
|
6795
|
-
else if (command.topic === "app analytics
|
|
6796
|
-
io.stdout(
|
|
6657
|
+
else if (command.topic === "app analytics properties list") {
|
|
6658
|
+
io.stdout(analyticsPropertiesListHelp());
|
|
6797
6659
|
}
|
|
6798
|
-
else if (command.topic === "app analytics
|
|
6799
|
-
io.stdout(
|
|
6660
|
+
else if (command.topic === "app analytics properties activate") {
|
|
6661
|
+
io.stdout(analyticsPropertiesActivateHelp());
|
|
6800
6662
|
}
|
|
6801
6663
|
else if (command.topic === "app") {
|
|
6802
6664
|
io.stdout(appHelp());
|
|
@@ -6908,11 +6770,11 @@ export async function runTenderCli(args, io = {
|
|
|
6908
6770
|
if (command.command === "app analytics charts delete") {
|
|
6909
6771
|
return await runAnalyticsChartsDelete(command, io, runtime);
|
|
6910
6772
|
}
|
|
6911
|
-
if (command.command === "app analytics
|
|
6912
|
-
return await
|
|
6773
|
+
if (command.command === "app analytics properties list") {
|
|
6774
|
+
return await runAnalyticsPropertiesList(command, io, runtime);
|
|
6913
6775
|
}
|
|
6914
|
-
if (command.command === "app analytics
|
|
6915
|
-
return await
|
|
6776
|
+
if (command.command === "app analytics properties activate") {
|
|
6777
|
+
return await runAnalyticsPropertiesActivate(command, io, runtime);
|
|
6916
6778
|
}
|
|
6917
6779
|
if (command.command === "app git remote") {
|
|
6918
6780
|
return await runGitRemote(command, io, runtime);
|