@carthooks/arcubase-cli 0.1.22 → 0.1.23

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.
@@ -1082,6 +1082,27 @@ var userCommands = [
1082
1082
  ],
1083
1083
  "responseType": "GlobalActionEntryRespVO"
1084
1084
  },
1085
+ {
1086
+ "scope": "user",
1087
+ "module": "app",
1088
+ "functionName": "getAppDetail",
1089
+ "commandPath": [
1090
+ "app",
1091
+ "get"
1092
+ ],
1093
+ "method": "GET",
1094
+ "endpoint": "/api/apps/:id",
1095
+ "pathParams": [
1096
+ {
1097
+ "param": "id",
1098
+ "flag": "app-id"
1099
+ }
1100
+ ],
1101
+ "controller": "UserAction.AppDetail",
1102
+ "requestType": null,
1103
+ "queryParams": [],
1104
+ "responseType": "AppDetailRespVO"
1105
+ },
1085
1106
  {
1086
1107
  "scope": "user",
1087
1108
  "module": "dashboard",
@@ -18434,6 +18455,68 @@ var helpExamplesIndex = {
18434
18455
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
18435
18456
  "unsupported aggregate names fail local body validation before the request is sent"
18436
18457
  ]
18458
+ },
18459
+ {
18460
+ "title": "preview filtered distinct_count grouped by source",
18461
+ "body": {
18462
+ "dataSource": 2188891001,
18463
+ "dataSourceType": "entity",
18464
+ "dimensions": [
18465
+ {
18466
+ "IsField": true,
18467
+ "FieldID": 1004,
18468
+ "Name": "Source"
18469
+ }
18470
+ ],
18471
+ "conditions": {
18472
+ "mode": "and",
18473
+ "conditions": [
18474
+ {
18475
+ "column": ":1006",
18476
+ "operator": "$eq",
18477
+ "value": "yes"
18478
+ }
18479
+ ]
18480
+ },
18481
+ "measures": [
18482
+ {
18483
+ "FieldID": 1002,
18484
+ "Aggregate": "distinct_count",
18485
+ "Name": "Distinct Customers"
18486
+ }
18487
+ ]
18488
+ },
18489
+ "notes": [
18490
+ "use conditions, not filters, for chart data filtering",
18491
+ "for saved charts put the same condition set under options.charts.conditions",
18492
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
18493
+ ]
18494
+ }
18495
+ ]
18496
+ },
18497
+ "admin.widget.update-ingress-options": {
18498
+ "command": [
18499
+ "widget",
18500
+ "update-ingress-options"
18501
+ ],
18502
+ "examples": [
18503
+ {
18504
+ "title": "adjust an ingress list widget display configuration",
18505
+ "body": {
18506
+ "options": {
18507
+ "cond_follow": true,
18508
+ "cond_follow_tab": true,
18509
+ "cond_follow_cols": [
18510
+ ":1001",
18511
+ ":1002"
18512
+ ]
18513
+ }
18514
+ },
18515
+ "notes": [
18516
+ "use this only for widgets created with options.ingress_id",
18517
+ "do not use dashboard update-layout for ingress widgets",
18518
+ "verify with widget get after updating ingress options"
18519
+ ]
18437
18520
  }
18438
18521
  ]
18439
18522
  },
@@ -19775,16 +19858,38 @@ function buildBodyGuidance(requestType) {
19775
19858
  dataSource: 2188891001,
19776
19859
  dataSourceType: "entity",
19777
19860
  dimensions: [{ IsField: true, FieldID: 1004, Name: "Source" }],
19778
- measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }]
19861
+ measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }],
19862
+ conditions: { mode: "and", conditions: [{ column: ":1006", operator: "$eq", value: "yes" }] }
19779
19863
  },
19780
19864
  commonMistakes: [
19781
19865
  "widget preview-data body is the chart query itself",
19782
19866
  "do not send a saved widget object with id, entity_id, or options",
19783
19867
  "field dimensions with FieldID must set IsField:true",
19868
+ "use conditions, not filters, for chart data filtering",
19869
+ "do not retry without conditions and then hand-calculate filtered statistics",
19784
19870
  "unsupported aggregates are invalid; use sum, avg, max, min, count, or distinct_count"
19785
19871
  ],
19786
19872
  suggestions: [
19787
- `retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}'`
19873
+ `retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}'`,
19874
+ `conditional stats: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<source_field_id>,"Name":"Source"}],"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]},"measures":[{"FieldID":<customer_field_id>,"Aggregate":"distinct_count","Name":"Distinct Customers"}]}'`
19875
+ ]
19876
+ };
19877
+ }
19878
+ if (requestType === "AppNewWidgetsReqVO") {
19879
+ return {
19880
+ shapeHint: {
19881
+ type: "list",
19882
+ options: { ingress_id: 2188893001 }
19883
+ },
19884
+ commonMistakes: [
19885
+ "dashboard widgets use options.dashboard_id",
19886
+ "ingress widgets use options.ingress_id",
19887
+ "do not put entity_id at body top level or under options when creating a widget",
19888
+ "after creating an ingress widget, use widget update-ingress-options to adjust display configuration"
19889
+ ],
19890
+ suggestions: [
19891
+ `dashboard chart: arcubase-admin widget create --app-id <app_id> --body-json '{"type":"chart","options":{"dashboard_id":<dashboard_id>}}'`,
19892
+ `ingress list: arcubase-admin widget create --app-id <app_id> --body-json '{"type":"list","options":{"ingress_id":<ingress_id>}}'`
19788
19893
  ]
19789
19894
  };
19790
19895
  }
@@ -19797,14 +19902,38 @@ function buildBodyGuidance(requestType) {
19797
19902
  entity_id: 2188891001,
19798
19903
  dimensions: [{ IsField: true, FieldID: 1004, Name: "Source" }],
19799
19904
  measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }],
19905
+ conditions: { mode: "and", conditions: [{ column: ":1006", operator: "$eq", value: "yes" }] },
19800
19906
  type: "bar"
19801
19907
  }
19802
19908
  }
19803
19909
  },
19804
19910
  commonMistakes: [
19805
19911
  "dashboard chart config belongs in body.options.charts",
19912
+ "ingress/list display settings use widget update-ingress-options, not widget update",
19913
+ "do not put ingress_id, list, default_cols, page_size, or entry display settings in widget update",
19806
19914
  "field dimensions with FieldID must set IsField:true",
19915
+ "use options.charts.conditions, not filters, for chart data filtering",
19916
+ "do not retry without conditions and then hand-calculate filtered statistics",
19807
19917
  "verify persistence with widget get or widget list after update"
19918
+ ],
19919
+ suggestions: [
19920
+ `dashboard chart: arcubase-admin widget update --app-id <app_id> --widget-id <widget_id> --body-json '{"entity_id":<table_id>,"options":{"charts":{"entity_id":<table_id>,"dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}],"type":"bar"}}}'`,
19921
+ `ingress list display: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json '{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}'`
19922
+ ]
19923
+ };
19924
+ }
19925
+ if (requestType === "AppUpdateWidgetsIngressOptionsReqVO") {
19926
+ return {
19927
+ shapeHint: {
19928
+ options: { cond_follow: true, cond_follow_tab: true, cond_follow_cols: [":1001", ":1002"] }
19929
+ },
19930
+ commonMistakes: [
19931
+ "widget update-ingress-options is for ingress widgets, not dashboard chart widgets",
19932
+ "put display settings under body.options",
19933
+ "verify the ingress widget with widget get after update"
19934
+ ],
19935
+ suggestions: [
19936
+ `retry with: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json '{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}'`
19808
19937
  ]
19809
19938
  };
19810
19939
  }
@@ -1082,6 +1082,27 @@ var userCommands = [
1082
1082
  ],
1083
1083
  "responseType": "GlobalActionEntryRespVO"
1084
1084
  },
1085
+ {
1086
+ "scope": "user",
1087
+ "module": "app",
1088
+ "functionName": "getAppDetail",
1089
+ "commandPath": [
1090
+ "app",
1091
+ "get"
1092
+ ],
1093
+ "method": "GET",
1094
+ "endpoint": "/api/apps/:id",
1095
+ "pathParams": [
1096
+ {
1097
+ "param": "id",
1098
+ "flag": "app-id"
1099
+ }
1100
+ ],
1101
+ "controller": "UserAction.AppDetail",
1102
+ "requestType": null,
1103
+ "queryParams": [],
1104
+ "responseType": "AppDetailRespVO"
1105
+ },
1085
1106
  {
1086
1107
  "scope": "user",
1087
1108
  "module": "dashboard",
@@ -18434,6 +18455,68 @@ var helpExamplesIndex = {
18434
18455
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
18435
18456
  "unsupported aggregate names fail local body validation before the request is sent"
18436
18457
  ]
18458
+ },
18459
+ {
18460
+ "title": "preview filtered distinct_count grouped by source",
18461
+ "body": {
18462
+ "dataSource": 2188891001,
18463
+ "dataSourceType": "entity",
18464
+ "dimensions": [
18465
+ {
18466
+ "IsField": true,
18467
+ "FieldID": 1004,
18468
+ "Name": "Source"
18469
+ }
18470
+ ],
18471
+ "conditions": {
18472
+ "mode": "and",
18473
+ "conditions": [
18474
+ {
18475
+ "column": ":1006",
18476
+ "operator": "$eq",
18477
+ "value": "yes"
18478
+ }
18479
+ ]
18480
+ },
18481
+ "measures": [
18482
+ {
18483
+ "FieldID": 1002,
18484
+ "Aggregate": "distinct_count",
18485
+ "Name": "Distinct Customers"
18486
+ }
18487
+ ]
18488
+ },
18489
+ "notes": [
18490
+ "use conditions, not filters, for chart data filtering",
18491
+ "for saved charts put the same condition set under options.charts.conditions",
18492
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
18493
+ ]
18494
+ }
18495
+ ]
18496
+ },
18497
+ "admin.widget.update-ingress-options": {
18498
+ "command": [
18499
+ "widget",
18500
+ "update-ingress-options"
18501
+ ],
18502
+ "examples": [
18503
+ {
18504
+ "title": "adjust an ingress list widget display configuration",
18505
+ "body": {
18506
+ "options": {
18507
+ "cond_follow": true,
18508
+ "cond_follow_tab": true,
18509
+ "cond_follow_cols": [
18510
+ ":1001",
18511
+ ":1002"
18512
+ ]
18513
+ }
18514
+ },
18515
+ "notes": [
18516
+ "use this only for widgets created with options.ingress_id",
18517
+ "do not use dashboard update-layout for ingress widgets",
18518
+ "verify with widget get after updating ingress options"
18519
+ ]
18437
18520
  }
18438
18521
  ]
18439
18522
  },
@@ -19775,16 +19858,38 @@ function buildBodyGuidance(requestType) {
19775
19858
  dataSource: 2188891001,
19776
19859
  dataSourceType: "entity",
19777
19860
  dimensions: [{ IsField: true, FieldID: 1004, Name: "Source" }],
19778
- measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }]
19861
+ measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }],
19862
+ conditions: { mode: "and", conditions: [{ column: ":1006", operator: "$eq", value: "yes" }] }
19779
19863
  },
19780
19864
  commonMistakes: [
19781
19865
  "widget preview-data body is the chart query itself",
19782
19866
  "do not send a saved widget object with id, entity_id, or options",
19783
19867
  "field dimensions with FieldID must set IsField:true",
19868
+ "use conditions, not filters, for chart data filtering",
19869
+ "do not retry without conditions and then hand-calculate filtered statistics",
19784
19870
  "unsupported aggregates are invalid; use sum, avg, max, min, count, or distinct_count"
19785
19871
  ],
19786
19872
  suggestions: [
19787
- `retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}'`
19873
+ `retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}'`,
19874
+ `conditional stats: arcubase-admin widget preview-data --app-id <app_id> --body-json '{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<source_field_id>,"Name":"Source"}],"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]},"measures":[{"FieldID":<customer_field_id>,"Aggregate":"distinct_count","Name":"Distinct Customers"}]}'`
19875
+ ]
19876
+ };
19877
+ }
19878
+ if (requestType === "AppNewWidgetsReqVO") {
19879
+ return {
19880
+ shapeHint: {
19881
+ type: "list",
19882
+ options: { ingress_id: 2188893001 }
19883
+ },
19884
+ commonMistakes: [
19885
+ "dashboard widgets use options.dashboard_id",
19886
+ "ingress widgets use options.ingress_id",
19887
+ "do not put entity_id at body top level or under options when creating a widget",
19888
+ "after creating an ingress widget, use widget update-ingress-options to adjust display configuration"
19889
+ ],
19890
+ suggestions: [
19891
+ `dashboard chart: arcubase-admin widget create --app-id <app_id> --body-json '{"type":"chart","options":{"dashboard_id":<dashboard_id>}}'`,
19892
+ `ingress list: arcubase-admin widget create --app-id <app_id> --body-json '{"type":"list","options":{"ingress_id":<ingress_id>}}'`
19788
19893
  ]
19789
19894
  };
19790
19895
  }
@@ -19797,14 +19902,38 @@ function buildBodyGuidance(requestType) {
19797
19902
  entity_id: 2188891001,
19798
19903
  dimensions: [{ IsField: true, FieldID: 1004, Name: "Source" }],
19799
19904
  measures: [{ FieldID: 1005, Aggregate: "sum", Name: "Total Amount" }],
19905
+ conditions: { mode: "and", conditions: [{ column: ":1006", operator: "$eq", value: "yes" }] },
19800
19906
  type: "bar"
19801
19907
  }
19802
19908
  }
19803
19909
  },
19804
19910
  commonMistakes: [
19805
19911
  "dashboard chart config belongs in body.options.charts",
19912
+ "ingress/list display settings use widget update-ingress-options, not widget update",
19913
+ "do not put ingress_id, list, default_cols, page_size, or entry display settings in widget update",
19806
19914
  "field dimensions with FieldID must set IsField:true",
19915
+ "use options.charts.conditions, not filters, for chart data filtering",
19916
+ "do not retry without conditions and then hand-calculate filtered statistics",
19807
19917
  "verify persistence with widget get or widget list after update"
19918
+ ],
19919
+ suggestions: [
19920
+ `dashboard chart: arcubase-admin widget update --app-id <app_id> --widget-id <widget_id> --body-json '{"entity_id":<table_id>,"options":{"charts":{"entity_id":<table_id>,"dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}],"type":"bar"}}}'`,
19921
+ `ingress list display: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json '{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}'`
19922
+ ]
19923
+ };
19924
+ }
19925
+ if (requestType === "AppUpdateWidgetsIngressOptionsReqVO") {
19926
+ return {
19927
+ shapeHint: {
19928
+ options: { cond_follow: true, cond_follow_tab: true, cond_follow_cols: [":1001", ":1002"] }
19929
+ },
19930
+ commonMistakes: [
19931
+ "widget update-ingress-options is for ingress widgets, not dashboard chart widgets",
19932
+ "put display settings under body.options",
19933
+ "verify the ingress widget with widget get after update"
19934
+ ],
19935
+ suggestions: [
19936
+ `retry with: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json '{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}'`
19808
19937
  ]
19809
19938
  };
19810
19939
  }
@@ -699,6 +699,21 @@ export declare const userCommands: readonly [{
699
699
  readonly fixedValue: "true";
700
700
  }];
701
701
  readonly responseType: "GlobalActionEntryRespVO";
702
+ }, {
703
+ readonly scope: "user";
704
+ readonly module: "app";
705
+ readonly functionName: "getAppDetail";
706
+ readonly commandPath: readonly ["app", "get"];
707
+ readonly method: "GET";
708
+ readonly endpoint: "/api/apps/:id";
709
+ readonly pathParams: readonly [{
710
+ readonly param: "id";
711
+ readonly flag: "app-id";
712
+ }];
713
+ readonly controller: "UserAction.AppDetail";
714
+ readonly requestType: null;
715
+ readonly queryParams: readonly [];
716
+ readonly responseType: "AppDetailRespVO";
702
717
  }, {
703
718
  readonly scope: "user";
704
719
  readonly module: "dashboard";
@@ -1 +1 @@
1
- {"version":3,"file":"command_registry.generated.d.ts","sourceRoot":"","sources":["../../src/generated/command_registry.generated.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC3E,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,WAAW,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7G,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAi5BhB,CAAA;AAEV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAszBf,CAAA"}
1
+ {"version":3,"file":"command_registry.generated.d.ts","sourceRoot":"","sources":["../../src/generated/command_registry.generated.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC3E,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,WAAW,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7G,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAi5BhB,CAAA;AAEV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA20Bf,CAAA"}
@@ -937,6 +937,27 @@ export const userCommands = [
937
937
  ],
938
938
  "responseType": "GlobalActionEntryRespVO"
939
939
  },
940
+ {
941
+ "scope": "user",
942
+ "module": "app",
943
+ "functionName": "getAppDetail",
944
+ "commandPath": [
945
+ "app",
946
+ "get"
947
+ ],
948
+ "method": "GET",
949
+ "endpoint": "/api/apps/:id",
950
+ "pathParams": [
951
+ {
952
+ "param": "id",
953
+ "flag": "app-id"
954
+ }
955
+ ],
956
+ "controller": "UserAction.AppDetail",
957
+ "requestType": null,
958
+ "queryParams": [],
959
+ "responseType": "AppDetailRespVO"
960
+ },
940
961
  {
941
962
  "scope": "user",
942
963
  "module": "dashboard",
@@ -323,6 +323,45 @@ export declare const helpExamplesIndex: {
323
323
  }];
324
324
  };
325
325
  readonly notes: readonly ["supported Aggregate values are sum, avg, max, min, count, and distinct_count", "unsupported aggregate names fail local body validation before the request is sent"];
326
+ }, {
327
+ readonly title: "preview filtered distinct_count grouped by source";
328
+ readonly body: {
329
+ readonly dataSource: 2188891001;
330
+ readonly dataSourceType: "entity";
331
+ readonly dimensions: readonly [{
332
+ readonly IsField: true;
333
+ readonly FieldID: 1004;
334
+ readonly Name: "Source";
335
+ }];
336
+ readonly conditions: {
337
+ readonly mode: "and";
338
+ readonly conditions: readonly [{
339
+ readonly column: ":1006";
340
+ readonly operator: "$eq";
341
+ readonly value: "yes";
342
+ }];
343
+ };
344
+ readonly measures: readonly [{
345
+ readonly FieldID: 1002;
346
+ readonly Aggregate: "distinct_count";
347
+ readonly Name: "Distinct Customers";
348
+ }];
349
+ };
350
+ readonly notes: readonly ["use conditions, not filters, for chart data filtering", "for saved charts put the same condition set under options.charts.conditions", "do not remove the condition and hand-calculate filtered statistics from row query results"];
351
+ }];
352
+ };
353
+ readonly "admin.widget.update-ingress-options": {
354
+ readonly command: readonly ["widget", "update-ingress-options"];
355
+ readonly examples: readonly [{
356
+ readonly title: "adjust an ingress list widget display configuration";
357
+ readonly body: {
358
+ readonly options: {
359
+ readonly cond_follow: true;
360
+ readonly cond_follow_tab: true;
361
+ readonly cond_follow_cols: readonly [":1001", ":1002"];
362
+ };
363
+ };
364
+ readonly notes: readonly ["use this only for widgets created with options.ingress_id", "do not use dashboard update-layout for ingress widgets", "verify with widget get after updating ingress options"];
326
365
  }];
327
366
  };
328
367
  readonly "user.row.bulk-update": {
@@ -1 +1 @@
1
- {"version":3,"file":"help_examples.generated.d.ts","sourceRoot":"","sources":["../../src/generated/help_examples.generated.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6iBgF,CAAA"}
1
+ {"version":3,"file":"help_examples.generated.d.ts","sourceRoot":"","sources":["../../src/generated/help_examples.generated.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2mBgF,CAAA"}
@@ -458,6 +458,68 @@ export const helpExamplesIndex = {
458
458
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
459
459
  "unsupported aggregate names fail local body validation before the request is sent"
460
460
  ]
461
+ },
462
+ {
463
+ "title": "preview filtered distinct_count grouped by source",
464
+ "body": {
465
+ "dataSource": 2188891001,
466
+ "dataSourceType": "entity",
467
+ "dimensions": [
468
+ {
469
+ "IsField": true,
470
+ "FieldID": 1004,
471
+ "Name": "Source"
472
+ }
473
+ ],
474
+ "conditions": {
475
+ "mode": "and",
476
+ "conditions": [
477
+ {
478
+ "column": ":1006",
479
+ "operator": "$eq",
480
+ "value": "yes"
481
+ }
482
+ ]
483
+ },
484
+ "measures": [
485
+ {
486
+ "FieldID": 1002,
487
+ "Aggregate": "distinct_count",
488
+ "Name": "Distinct Customers"
489
+ }
490
+ ]
491
+ },
492
+ "notes": [
493
+ "use conditions, not filters, for chart data filtering",
494
+ "for saved charts put the same condition set under options.charts.conditions",
495
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
496
+ ]
497
+ }
498
+ ]
499
+ },
500
+ "admin.widget.update-ingress-options": {
501
+ "command": [
502
+ "widget",
503
+ "update-ingress-options"
504
+ ],
505
+ "examples": [
506
+ {
507
+ "title": "adjust an ingress list widget display configuration",
508
+ "body": {
509
+ "options": {
510
+ "cond_follow": true,
511
+ "cond_follow_tab": true,
512
+ "cond_follow_cols": [
513
+ ":1001",
514
+ ":1002"
515
+ ]
516
+ }
517
+ },
518
+ "notes": [
519
+ "use this only for widgets created with options.ingress_id",
520
+ "do not use dashboard update-layout for ingress widgets",
521
+ "verify with widget get after updating ingress options"
522
+ ]
461
523
  }
462
524
  ]
463
525
  },
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/runtime/execute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AAG1D,OAAO,EAAyF,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAShJ,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,YAAY,CAAA;IACnB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAC9B,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAe1D;AAaD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,QAAsB,GAAG,MAAM,CAoB7G;AA8BD,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAUlD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,QAAsB,GAAG,MAAM,CA8HpI;AAurED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,uBAAuB,CActH;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,SAAS,GAAE,OAAO,KAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAyOrI"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/runtime/execute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AAG1D,OAAO,EAAyF,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAShJ,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,YAAY,CAAA;IACnB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAC9B,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAe1D;AAaD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,QAAsB,GAAG,MAAM,CAoB7G;AA8BD,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAUlD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,QAAsB,GAAG,MAAM,CA8HpI;AAquED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,uBAAuB,CActH;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,SAAS,GAAE,OAAO,KAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAyOrI"}
@@ -948,15 +948,37 @@ function buildBodyGuidance(requestType) {
948
948
  dataSourceType: 'entity',
949
949
  dimensions: [{ IsField: true, FieldID: 1004, Name: 'Source' }],
950
950
  measures: [{ FieldID: 1005, Aggregate: 'sum', Name: 'Total Amount' }],
951
+ conditions: { mode: 'and', conditions: [{ column: ':1006', operator: '$eq', value: 'yes' }] },
951
952
  },
952
953
  commonMistakes: [
953
954
  'widget preview-data body is the chart query itself',
954
955
  'do not send a saved widget object with id, entity_id, or options',
955
956
  'field dimensions with FieldID must set IsField:true',
957
+ 'use conditions, not filters, for chart data filtering',
958
+ 'do not retry without conditions and then hand-calculate filtered statistics',
956
959
  'unsupported aggregates are invalid; use sum, avg, max, min, count, or distinct_count',
957
960
  ],
958
961
  suggestions: [
959
962
  'retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json \'{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}\'',
963
+ 'conditional stats: arcubase-admin widget preview-data --app-id <app_id> --body-json \'{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<source_field_id>,"Name":"Source"}],"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]},"measures":[{"FieldID":<customer_field_id>,"Aggregate":"distinct_count","Name":"Distinct Customers"}]}\'',
964
+ ],
965
+ };
966
+ }
967
+ if (requestType === 'AppNewWidgetsReqVO') {
968
+ return {
969
+ shapeHint: {
970
+ type: 'list',
971
+ options: { ingress_id: 2188893001 },
972
+ },
973
+ commonMistakes: [
974
+ 'dashboard widgets use options.dashboard_id',
975
+ 'ingress widgets use options.ingress_id',
976
+ 'do not put entity_id at body top level or under options when creating a widget',
977
+ 'after creating an ingress widget, use widget update-ingress-options to adjust display configuration',
978
+ ],
979
+ suggestions: [
980
+ 'dashboard chart: arcubase-admin widget create --app-id <app_id> --body-json \'{"type":"chart","options":{"dashboard_id":<dashboard_id>}}\'',
981
+ 'ingress list: arcubase-admin widget create --app-id <app_id> --body-json \'{"type":"list","options":{"ingress_id":<ingress_id>}}\'',
960
982
  ],
961
983
  };
962
984
  }
@@ -969,15 +991,39 @@ function buildBodyGuidance(requestType) {
969
991
  entity_id: 2188891001,
970
992
  dimensions: [{ IsField: true, FieldID: 1004, Name: 'Source' }],
971
993
  measures: [{ FieldID: 1005, Aggregate: 'sum', Name: 'Total Amount' }],
994
+ conditions: { mode: 'and', conditions: [{ column: ':1006', operator: '$eq', value: 'yes' }] },
972
995
  type: 'bar',
973
996
  },
974
997
  },
975
998
  },
976
999
  commonMistakes: [
977
1000
  'dashboard chart config belongs in body.options.charts',
1001
+ 'ingress/list display settings use widget update-ingress-options, not widget update',
1002
+ 'do not put ingress_id, list, default_cols, page_size, or entry display settings in widget update',
978
1003
  'field dimensions with FieldID must set IsField:true',
1004
+ 'use options.charts.conditions, not filters, for chart data filtering',
1005
+ 'do not retry without conditions and then hand-calculate filtered statistics',
979
1006
  'verify persistence with widget get or widget list after update',
980
1007
  ],
1008
+ suggestions: [
1009
+ 'dashboard chart: arcubase-admin widget update --app-id <app_id> --widget-id <widget_id> --body-json \'{"entity_id":<table_id>,"options":{"charts":{"entity_id":<table_id>,"dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}],"type":"bar"}}}\'',
1010
+ 'ingress list display: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json \'{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}\'',
1011
+ ],
1012
+ };
1013
+ }
1014
+ if (requestType === 'AppUpdateWidgetsIngressOptionsReqVO') {
1015
+ return {
1016
+ shapeHint: {
1017
+ options: { cond_follow: true, cond_follow_tab: true, cond_follow_cols: [':1001', ':1002'] },
1018
+ },
1019
+ commonMistakes: [
1020
+ 'widget update-ingress-options is for ingress widgets, not dashboard chart widgets',
1021
+ 'put display settings under body.options',
1022
+ 'verify the ingress widget with widget get after update',
1023
+ ],
1024
+ suggestions: [
1025
+ 'retry with: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json \'{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}\'',
1026
+ ],
981
1027
  };
982
1028
  }
983
1029
  return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carthooks/arcubase-cli",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Arcubase runtime CLI for admin and user command execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,13 @@
1
1
  # Dashboard
2
2
 
3
- Use `arcubase dashboard get` and `arcubase dashboard widgets` to read dashboards as a tenant user.
3
+ Use `arcubase app get`, `arcubase dashboard get`, and `arcubase dashboard widgets` to read dashboards as a tenant user.
4
+
5
+ User dashboard discovery:
6
+
7
+ - `arcubase entry` lists the current user's visible apps and tables.
8
+ - `arcubase app get --app-id <app_id>` returns app detail, including dashboards visible to the current user.
9
+ - To find a dashboard by name, run `app get` for candidate apps from `entry`, match `Dashboard[].Name`, then use that app id and dashboard id with `dashboard get`, `dashboard widgets`, and `widget data`.
10
+ - Do not use admin dashboard commands to prove a normal user's dashboard visibility.
4
11
 
5
12
  Use `arcubase-admin dashboard list`, `arcubase-admin dashboard create`, `arcubase-admin dashboard get-options`, `arcubase-admin dashboard update-options`, `arcubase-admin dashboard update-layout`, and `arcubase-admin dashboard rename` to manage dashboards as an admin.
6
13
 
@@ -37,6 +37,30 @@
37
37
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
38
38
  "unsupported aggregate names fail local body validation before the request is sent"
39
39
  ]
40
+ },
41
+ {
42
+ "title": "preview filtered distinct_count grouped by source",
43
+ "body": {
44
+ "dataSource": 2188891001,
45
+ "dataSourceType": "entity",
46
+ "dimensions": [
47
+ {"IsField": true, "FieldID": 1004, "Name": "Source"}
48
+ ],
49
+ "conditions": {
50
+ "mode": "and",
51
+ "conditions": [
52
+ {"column": ":1006", "operator": "$eq", "value": "yes"}
53
+ ]
54
+ },
55
+ "measures": [
56
+ {"FieldID": 1002, "Aggregate": "distinct_count", "Name": "Distinct Customers"}
57
+ ]
58
+ },
59
+ "notes": [
60
+ "use conditions, not filters, for chart data filtering",
61
+ "for saved charts put the same condition set under options.charts.conditions",
62
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
63
+ ]
40
64
  }
41
65
  ]
42
66
  }
@@ -0,0 +1,21 @@
1
+ {
2
+ "scope": "admin",
3
+ "command": ["widget", "update-ingress-options"],
4
+ "examples": [
5
+ {
6
+ "title": "adjust an ingress list widget display configuration",
7
+ "body": {
8
+ "options": {
9
+ "cond_follow": true,
10
+ "cond_follow_tab": true,
11
+ "cond_follow_cols": [":1001", ":1002"]
12
+ }
13
+ },
14
+ "notes": [
15
+ "use this only for widgets created with options.ingress_id",
16
+ "do not use dashboard update-layout for ingress widgets",
17
+ "verify with widget get after updating ingress options"
18
+ ]
19
+ }
20
+ ]
21
+ }
@@ -8,6 +8,14 @@ Use `arcubase widget data --app-id <app_id> --body-json '<FetchWidgetsDataReqVO>
8
8
 
9
9
  Create dashboard widgets with `{"type":"chart","options":{"dashboard_id":<dashboard_id>}}`. Do not set `options.type` by hand; the backend derives dashboard versus ingress widget type from `dashboard_id` or `ingress_id`.
10
10
 
11
+ Create ingress list widgets with `{"type":"list","options":{"ingress_id":<ingress_id>}}`, where `ingress_id` is the entry/access-rule id. Do not put `entity_id` at the top level or under `options` when creating a widget. After creation, adjust entry list display settings with `widget update-ingress-options`, then verify with `widget get`. Ingress widgets have `dashboard_id:0` and must not be placed with `dashboard update-layout`.
12
+
13
+ If ingress/list display settings such as `ingress_id`, `list`, `default_cols`, or `page_size` are rejected by `widget update`, switch to `widget update-ingress-options`; do not retry `widget update` with empty options.
14
+
15
+ ```json
16
+ {"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}
17
+ ```
18
+
11
19
  Most widget commands use `--widget-id`; `widget preview-data` is the exception. Preview data does not read a saved widget by id and does not accept `--widget-id`, `widget_id`, or `id`. Its body is the chart query itself:
12
20
 
13
21
  ```json
@@ -20,6 +28,22 @@ Fastfail rule: `widget preview-data` accepts only the chart query body. If valid
20
28
 
21
29
  After `widget update`, verify persistence with `widget get` or `widget list`. The saved widget must contain non-null `options.charts`; an update response alone is not enough evidence that the chart configuration was persisted.
22
30
 
31
+ ## Chart conditions
32
+
33
+ Use `conditions`, not `filters`, to filter dashboard chart statistics. The condition set shape is:
34
+
35
+ ```json
36
+ {"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]}
37
+ ```
38
+
39
+ For saved widgets, place this under `options.charts.conditions`. For `widget preview-data`, place it at top level beside `dataSource`, `dimensions`, and `measures`.
40
+
41
+ ```json
42
+ {"dataSource":2188891001,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":1004,"Name":"Source"}],"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]},"measures":[{"FieldID":1002,"Aggregate":"distinct_count","Name":"Distinct Customers"}]}
43
+ ```
44
+
45
+ Fastfail rule: if a chart statistic requires filtering and validation rejects a guessed key such as `filters`, retry with `conditions`. Do not remove the filter and then hand-calculate filtered statistics from row data.
46
+
23
47
  ## Chart measures
24
48
 
25
49
  Dashboard chart widgets use `ChartOption.measures[]` to define statistics. Supported `Aggregate` values are:
@@ -953,6 +953,27 @@ export const userCommands = [
953
953
  ],
954
954
  "responseType": "GlobalActionEntryRespVO"
955
955
  },
956
+ {
957
+ "scope": "user",
958
+ "module": "app",
959
+ "functionName": "getAppDetail",
960
+ "commandPath": [
961
+ "app",
962
+ "get"
963
+ ],
964
+ "method": "GET",
965
+ "endpoint": "/api/apps/:id",
966
+ "pathParams": [
967
+ {
968
+ "param": "id",
969
+ "flag": "app-id"
970
+ }
971
+ ],
972
+ "controller": "UserAction.AppDetail",
973
+ "requestType": null,
974
+ "queryParams": [],
975
+ "responseType": "AppDetailRespVO"
976
+ },
956
977
  {
957
978
  "scope": "user",
958
979
  "module": "dashboard",
@@ -465,6 +465,68 @@ export const helpExamplesIndex = {
465
465
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
466
466
  "unsupported aggregate names fail local body validation before the request is sent"
467
467
  ]
468
+ },
469
+ {
470
+ "title": "preview filtered distinct_count grouped by source",
471
+ "body": {
472
+ "dataSource": 2188891001,
473
+ "dataSourceType": "entity",
474
+ "dimensions": [
475
+ {
476
+ "IsField": true,
477
+ "FieldID": 1004,
478
+ "Name": "Source"
479
+ }
480
+ ],
481
+ "conditions": {
482
+ "mode": "and",
483
+ "conditions": [
484
+ {
485
+ "column": ":1006",
486
+ "operator": "$eq",
487
+ "value": "yes"
488
+ }
489
+ ]
490
+ },
491
+ "measures": [
492
+ {
493
+ "FieldID": 1002,
494
+ "Aggregate": "distinct_count",
495
+ "Name": "Distinct Customers"
496
+ }
497
+ ]
498
+ },
499
+ "notes": [
500
+ "use conditions, not filters, for chart data filtering",
501
+ "for saved charts put the same condition set under options.charts.conditions",
502
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
503
+ ]
504
+ }
505
+ ]
506
+ },
507
+ "admin.widget.update-ingress-options": {
508
+ "command": [
509
+ "widget",
510
+ "update-ingress-options"
511
+ ],
512
+ "examples": [
513
+ {
514
+ "title": "adjust an ingress list widget display configuration",
515
+ "body": {
516
+ "options": {
517
+ "cond_follow": true,
518
+ "cond_follow_tab": true,
519
+ "cond_follow_cols": [
520
+ ":1001",
521
+ ":1002"
522
+ ]
523
+ }
524
+ },
525
+ "notes": [
526
+ "use this only for widgets created with options.ingress_id",
527
+ "do not use dashboard update-layout for ingress widgets",
528
+ "verify with widget get after updating ingress options"
529
+ ]
468
530
  }
469
531
  ]
470
532
  },
@@ -953,6 +953,27 @@ export const userCommands = [
953
953
  ],
954
954
  "responseType": "GlobalActionEntryRespVO"
955
955
  },
956
+ {
957
+ "scope": "user",
958
+ "module": "app",
959
+ "functionName": "getAppDetail",
960
+ "commandPath": [
961
+ "app",
962
+ "get"
963
+ ],
964
+ "method": "GET",
965
+ "endpoint": "/api/apps/:id",
966
+ "pathParams": [
967
+ {
968
+ "param": "id",
969
+ "flag": "app-id"
970
+ }
971
+ ],
972
+ "controller": "UserAction.AppDetail",
973
+ "requestType": null,
974
+ "queryParams": [],
975
+ "responseType": "AppDetailRespVO"
976
+ },
956
977
  {
957
978
  "scope": "user",
958
979
  "module": "dashboard",
@@ -465,6 +465,68 @@ export const helpExamplesIndex = {
465
465
  "supported Aggregate values are sum, avg, max, min, count, and distinct_count",
466
466
  "unsupported aggregate names fail local body validation before the request is sent"
467
467
  ]
468
+ },
469
+ {
470
+ "title": "preview filtered distinct_count grouped by source",
471
+ "body": {
472
+ "dataSource": 2188891001,
473
+ "dataSourceType": "entity",
474
+ "dimensions": [
475
+ {
476
+ "IsField": true,
477
+ "FieldID": 1004,
478
+ "Name": "Source"
479
+ }
480
+ ],
481
+ "conditions": {
482
+ "mode": "and",
483
+ "conditions": [
484
+ {
485
+ "column": ":1006",
486
+ "operator": "$eq",
487
+ "value": "yes"
488
+ }
489
+ ]
490
+ },
491
+ "measures": [
492
+ {
493
+ "FieldID": 1002,
494
+ "Aggregate": "distinct_count",
495
+ "Name": "Distinct Customers"
496
+ }
497
+ ]
498
+ },
499
+ "notes": [
500
+ "use conditions, not filters, for chart data filtering",
501
+ "for saved charts put the same condition set under options.charts.conditions",
502
+ "do not remove the condition and hand-calculate filtered statistics from row query results"
503
+ ]
504
+ }
505
+ ]
506
+ },
507
+ "admin.widget.update-ingress-options": {
508
+ "command": [
509
+ "widget",
510
+ "update-ingress-options"
511
+ ],
512
+ "examples": [
513
+ {
514
+ "title": "adjust an ingress list widget display configuration",
515
+ "body": {
516
+ "options": {
517
+ "cond_follow": true,
518
+ "cond_follow_tab": true,
519
+ "cond_follow_cols": [
520
+ ":1001",
521
+ ":1002"
522
+ ]
523
+ }
524
+ },
525
+ "notes": [
526
+ "use this only for widgets created with options.ingress_id",
527
+ "do not use dashboard update-layout for ingress widgets",
528
+ "verify with widget get after updating ingress options"
529
+ ]
468
530
  }
469
531
  ]
470
532
  },
@@ -1032,15 +1032,37 @@ function buildBodyGuidance(requestType: string): Pick<CLIErrorDetails, 'retryToo
1032
1032
  dataSourceType: 'entity',
1033
1033
  dimensions: [{ IsField: true, FieldID: 1004, Name: 'Source' }],
1034
1034
  measures: [{ FieldID: 1005, Aggregate: 'sum', Name: 'Total Amount' }],
1035
+ conditions: { mode: 'and', conditions: [{ column: ':1006', operator: '$eq', value: 'yes' }] },
1035
1036
  },
1036
1037
  commonMistakes: [
1037
1038
  'widget preview-data body is the chart query itself',
1038
1039
  'do not send a saved widget object with id, entity_id, or options',
1039
1040
  'field dimensions with FieldID must set IsField:true',
1041
+ 'use conditions, not filters, for chart data filtering',
1042
+ 'do not retry without conditions and then hand-calculate filtered statistics',
1040
1043
  'unsupported aggregates are invalid; use sum, avg, max, min, count, or distinct_count',
1041
1044
  ],
1042
1045
  suggestions: [
1043
1046
  'retry with: arcubase-admin widget preview-data --app-id <app_id> --body-json \'{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}]}\'',
1047
+ 'conditional stats: arcubase-admin widget preview-data --app-id <app_id> --body-json \'{"dataSource":<table_id>,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":<source_field_id>,"Name":"Source"}],"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]},"measures":[{"FieldID":<customer_field_id>,"Aggregate":"distinct_count","Name":"Distinct Customers"}]}\'',
1048
+ ],
1049
+ }
1050
+ }
1051
+ if (requestType === 'AppNewWidgetsReqVO') {
1052
+ return {
1053
+ shapeHint: {
1054
+ type: 'list',
1055
+ options: { ingress_id: 2188893001 },
1056
+ },
1057
+ commonMistakes: [
1058
+ 'dashboard widgets use options.dashboard_id',
1059
+ 'ingress widgets use options.ingress_id',
1060
+ 'do not put entity_id at body top level or under options when creating a widget',
1061
+ 'after creating an ingress widget, use widget update-ingress-options to adjust display configuration',
1062
+ ],
1063
+ suggestions: [
1064
+ 'dashboard chart: arcubase-admin widget create --app-id <app_id> --body-json \'{"type":"chart","options":{"dashboard_id":<dashboard_id>}}\'',
1065
+ 'ingress list: arcubase-admin widget create --app-id <app_id> --body-json \'{"type":"list","options":{"ingress_id":<ingress_id>}}\'',
1044
1066
  ],
1045
1067
  }
1046
1068
  }
@@ -1053,15 +1075,39 @@ function buildBodyGuidance(requestType: string): Pick<CLIErrorDetails, 'retryToo
1053
1075
  entity_id: 2188891001,
1054
1076
  dimensions: [{ IsField: true, FieldID: 1004, Name: 'Source' }],
1055
1077
  measures: [{ FieldID: 1005, Aggregate: 'sum', Name: 'Total Amount' }],
1078
+ conditions: { mode: 'and', conditions: [{ column: ':1006', operator: '$eq', value: 'yes' }] },
1056
1079
  type: 'bar',
1057
1080
  },
1058
1081
  },
1059
1082
  },
1060
1083
  commonMistakes: [
1061
1084
  'dashboard chart config belongs in body.options.charts',
1085
+ 'ingress/list display settings use widget update-ingress-options, not widget update',
1086
+ 'do not put ingress_id, list, default_cols, page_size, or entry display settings in widget update',
1062
1087
  'field dimensions with FieldID must set IsField:true',
1088
+ 'use options.charts.conditions, not filters, for chart data filtering',
1089
+ 'do not retry without conditions and then hand-calculate filtered statistics',
1063
1090
  'verify persistence with widget get or widget list after update',
1064
1091
  ],
1092
+ suggestions: [
1093
+ 'dashboard chart: arcubase-admin widget update --app-id <app_id> --widget-id <widget_id> --body-json \'{"entity_id":<table_id>,"options":{"charts":{"entity_id":<table_id>,"dimensions":[{"IsField":true,"FieldID":<field_id>,"Name":"Source"}],"measures":[{"FieldID":<number_field_id>,"Aggregate":"sum","Name":"Total Amount"}],"type":"bar"}}}\'',
1094
+ 'ingress list display: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json \'{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}\'',
1095
+ ],
1096
+ }
1097
+ }
1098
+ if (requestType === 'AppUpdateWidgetsIngressOptionsReqVO') {
1099
+ return {
1100
+ shapeHint: {
1101
+ options: { cond_follow: true, cond_follow_tab: true, cond_follow_cols: [':1001', ':1002'] },
1102
+ },
1103
+ commonMistakes: [
1104
+ 'widget update-ingress-options is for ingress widgets, not dashboard chart widgets',
1105
+ 'put display settings under body.options',
1106
+ 'verify the ingress widget with widget get after update',
1107
+ ],
1108
+ suggestions: [
1109
+ 'retry with: arcubase-admin widget update-ingress-options --app-id <app_id> --widget-id <widget_id> --body-json \'{"options":{"cond_follow":true,"cond_follow_tab":true,"cond_follow_cols":[":1001",":1002"]}}\'',
1110
+ ],
1065
1111
  }
1066
1112
  }
1067
1113
  return {}
@@ -54,6 +54,7 @@ test('admin surface is restricted to reset white list', () => {
54
54
  test('user surface is restricted to reset white list', () => {
55
55
  const actual = commandPaths(userCommands)
56
56
  const expected = [
57
+ 'app get',
57
58
  'dashboard get',
58
59
  'dashboard widgets',
59
60
  'entry',
@@ -93,7 +94,7 @@ test('generated modules use CLI namespaces only', () => {
93
94
  const adminModules = [...new Set(adminCommands.map((item) => item.module))].sort()
94
95
  const userModules = [...new Set(userCommands.map((item) => item.module))].sort()
95
96
  assert.deepEqual(adminModules, ['access-rule', 'app', 'dashboard', 'table', 'widget', 'workflow'])
96
- assert.deepEqual(userModules, ['dashboard', 'entry', 'profile', 'row', 'table', 'upload', 'widget', 'workflow'])
97
+ assert.deepEqual(userModules, ['app', 'dashboard', 'entry', 'profile', 'row', 'table', 'upload', 'widget', 'workflow'])
97
98
  })
98
99
 
99
100
  test('black list commands are removed from registry', () => {
@@ -1095,6 +1095,16 @@ test('entry fixed app tables query cannot be disabled by query file', async () =
1095
1095
  })
1096
1096
 
1097
1097
  test('dashboard and widget commands map to approved endpoints', async () => {
1098
+ const userAppGet = await executeCLI(
1099
+ 'user',
1100
+ ['app', 'get', '--app-id', 'app_1'],
1101
+ env as any,
1102
+ async (url, init) => new Response(JSON.stringify({ url, method: init?.method }), { status: 200 }),
1103
+ )
1104
+ assert.equal(userAppGet.kind, 'result')
1105
+ assert.equal(userAppGet.data.url, 'https://arcubase.example.com/api/apps/app_1')
1106
+ assert.equal(userAppGet.data.method, 'GET')
1107
+
1098
1108
  const adminWidgetList = await executeCLI(
1099
1109
  'admin',
1100
1110
  ['widget', 'list', '--app-id', 'app_1', '--type', 'dashboard', '--dashboard-id', '100'],
@@ -1131,6 +1141,61 @@ test('dashboard and widget commands map to approved endpoints', async () => {
1131
1141
  assert.deepEqual(userWidgetData.data.body, { dashboard_id: 100, type: 1 })
1132
1142
  })
1133
1143
 
1144
+ test('widget create ingress mistakes suggest ingress widget shape before request', async () => {
1145
+ let called = false
1146
+ await assert.rejects(async () => {
1147
+ await executeCLI(
1148
+ 'admin',
1149
+ ['widget', 'create', '--app-id', 'app_1', '--body-json', '{"type":"list","options":{"entity_id":2188891001}}'],
1150
+ env as any,
1151
+ async () => {
1152
+ called = true
1153
+ return new Response('{}', { status: 200 })
1154
+ },
1155
+ )
1156
+ }, (error: unknown) => {
1157
+ assert.ok(error instanceof CLIError)
1158
+ assert.equal(error.code, 'BODY_VALIDATION_FAILED')
1159
+ assert.equal(error.details?.requestType, 'AppNewWidgetsReqVO')
1160
+ assert.ok((error.details?.commonMistakes ?? []).includes('ingress widgets use options.ingress_id'))
1161
+ assert.ok((error.details?.commonMistakes ?? []).includes('after creating an ingress widget, use widget update-ingress-options to adjust display configuration'))
1162
+ return true
1163
+ })
1164
+ assert.equal(called, false)
1165
+ })
1166
+
1167
+ test('widget update ingress list options points to update-ingress-options before request', async () => {
1168
+ let called = false
1169
+ await assert.rejects(async () => {
1170
+ await executeCLI(
1171
+ 'admin',
1172
+ [
1173
+ 'widget',
1174
+ 'update',
1175
+ '--app-id',
1176
+ 'app_1',
1177
+ '--widget-id',
1178
+ 'widget_1',
1179
+ '--body-json',
1180
+ '{"ingress_id":2188893001,"options":{"list":{"default_cols":[1001,1002],"page_size":10}}}',
1181
+ ],
1182
+ env as any,
1183
+ async () => {
1184
+ called = true
1185
+ return new Response('{}', { status: 200 })
1186
+ },
1187
+ )
1188
+ }, (error: unknown) => {
1189
+ assert.ok(error instanceof CLIError)
1190
+ assert.equal(error.code, 'BODY_VALIDATION_FAILED')
1191
+ assert.equal(error.details?.requestType, 'AppUpdateWidgetsReqVO')
1192
+ assert.ok((error.details?.commonMistakes ?? []).includes('ingress/list display settings use widget update-ingress-options, not widget update'))
1193
+ assert.ok((error.details?.suggestions ?? []).some((item) => item.includes('widget update-ingress-options')))
1194
+ return true
1195
+ })
1196
+ assert.equal(called, false)
1197
+ })
1198
+
1134
1199
  test('widget preview-data rejects unsupported aggregate before request', async () => {
1135
1200
  let called = false
1136
1201
  await assert.rejects(async () => {
@@ -1191,6 +1256,38 @@ test('widget preview-data rejects field dimensions without IsField true before r
1191
1256
  assert.equal(called, false)
1192
1257
  })
1193
1258
 
1259
+ test('widget preview-data filter mistakes suggest chart conditions before request', async () => {
1260
+ let called = false
1261
+ await assert.rejects(async () => {
1262
+ await executeCLI(
1263
+ 'admin',
1264
+ [
1265
+ 'widget',
1266
+ 'preview-data',
1267
+ '--app-id',
1268
+ 'app_1',
1269
+ '--body-json',
1270
+ '{"dataSource":2188891001,"dataSourceType":"entity","dimensions":[{"IsField":true,"FieldID":1004,"Name":"Source"}],"filters":[{"FieldID":1006,"Operator":"$eq","Value":"yes"}],"measures":[{"Name":"Distinct Customers","FieldID":1002,"Aggregate":"distinct_count"}]}',
1271
+ ],
1272
+ env as any,
1273
+ async () => {
1274
+ called = true
1275
+ return new Response('{}', { status: 200 })
1276
+ },
1277
+ )
1278
+ }, (error: unknown) => {
1279
+ assert.ok(error instanceof CLIError)
1280
+ assert.equal(error.code, 'BODY_VALIDATION_FAILED')
1281
+ assert.equal(error.details?.requestType, 'AppPreviewWidgetsDataReqVO')
1282
+ assert.ok((error.details?.issues ?? []).some((item) => item.path === 'body'))
1283
+ assert.ok((error.details?.commonMistakes ?? []).includes('use conditions, not filters, for chart data filtering'))
1284
+ assert.ok((error.details?.commonMistakes ?? []).includes('do not retry without conditions and then hand-calculate filtered statistics'))
1285
+ assert.ok((error.details?.suggestions ?? []).some((item) => item.includes('"conditions":{"mode":"and","conditions":[{"column":":1006","operator":"$eq","value":"yes"}]}')))
1286
+ return true
1287
+ })
1288
+ assert.equal(called, false)
1289
+ })
1290
+
1194
1291
  test('widget update rejects chart field dimensions without IsField true before request', async () => {
1195
1292
  let called = false
1196
1293
  await assert.rejects(async () => {
@@ -136,6 +136,12 @@ test('dashboard and widget help exposes agent-readable body docs and flags', asy
136
136
  assert.match(userWidgetData.text, /body: FetchWidgetsDataReqVO via --body-json/)
137
137
  assert.match(userWidgetData.text, /^types:$/m)
138
138
  assert.match(userWidgetData.text, /^docs:$/m)
139
+
140
+ const userAppGet = await executeCLI('user', ['app', 'get', '--help'], env as any, async () => new Response('{}'))
141
+ assert.equal(userAppGet.kind, 'help')
142
+ assert.match(userAppGet.text, /arcubase app get/)
143
+ assert.match(userAppGet.text, /endpoint: \/apps\/:id/)
144
+ assert.match(userAppGet.text, /path flags: --app-id/)
139
145
  })
140
146
 
141
147
  test('admin access-rule help gives update whitelist and assign-users body-json examples', async () => {
@@ -221,6 +227,8 @@ test('admin widget preview-data help-examples show chart query body without widg
221
227
  assert.match(out.text, /"dataSource":2188891001/)
222
228
  assert.match(out.text, /"dataSourceType":"entity"/)
223
229
  assert.match(out.text, /"Aggregate":"sum"/)
230
+ assert.match(out.text, /"conditions":\{"mode":"and","conditions":\[\{"column":":1006","operator":"\$eq","value":"yes"\}\]\}/)
231
+ assert.match(out.text, /use conditions, not filters/)
224
232
  assert.match(out.text, /preview-data does not accept --widget-id/)
225
233
  assert.match(out.text, /do not send widget_id or id/)
226
234
  assert.doesNotMatch(out.text, /--widget-id <widget_id>/)
@@ -236,6 +244,14 @@ test('admin widget create help-examples avoid manual options type', async () =>
236
244
  assert.doesNotMatch(out.text, /"options":\{"dashboard_id":2188892001,"type":/)
237
245
  })
238
246
 
247
+ test('admin widget update-ingress-options help-examples show ingress display body', async () => {
248
+ const out = await executeCLI('admin', ['widget', 'update-ingress-options', '--help-examples'], env as any, async () => new Response('{}'))
249
+ assert.equal(out.kind, 'help')
250
+ assert.match(out.text, /arcubase-admin widget update-ingress-options --help-examples/)
251
+ assert.match(out.text, /"cond_follow":true/)
252
+ assert.match(out.text, /verify with widget get/)
253
+ })
254
+
239
255
  test('user row bulk-update help-examples show ids and condition selection bodies', async () => {
240
256
  const out = await executeCLI('user', ['row', 'bulk-update', '--help-examples'], env as any, async () => new Response('{}'))
241
257
  assert.equal(out.kind, 'help')