@camunda/ccma-shared-types 2.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tests/approvals/cluster-bulk-operation.spec.d.ts +1 -0
- package/dist/_tests/dtos/FeatureFlagOverride.dto.spec.d.ts +1 -0
- package/dist/_tests/permissions/session-permissions.spec.d.ts +1 -0
- package/dist/annotations/policy.d.ts +98 -0
- package/dist/annotations/policy.js +61 -0
- package/dist/annotations/policy.js.map +7 -0
- package/dist/approvals/cluster-bulk-operation.d.ts +196 -0
- package/dist/approvals/cluster-bulk-operation.js +127 -0
- package/dist/approvals/cluster-bulk-operation.js.map +7 -0
- package/dist/approvals/policy.d.ts +138 -9
- package/dist/approvals/policy.js +100 -23
- package/dist/approvals/policy.js.map +2 -2
- package/dist/approvals/use-cases.const.d.ts +114 -0
- package/dist/approvals/use-cases.const.js +31 -0
- package/dist/approvals/use-cases.const.js.map +7 -0
- package/dist/config/camundi-permission-rules.js +24 -3
- package/dist/config/camundi-permission-rules.js.map +2 -2
- package/dist/constants/misc.const.d.ts +2 -0
- package/dist/constants/misc.const.js +4 -0
- package/dist/constants/misc.const.js.map +2 -2
- package/dist/dtos/AlertSubscription.dto.d.ts +6 -0
- package/dist/dtos/AlertSubscription.dto.js.map +2 -2
- package/dist/dtos/Annotation.dto.d.ts +240 -0
- package/dist/dtos/Annotation.dto.js +47 -0
- package/dist/dtos/Annotation.dto.js.map +7 -0
- package/dist/dtos/ApprovalJob.dto.d.ts +408 -4
- package/dist/dtos/ApprovalJob.dto.js +64 -1
- package/dist/dtos/ApprovalJob.dto.js.map +2 -2
- package/dist/dtos/ClusterOwnerMove.dto.d.ts +81 -0
- package/dist/dtos/ClusterOwnerMove.dto.js +1 -0
- package/dist/dtos/ClusterOwnerMove.dto.js.map +7 -0
- package/dist/dtos/CommonCluster.dto.d.ts +6 -0
- package/dist/dtos/ControlV2.dto.d.ts +55 -3
- package/dist/dtos/FeatureFlagOverride.dto.d.ts +226 -0
- package/dist/dtos/FeatureFlagOverride.dto.js +38 -0
- package/dist/dtos/FeatureFlagOverride.dto.js.map +7 -0
- package/dist/dtos/FeatureFlags.dto.d.ts +58 -45
- package/dist/dtos/FeatureFlags.dto.js +10 -0
- package/dist/dtos/FeatureFlags.dto.js.map +3 -3
- package/dist/dtos/Generations.dto.d.ts +17 -0
- package/dist/dtos/Generations.dto.js +7 -0
- package/dist/dtos/Generations.dto.js.map +2 -2
- package/dist/dtos/Generations.dto.spec.d.ts +1 -0
- package/dist/dtos/K8sContext.dto.d.ts +13 -4
- package/dist/dtos/ReleaseTrainSanity.dto.d.ts +6 -0
- package/dist/enums/SystemAuditEntity.enum.d.ts +1 -0
- package/dist/enums/SystemAuditEntity.enum.js +1 -0
- package/dist/enums/SystemAuditEntity.enum.js.map +2 -2
- package/dist/index.d.ts +21 -10
- package/dist/index.js +157 -9
- package/dist/index.js.map +2 -2
- package/dist/permissions/accounts.permissions.d.ts +35 -0
- package/dist/permissions/accounts.permissions.js +33 -1
- package/dist/permissions/accounts.permissions.js.map +2 -2
- package/dist/permissions/combo.d.ts +9 -0
- package/dist/permissions/combo.js +64 -3
- package/dist/permissions/combo.js.map +2 -2
- package/dist/permissions/console.permissions.d.ts +32 -0
- package/dist/permissions/console.permissions.js +24 -2
- package/dist/permissions/console.permissions.js.map +2 -2
- package/dist/types/Roles.d.ts +1 -1
- package/dist/types/Roles.js.map +2 -2
- package/dist/utils/versionCheck.utils.d.ts +9 -0
- package/dist/utils/versionCheck.utils.js +7 -2
- package/dist/utils/versionCheck.utils.js.map +2 -2
- package/package.json +1 -1
- package/dist/constants/failoverRegionPairs.const.d.ts +0 -36
- package/dist/constants/failoverRegionPairs.const.js +0 -34
- package/dist/constants/failoverRegionPairs.const.js.map +0 -7
- /package/dist/_tests/{constants/failoverRegionPairs.const.spec.d.ts → annotations/policy.spec.d.ts} +0 -0
|
@@ -24,11 +24,32 @@ const CONFIG = {
|
|
|
24
24
|
"support:agent"
|
|
25
25
|
],
|
|
26
26
|
// Pre-Sales as per https://confluence.camunda.com/spaces/HAN/pages/168660217/Adjust+C8+SaaS+permissions+and+sales+plan#AdjustC8SaaSpermissionsandsalesplan-DetailsperRole
|
|
27
|
+
// Professional Services holds 36 people, the consultants. Six of them
|
|
28
|
+
// sit in the Education subdivision. They train customers and do not
|
|
29
|
+
// work on customer clusters.
|
|
30
|
+
//
|
|
31
|
+
// The augmenter can only ADD a role, so no rule here can EXCLUDE
|
|
32
|
+
// Education from this grant. The other 30 consultants carry no
|
|
33
|
+
// subdivision at all, so a subdivision rule cannot name them either.
|
|
34
|
+
//
|
|
35
|
+
// This grant covers the whole division on purpose. A rule that keys on
|
|
36
|
+
// the ABSENCE of a subdivision id is more fragile than one that keys on
|
|
37
|
+
// a present id, and two comments in this file already record a
|
|
38
|
+
// subdivision id that a HiBob restructure broke without warning.
|
|
39
|
+
//
|
|
40
|
+
// If the 30 consultants without a subdivision get one of their own one
|
|
41
|
+
// day, move this grant down to that subdivision and remove this rule.
|
|
42
|
+
// Education would then stop inheriting the grant, because the division
|
|
43
|
+
// no longer carries it and the subdivision rule never named Education.
|
|
44
|
+
"266189454": ["console:clusterMover"],
|
|
45
|
+
// Professional Services
|
|
27
46
|
// Enterprise Success holds the CSMs and the TAMs. A customer who has
|
|
28
47
|
// privacy concerns asks them to switch optional telemetry off, thus they
|
|
29
|
-
// carry
|
|
30
|
-
// smallest group that holds all of them.
|
|
31
|
-
|
|
48
|
+
// carry that capability. HiBob marks no TAM, thus the division is the
|
|
49
|
+
// smallest group that holds all of them. The CSMs and TAMs also move a
|
|
50
|
+
// cluster to another org for a customer, thus they carry
|
|
51
|
+
// `console:clusterMover` too.
|
|
52
|
+
"266229124": ["console:optionalTelemetryManager", "console:clusterMover"]
|
|
32
53
|
// Enterprise Success
|
|
33
54
|
},
|
|
34
55
|
subdivisionRules: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/config/camundi-permission-rules.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type { CamundiPermissionRules } from './camundi-permission-rules.types.js'\n\nconst CONFIG: CamundiPermissionRules = {\n departmentRules: {\n '205882305': ['accounts:read', 'accounts:trialExtender'], // CS\n Marketing: ['accounts:read', 'accounts:trialExtender'],\n '205882307': ['accounts:read', 'accounts:trialExtender'], // revops\n Products: ['console:admin:readonly', 'accounts:read'],\n Executive: ['accounts:read'],\n '259633605': ['accounts:read', 'accounts:trialExtender'], // Sales\n },\n divisionRules: {\n Engineering: ['console:admin:readonly'],\n '259633608': [\n 'accounts:connections:create',\n 'accounts:connections:update',\n 'support:agent',\n ], // Support\n '259633611': [\n 'accounts:trialExtender',\n 'accounts:limitExtender',\n 'support:agent',\n ], // Pre-Sales as per https://confluence.camunda.com/spaces/HAN/pages/168660217/Adjust+C8+SaaS+permissions+and+sales+plan#AdjustC8SaaSpermissionsandsalesplan-DetailsperRole\n // Enterprise Success holds the CSMs and the TAMs. A customer who has\n // privacy concerns asks them to switch optional telemetry off, thus they\n // carry
|
|
5
|
-
"mappings": "AAQA,MAAM,SAAiC;AAAA,EACrC,iBAAiB;AAAA,IACf,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,IACvD,WAAW,CAAC,iBAAiB,wBAAwB;AAAA,IACrD,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,IACvD,UAAU,CAAC,0BAA0B,eAAe;AAAA,IACpD,WAAW,CAAC,eAAe;AAAA,IAC3B,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,EACzD;AAAA,EACA,eAAe;AAAA,IACb,aAAa,CAAC,wBAAwB;AAAA,IACtC,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IACA,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type { CamundiPermissionRules } from './camundi-permission-rules.types.js'\n\nconst CONFIG: CamundiPermissionRules = {\n departmentRules: {\n '205882305': ['accounts:read', 'accounts:trialExtender'], // CS\n Marketing: ['accounts:read', 'accounts:trialExtender'],\n '205882307': ['accounts:read', 'accounts:trialExtender'], // revops\n Products: ['console:admin:readonly', 'accounts:read'],\n Executive: ['accounts:read'],\n '259633605': ['accounts:read', 'accounts:trialExtender'], // Sales\n },\n divisionRules: {\n Engineering: ['console:admin:readonly'],\n '259633608': [\n 'accounts:connections:create',\n 'accounts:connections:update',\n 'support:agent',\n ], // Support\n '259633611': [\n 'accounts:trialExtender',\n 'accounts:limitExtender',\n 'support:agent',\n ], // Pre-Sales as per https://confluence.camunda.com/spaces/HAN/pages/168660217/Adjust+C8+SaaS+permissions+and+sales+plan#AdjustC8SaaSpermissionsandsalesplan-DetailsperRole\n // Professional Services holds 36 people, the consultants. Six of them\n // sit in the Education subdivision. They train customers and do not\n // work on customer clusters.\n //\n // The augmenter can only ADD a role, so no rule here can EXCLUDE\n // Education from this grant. The other 30 consultants carry no\n // subdivision at all, so a subdivision rule cannot name them either.\n //\n // This grant covers the whole division on purpose. A rule that keys on\n // the ABSENCE of a subdivision id is more fragile than one that keys on\n // a present id, and two comments in this file already record a\n // subdivision id that a HiBob restructure broke without warning.\n //\n // If the 30 consultants without a subdivision get one of their own one\n // day, move this grant down to that subdivision and remove this rule.\n // Education would then stop inheriting the grant, because the division\n // no longer carries it and the subdivision rule never named Education.\n '266189454': ['console:clusterMover'], // Professional Services\n // Enterprise Success holds the CSMs and the TAMs. A customer who has\n // privacy concerns asks them to switch optional telemetry off, thus they\n // carry that capability. HiBob marks no TAM, thus the division is the\n // smallest group that holds all of them. The CSMs and TAMs also move a\n // cluster to another org for a customer, thus they carry\n // `console:clusterMover` too.\n '266229124': ['console:optionalTelemetryManager', 'console:clusterMover'], // Enterprise Success\n },\n subdivisionRules: {\n // The console team is the \"Control plane\" subdivision. The id was\n // `256909487` until a HiBob restructure, and the augmenter matches a\n // subdivision exactly and stays quiet on a miss, thus the rule granted\n // nothing to anybody and nobody saw it.\n '267516827': ['accounts:admin', 'console:admin', 'consoleTeam'], // Control plane\n 'Engineering Management': [\n 'accounts:addSafeRoles',\n 'accounts:orgCreator',\n 'console:C8ReleaseManager',\n ], // Engineering Management\n // Same story: the id `258049291` is gone. The subdivision carries the name\n // `Controller` now, and a name is a valid key \u2014 `Engineering Management`\n // above is one too.\n Controller: ['console:clusterPlanManager', 'console:operationsEngineer'],\n },\n}\nexport default CONFIG\n"],
|
|
5
|
+
"mappings": "AAQA,MAAM,SAAiC;AAAA,EACrC,iBAAiB;AAAA,IACf,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,IACvD,WAAW,CAAC,iBAAiB,wBAAwB;AAAA,IACrD,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,IACvD,UAAU,CAAC,0BAA0B,eAAe;AAAA,IACpD,WAAW,CAAC,eAAe;AAAA,IAC3B,aAAa,CAAC,iBAAiB,wBAAwB;AAAA;AAAA,EACzD;AAAA,EACA,eAAe;AAAA,IACb,aAAa,CAAC,wBAAwB;AAAA,IACtC,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IACA,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBA,aAAa,CAAC,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOpC,aAAa,CAAC,oCAAoC,sBAAsB;AAAA;AAAA,EAC1E;AAAA,EACA,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,IAKhB,aAAa,CAAC,kBAAkB,iBAAiB,aAAa;AAAA;AAAA,IAC9D,0BAA0B;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,IAIA,YAAY,CAAC,8BAA8B,4BAA4B;AAAA,EACzE;AACF;AACA,IAAO,mCAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -33,6 +33,8 @@ export declare const MINIMUM_EYEPAIRS: {
|
|
|
33
33
|
CLUSTER_GENERATION_UPDATE: number;
|
|
34
34
|
CLUSTER_PLAN_UPDATE: number;
|
|
35
35
|
CLUSTER_PLAN_TYPE_UPDATE: number;
|
|
36
|
+
CLUSTER_SLEEP_WAKEUP: number;
|
|
37
|
+
CLUSTER_SPEC_UPDATE: number;
|
|
36
38
|
CLUSTER_PLAN_MODIFICATION: number;
|
|
37
39
|
CLUSTER_MODIFICATION: number;
|
|
38
40
|
};
|
|
@@ -16,6 +16,10 @@ const MINIMUM_EYEPAIRS = {
|
|
|
16
16
|
CLUSTER_GENERATION_UPDATE: 2,
|
|
17
17
|
CLUSTER_PLAN_UPDATE: 2,
|
|
18
18
|
CLUSTER_PLAN_TYPE_UPDATE: 2,
|
|
19
|
+
// These two had no name, and each reader fell back to
|
|
20
|
+
// `CLUSTER_PLAN_UPDATE`. The values are the same as that fallback.
|
|
21
|
+
CLUSTER_SLEEP_WAKEUP: 2,
|
|
22
|
+
CLUSTER_SPEC_UPDATE: 2,
|
|
19
23
|
CLUSTER_PLAN_MODIFICATION: 1,
|
|
20
24
|
CLUSTER_MODIFICATION: 1
|
|
21
25
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/constants/misc.const.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nexport const CONSOLE_API_USER_ID = 'console-api'\n\n/**\n * The namespace of the custom claims that Auth0 adds to a token of this fleet.\n *\n * An Auth0 API access token carries no `email` claim of its own. The rules of\n * the tenant put the email of the person under this namespace instead, and\n * every reader of the fleet must look there. A service that reads a top-level\n * `email` claim gets nothing, and the failure is silent: the identity is still\n * valid, so the request continues with an empty email.\n */\nexport const CAMUNDA_CLAIMS_NAMESPACE = 'https://camunda.com/meta'\n\n/**\n * The email of an actor whose token carries no email.\n *\n * It is a value and not an empty string, because an empty string reads like a\n * field that nobody wrote. A record that says `unknown` says that the token had\n * no email, which is a different fact.\n *\n * A rule that compares two people MUST NOT treat two of these as one person.\n * `isSameActorEmail` in `approvals/policy.ts` holds that.\n */\nexport const UNKNOWN_ACTOR_EMAIL = 'unknown'\nexport const TEMPORARY_CLUSTER_NAME = 'Get Started'\nexport type Stage = 'local' | 'dev' | 'int' | 'prod'\nexport const HOTBACKUP_MIN_CREATE_PERIOD = 1000 * 60 * 60 * 0.25 // 15 minutes\n\nexport const SECRETS_MAX_LENGTH = 4096\nexport const FIRSTNAME_LASTNAME_MAX_LENGTH = 255\n\nexport const STARTING_PRICE_PER_MONTH_IN_EURO = 99\n\nexport const MAX_LENGTH_CLUSTER_NAME = 50\n\nexport const NAMES_OF_ENTERPRISE_SALESPLANS_WITH_SLEEPING_CLUSTERS = [\n 'CELP with sleeping clusters',\n 'Camunda Partner',\n]\n\nexport const MINIMUM_EYEPAIRS = {\n CLUSTER_DELETION: 3,\n CLUSTER_GENERATION_UPDATE: 2,\n CLUSTER_PLAN_UPDATE: 2,\n CLUSTER_PLAN_TYPE_UPDATE: 2,\n CLUSTER_PLAN_MODIFICATION: 1,\n CLUSTER_MODIFICATION: 1,\n}\n\nexport const MAX_HARDWARE_PACKAGE_COUNT = 4\n"],
|
|
5
|
-
"mappings": "AAMO,MAAM,sBAAsB;AAW5B,MAAM,2BAA2B;AAYjC,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAE/B,MAAM,8BAA8B,MAAO,KAAK,KAAK;AAErD,MAAM,qBAAqB;AAC3B,MAAM,gCAAgC;AAEtC,MAAM,mCAAmC;AAEzC,MAAM,0BAA0B;AAEhC,MAAM,wDAAwD;AAAA,EACnE;AAAA,EACA;AACF;AAEO,MAAM,mBAAmB;AAAA,EAC9B,kBAAkB;AAAA,EAClB,2BAA2B;AAAA,EAC3B,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nexport const CONSOLE_API_USER_ID = 'console-api'\n\n/**\n * The namespace of the custom claims that Auth0 adds to a token of this fleet.\n *\n * An Auth0 API access token carries no `email` claim of its own. The rules of\n * the tenant put the email of the person under this namespace instead, and\n * every reader of the fleet must look there. A service that reads a top-level\n * `email` claim gets nothing, and the failure is silent: the identity is still\n * valid, so the request continues with an empty email.\n */\nexport const CAMUNDA_CLAIMS_NAMESPACE = 'https://camunda.com/meta'\n\n/**\n * The email of an actor whose token carries no email.\n *\n * It is a value and not an empty string, because an empty string reads like a\n * field that nobody wrote. A record that says `unknown` says that the token had\n * no email, which is a different fact.\n *\n * A rule that compares two people MUST NOT treat two of these as one person.\n * `isSameActorEmail` in `approvals/policy.ts` holds that.\n */\nexport const UNKNOWN_ACTOR_EMAIL = 'unknown'\nexport const TEMPORARY_CLUSTER_NAME = 'Get Started'\nexport type Stage = 'local' | 'dev' | 'int' | 'prod'\nexport const HOTBACKUP_MIN_CREATE_PERIOD = 1000 * 60 * 60 * 0.25 // 15 minutes\n\nexport const SECRETS_MAX_LENGTH = 4096\nexport const FIRSTNAME_LASTNAME_MAX_LENGTH = 255\n\nexport const STARTING_PRICE_PER_MONTH_IN_EURO = 99\n\nexport const MAX_LENGTH_CLUSTER_NAME = 50\n\nexport const NAMES_OF_ENTERPRISE_SALESPLANS_WITH_SLEEPING_CLUSTERS = [\n 'CELP with sleeping clusters',\n 'Camunda Partner',\n]\n\nexport const MINIMUM_EYEPAIRS = {\n CLUSTER_DELETION: 3,\n CLUSTER_GENERATION_UPDATE: 2,\n CLUSTER_PLAN_UPDATE: 2,\n CLUSTER_PLAN_TYPE_UPDATE: 2,\n // These two had no name, and each reader fell back to\n // `CLUSTER_PLAN_UPDATE`. The values are the same as that fallback.\n CLUSTER_SLEEP_WAKEUP: 2,\n CLUSTER_SPEC_UPDATE: 2,\n CLUSTER_PLAN_MODIFICATION: 1,\n CLUSTER_MODIFICATION: 1,\n}\n\nexport const MAX_HARDWARE_PACKAGE_COUNT = 4\n"],
|
|
5
|
+
"mappings": "AAMO,MAAM,sBAAsB;AAW5B,MAAM,2BAA2B;AAYjC,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAE/B,MAAM,8BAA8B,MAAO,KAAK,KAAK;AAErD,MAAM,qBAAqB;AAC3B,MAAM,gCAAgC;AAEtC,MAAM,mCAAmC;AAEzC,MAAM,0BAA0B;AAEhC,MAAM,wDAAwD;AAAA,EACnE;AAAA,EACA;AACF;AAEO,MAAM,mBAAmB;AAAA,EAC9B,kBAAkB;AAAA,EAClB,2BAA2B;AAAA,EAC3B,qBAAqB;AAAA,EACrB,0BAA0B;AAAA;AAAA;AAAA,EAG1B,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,sBAAsB;AACxB;AAEO,MAAM,6BAA6B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -13,6 +13,12 @@ export interface AlertSubscriptionDto {
|
|
|
13
13
|
updated: Date;
|
|
14
14
|
lastTimeTriggered?: Date;
|
|
15
15
|
numberOfTimesTriggered: number;
|
|
16
|
+
/**
|
|
17
|
+
* The address of an `Email` subscription. alert-distributor adds it from the
|
|
18
|
+
* user id, which its list endpoint then replaces with the name of the user.
|
|
19
|
+
* Thus this field is the only reliable way to identify the person.
|
|
20
|
+
*/
|
|
21
|
+
recepientEmail?: string;
|
|
16
22
|
}
|
|
17
23
|
export interface AlertSubscriptionEntryDto {
|
|
18
24
|
errorMessage?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/dtos/AlertSubscription.dto.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n AlertSubscriptionReportType,\n AlertSubscriptionType,\n} from '../enums/AlertSubscription.enum.js'\n\nexport interface AlertSubscriptionDto {\n uuid: string\n userIdOrWebhook: string\n type: AlertSubscriptionType\n report: AlertSubscriptionReportType\n webhookAuth?: AlertSubscriptionWebhookAuth\n createdBy: string\n createdByName: string\n created: Date\n updatedBy: string\n updatedByName: string\n updated: Date\n lastTimeTriggered?: Date\n numberOfTimesTriggered: number\n}\n\nexport interface AlertSubscriptionEntryDto {\n errorMessage?: string\n errorType?: string\n flowNodeId?: string\n jobKey?: string\n creationTime?: string\n processInstanceId?: string\n processName?: string\n processVersion?: number\n bpmnProcessId?: string\n}\n\nexport const HMAC_SUPPORTED_ALGORITHM = 'sha256'\nexport const HMAC_HEADER_POSITION = 'X-Camunda-Signature-256'\n\n/**\n * Webhook targets a customer may not point an alert at, to limit SSRF.\n *\n * Despite the name, each entry is a URL prefix, scheme included: callers match\n * with `url.href.startsWith(entry)`. So add entries as `https://<host>`, with\n * no trailing slash and no path.\n */\nexport const FORBIDDEN_HOSTNAMES_FOR_WEBHOOK_ALERTS = [\n 'https://camunda.com',\n 'https://console.cloud.camunda.io',\n 'https://accounts.cloud.camunda.io',\n 'https://console.camunda.io',\n 'https://accounts.camunda.io',\n 'https://console.ultrawombat.com',\n 'https://console.cloud.ultrawombat.com',\n 'https://accounts.cloud.ultrawombat.com',\n 'https://accounts.ultrawombat.com',\n 'https://console.cloud.dev.ultrawombat.com',\n 'https://console.dev.ultrawombat.com',\n 'https://accounts.cloud.dev.ultrawombat.com',\n 'https://accounts.dev.ultrawombat.com',\n // Hub and consolelegacy, all stages.\n // Note: This list contains URL prefixes (`https://<host>`), not bare hostnames.\n // Callers compare with `url.href.startsWith(...)`.\n 'https://hub.dev.ultrawombat.com',\n 'https://hub.ultrawombat.com',\n 'https://hub.camunda.io',\n 'https://consolelegacy.dev.ultrawombat.com',\n 'https://consolelegacy.ultrawombat.com',\n 'https://consolelegacy.camunda.io',\n]\n\nexport type ALERT_SUBSCRIPTION_TYPES = 'ProcessAlert'\nexport type ALERT_SUBSCRIPTION_REPORT_TYPES = 'Email' | 'Webhook'\n\nexport interface AlertSubscriptionWebhookAuth {\n hmac?: {\n secret: string\n }\n}\n\nexport type CheckFailedReason =\n | 'urlEmpty'\n | 'urlNoHead'\n | 'generatedHmacNotAccepted'\n | 'urlBad'\n | 'urlPrivate'\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n AlertSubscriptionReportType,\n AlertSubscriptionType,\n} from '../enums/AlertSubscription.enum.js'\n\nexport interface AlertSubscriptionDto {\n uuid: string\n userIdOrWebhook: string\n type: AlertSubscriptionType\n report: AlertSubscriptionReportType\n webhookAuth?: AlertSubscriptionWebhookAuth\n createdBy: string\n createdByName: string\n created: Date\n updatedBy: string\n updatedByName: string\n updated: Date\n lastTimeTriggered?: Date\n numberOfTimesTriggered: number\n /**\n * The address of an `Email` subscription. alert-distributor adds it from the\n * user id, which its list endpoint then replaces with the name of the user.\n * Thus this field is the only reliable way to identify the person.\n */\n recepientEmail?: string\n}\n\nexport interface AlertSubscriptionEntryDto {\n errorMessage?: string\n errorType?: string\n flowNodeId?: string\n jobKey?: string\n creationTime?: string\n processInstanceId?: string\n processName?: string\n processVersion?: number\n bpmnProcessId?: string\n}\n\nexport const HMAC_SUPPORTED_ALGORITHM = 'sha256'\nexport const HMAC_HEADER_POSITION = 'X-Camunda-Signature-256'\n\n/**\n * Webhook targets a customer may not point an alert at, to limit SSRF.\n *\n * Despite the name, each entry is a URL prefix, scheme included: callers match\n * with `url.href.startsWith(entry)`. So add entries as `https://<host>`, with\n * no trailing slash and no path.\n */\nexport const FORBIDDEN_HOSTNAMES_FOR_WEBHOOK_ALERTS = [\n 'https://camunda.com',\n 'https://console.cloud.camunda.io',\n 'https://accounts.cloud.camunda.io',\n 'https://console.camunda.io',\n 'https://accounts.camunda.io',\n 'https://console.ultrawombat.com',\n 'https://console.cloud.ultrawombat.com',\n 'https://accounts.cloud.ultrawombat.com',\n 'https://accounts.ultrawombat.com',\n 'https://console.cloud.dev.ultrawombat.com',\n 'https://console.dev.ultrawombat.com',\n 'https://accounts.cloud.dev.ultrawombat.com',\n 'https://accounts.dev.ultrawombat.com',\n // Hub and consolelegacy, all stages.\n // Note: This list contains URL prefixes (`https://<host>`), not bare hostnames.\n // Callers compare with `url.href.startsWith(...)`.\n 'https://hub.dev.ultrawombat.com',\n 'https://hub.ultrawombat.com',\n 'https://hub.camunda.io',\n 'https://consolelegacy.dev.ultrawombat.com',\n 'https://consolelegacy.ultrawombat.com',\n 'https://consolelegacy.camunda.io',\n]\n\nexport type ALERT_SUBSCRIPTION_TYPES = 'ProcessAlert'\nexport type ALERT_SUBSCRIPTION_REPORT_TYPES = 'Email' | 'Webhook'\n\nexport interface AlertSubscriptionWebhookAuth {\n hmac?: {\n secret: string\n }\n}\n\nexport type CheckFailedReason =\n | 'urlEmpty'\n | 'urlNoHead'\n | 'generatedHmacNotAccepted'\n | 'urlBad'\n | 'urlPrivate'\n"],
|
|
5
|
+
"mappings": "AA6CO,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAS7B,MAAM,yCAAyC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire types of the annotations of the fleet: the notes and the tags that a
|
|
3
|
+
* Camundi attaches to an entity.
|
|
4
|
+
*
|
|
5
|
+
* An annotation adds CONTEXT that the fleet itself does not hold. A cluster row
|
|
6
|
+
* says how much memory it has; it does not say "this is the playground of the
|
|
7
|
+
* demo team". A Camundi writes that here, and the next Camundi reads it.
|
|
8
|
+
*
|
|
9
|
+
* This file holds no logic and no dependency, because control-backend and
|
|
10
|
+
* control-frontend both read it. The rules that read these types are in
|
|
11
|
+
* `../annotations/policy.js`, and they are pure for the same reason.
|
|
12
|
+
*
|
|
13
|
+
* The feature is INTERNAL. No annotation reaches a customer, and no route of
|
|
14
|
+
* another service reads one.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Every kind of fleet entity that can carry an annotation.
|
|
18
|
+
*
|
|
19
|
+
* A `const` tuple, not an enum, so it is both the union type and the list that
|
|
20
|
+
* validates a request at run time.
|
|
21
|
+
*
|
|
22
|
+
* The kind is a STRING on the row and not a foreign key, because the entity is
|
|
23
|
+
* in a different database: a cluster belongs to console-backend and an
|
|
24
|
+
* organization to accounts-backend. That is also what keeps an annotation after
|
|
25
|
+
* the entity goes away. See `AnnotationDto.entityLabel`.
|
|
26
|
+
*
|
|
27
|
+
* Add a kind here and in `ANNOTATION_ENTITY_KIND_LABELS` below. The two lists
|
|
28
|
+
* are one `Record`, so a kind with no label does not compile.
|
|
29
|
+
*
|
|
30
|
+
* Every kind here is a THING of the fleet, and none of them is a person. That
|
|
31
|
+
* is a rule and not an accident. A `user` kind was in this list and came out
|
|
32
|
+
* again: an annotation outlives its entity on purpose, which is right for a
|
|
33
|
+
* cluster that somebody deleted and wrong for a colleague who left, and this
|
|
34
|
+
* feature has no retention rule, no reaper, and no way for the person written
|
|
35
|
+
* about to read or correct it. Add a kind that names a PERSON only with those
|
|
36
|
+
* three answered.
|
|
37
|
+
*/
|
|
38
|
+
export declare const ANNOTATION_ENTITY_KINDS: readonly ["cluster", "organization", "cluster-plan", "cluster-plan-type", "generation", "channel", "sales-plan", "k8s-context"];
|
|
39
|
+
export type AnnotationEntityKind = (typeof ANNOTATION_ENTITY_KINDS)[number];
|
|
40
|
+
/**
|
|
41
|
+
* What a reader sees for each kind, in the singular.
|
|
42
|
+
*
|
|
43
|
+
* The label is here and not in the frontend, because the search page shows
|
|
44
|
+
* results of every kind together and the backend writes the same word into a
|
|
45
|
+
* log line. Two spellings of one kind would read as two kinds.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ANNOTATION_ENTITY_KIND_LABELS: Record<AnnotationEntityKind, string>;
|
|
48
|
+
/**
|
|
49
|
+
* What an annotation IS: a written note, or a tag out of the dictionary.
|
|
50
|
+
*
|
|
51
|
+
* One row type carries both, because both answer the same question — what does
|
|
52
|
+
* a Camundi need to know about this entity? — and both are read, listed and
|
|
53
|
+
* removed the same way. The difference is what the row points at: a note holds
|
|
54
|
+
* `body`, and a tag holds `tag`.
|
|
55
|
+
*/
|
|
56
|
+
export declare const ANNOTATION_KINDS: readonly ["note", "tag"];
|
|
57
|
+
export type AnnotationKind = (typeof ANNOTATION_KINDS)[number];
|
|
58
|
+
/** Who wrote an annotation. The same shape as `ApprovalActor`. */
|
|
59
|
+
export interface AnnotationActor {
|
|
60
|
+
userId: string;
|
|
61
|
+
email: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* One tag of the dictionary.
|
|
65
|
+
*
|
|
66
|
+
* A tag is its own row, and not a string on the annotation, for one reason:
|
|
67
|
+
* a Camundi must be able to ask "what else carries `partner`?". A string on
|
|
68
|
+
* each row answers that only with a scan, and it drifts: `Partner`, `partner `
|
|
69
|
+
* and `partner` would be three tags that read as one.
|
|
70
|
+
*/
|
|
71
|
+
export interface AnnotationTagDto {
|
|
72
|
+
id: string;
|
|
73
|
+
/** What a reader sees. The first spelling that anybody wrote wins. */
|
|
74
|
+
name: string;
|
|
75
|
+
/** `name` through `normalizeTagName`. It is the identity of the tag. */
|
|
76
|
+
normalizedName: string;
|
|
77
|
+
createdBy: AnnotationActor;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
/**
|
|
80
|
+
* How many LIVE entities carry this tag.
|
|
81
|
+
*
|
|
82
|
+
* It is counted at read time and never stored, so a removed assignment
|
|
83
|
+
* lowers it with no second write. A list of the dictionary needs it to sort
|
|
84
|
+
* by use, which is how a Camundi finds the tag that the team already uses
|
|
85
|
+
* instead of inventing a second spelling of it.
|
|
86
|
+
*/
|
|
87
|
+
usageCount: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* One note, or one tag, on one entity.
|
|
91
|
+
*
|
|
92
|
+
* `entityKind` and `entityId` together name the entity. Neither is checked
|
|
93
|
+
* against the fleet: the entity lives in another service, and an annotation
|
|
94
|
+
* must survive its entity. See `entityLabel`.
|
|
95
|
+
*/
|
|
96
|
+
export interface AnnotationDto {
|
|
97
|
+
id: string;
|
|
98
|
+
kind: AnnotationKind;
|
|
99
|
+
entityKind: AnnotationEntityKind;
|
|
100
|
+
entityId: string;
|
|
101
|
+
/**
|
|
102
|
+
* What the entity was CALLED when somebody wrote the annotation.
|
|
103
|
+
*
|
|
104
|
+
* This is the only reason a search result stays readable after the entity is
|
|
105
|
+
* deleted: the id of a cluster that no longer exists says nothing, and the
|
|
106
|
+
* fleet can no longer answer what its name was. The label is a copy on
|
|
107
|
+
* purpose, so it can be stale — it says what the entity was called then, not
|
|
108
|
+
* what it is called now.
|
|
109
|
+
*/
|
|
110
|
+
entityLabel?: string;
|
|
111
|
+
/** The text of a note. Absent on a tag. */
|
|
112
|
+
body?: string;
|
|
113
|
+
/** The tag of a tag annotation. Absent on a note. */
|
|
114
|
+
tag?: AnnotationTagDto;
|
|
115
|
+
createdBy: AnnotationActor;
|
|
116
|
+
createdAt: string;
|
|
117
|
+
updatedAt: string;
|
|
118
|
+
/** True when `body` was changed after it was written. */
|
|
119
|
+
edited: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* How many times this row was written. A new one carries 1.
|
|
122
|
+
*
|
|
123
|
+
* An edit sends the version that it read, and the route refuses the write
|
|
124
|
+
* when the row moved on since. Without it the tab that somebody left open at
|
|
125
|
+
* breakfast silently replaces the edit they made at lunch, and neither write
|
|
126
|
+
* tells them that one of the two is gone.
|
|
127
|
+
*/
|
|
128
|
+
version: number;
|
|
129
|
+
}
|
|
130
|
+
/** The annotations of one entity, in one answer. */
|
|
131
|
+
export interface EntityAnnotationsDto {
|
|
132
|
+
entityKind: AnnotationEntityKind;
|
|
133
|
+
entityId: string;
|
|
134
|
+
notes: AnnotationDto[];
|
|
135
|
+
tags: AnnotationDto[];
|
|
136
|
+
/**
|
|
137
|
+
* True when the entity carries more than `ANNOTATION_ENTITY_MAX` rows, so
|
|
138
|
+
* the two lists above are the newest of them and not all of them.
|
|
139
|
+
*
|
|
140
|
+
* A panel that showed no sign of this would be a page that quietly stops
|
|
141
|
+
* being the whole story, which is worse for documentation than a page that
|
|
142
|
+
* says where the rest is.
|
|
143
|
+
*/
|
|
144
|
+
hasMore: boolean;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* What one entity carries, in the answer of a lookup over many entities.
|
|
148
|
+
*
|
|
149
|
+
* A table of 3000 clusters cannot read 3000 panels. The lookup answers the
|
|
150
|
+
* two questions that a row of such a table needs: which tags, and whether a
|
|
151
|
+
* colleague wrote something that a person must read before they act.
|
|
152
|
+
*/
|
|
153
|
+
export interface AnnotationLookupEntryDto {
|
|
154
|
+
entityId: string;
|
|
155
|
+
/**
|
|
156
|
+
* The live tag annotations of the entity, oldest first, and at most
|
|
157
|
+
* `ANNOTATION_LOOKUP_TAGS_MAX` of them.
|
|
158
|
+
*/
|
|
159
|
+
tags: AnnotationDto[];
|
|
160
|
+
/** How many live tags the entity carries. More than `tags` holds is cut. */
|
|
161
|
+
tagCount: number;
|
|
162
|
+
/** How many live notes the entity carries. */
|
|
163
|
+
noteCount: number;
|
|
164
|
+
/** The newest live note, so a row can show it with no second read. */
|
|
165
|
+
latestNote?: AnnotationDto;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The answer of a lookup. It holds ONLY the entities that carry something,
|
|
169
|
+
* so an entity with no entry carries nothing.
|
|
170
|
+
*/
|
|
171
|
+
export interface AnnotationLookupDto {
|
|
172
|
+
entityKind: AnnotationEntityKind;
|
|
173
|
+
entries: AnnotationLookupEntryDto[];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The most entities that one lookup names.
|
|
177
|
+
*
|
|
178
|
+
* The same number as the largest cluster bulk operation, which is the table
|
|
179
|
+
* that asks the largest question.
|
|
180
|
+
*/
|
|
181
|
+
export declare const ANNOTATION_LOOKUP_MAX_ENTITIES = 3000;
|
|
182
|
+
/**
|
|
183
|
+
* The most tags that a lookup answers for ONE entity.
|
|
184
|
+
*
|
|
185
|
+
* An entity can carry any number of tags. Without this cap, one lookup of
|
|
186
|
+
* 3000 entities has no bound on its rows. A row of a table shows a few chips,
|
|
187
|
+
* and `tagCount` tells it how many it did not get.
|
|
188
|
+
*/
|
|
189
|
+
export declare const ANNOTATION_LOOKUP_TAGS_MAX = 20;
|
|
190
|
+
/**
|
|
191
|
+
* The most annotations that the read of ONE entity answers with.
|
|
192
|
+
*
|
|
193
|
+
* The read has no page of its own: a panel is a thread that a person scrolls,
|
|
194
|
+
* not a table they walk. But it cannot be unbounded either — an entity that
|
|
195
|
+
* collects notes for a year would make every load of that page serialize
|
|
196
|
+
* thousands of rows of up to `ANNOTATION_BODY_MAX` characters each. So the
|
|
197
|
+
* answer is the NEWEST rows up to this number, with `hasMore` to say that
|
|
198
|
+
* older ones exist. The search page reads the rest.
|
|
199
|
+
*/
|
|
200
|
+
export declare const ANNOTATION_ENTITY_MAX = 200;
|
|
201
|
+
/**
|
|
202
|
+
* The longest note that a route accepts.
|
|
203
|
+
*
|
|
204
|
+
* A note is context for a colleague and not a document. The ceiling keeps one
|
|
205
|
+
* paste of a log file out of every read of the entity page, and a person who
|
|
206
|
+
* needs more has a handbook page to link to.
|
|
207
|
+
*/
|
|
208
|
+
export declare const ANNOTATION_BODY_MAX = 4000;
|
|
209
|
+
/** The longest tag name. A tag is a label, so it is short by design. */
|
|
210
|
+
export declare const ANNOTATION_TAG_NAME_MAX = 60;
|
|
211
|
+
/**
|
|
212
|
+
* The longest free text that the search accepts.
|
|
213
|
+
*
|
|
214
|
+
* The VIEW needs it as much as the route: a field with no ceiling lets a
|
|
215
|
+
* person paste more than the route takes, and the answer is then a 400 that
|
|
216
|
+
* reads like a broken search. The field holds them here instead, and a deep
|
|
217
|
+
* link that carries more is cut to this length rather than breaking the page.
|
|
218
|
+
*/
|
|
219
|
+
export declare const ANNOTATION_SEARCH_MAX_LENGTH = 200;
|
|
220
|
+
/** Annotations for each page when the caller asks for no number. */
|
|
221
|
+
export declare const ANNOTATION_PAGE_SIZE_DEFAULT = 100;
|
|
222
|
+
/**
|
|
223
|
+
* The most annotations that one page can hold.
|
|
224
|
+
*
|
|
225
|
+
* The view needs this number too: a page that asked for more rows than the
|
|
226
|
+
* service allows would get a 400 instead of rows.
|
|
227
|
+
*/
|
|
228
|
+
export declare const ANNOTATION_PAGE_SIZE_MAX = 500;
|
|
229
|
+
/**
|
|
230
|
+
* The identity of a tag, from what a person typed.
|
|
231
|
+
*
|
|
232
|
+
* The case and the outer spaces go, and every run of inner whitespace becomes
|
|
233
|
+
* one hyphen. `Partner`, ` partner ` and `Partner ` are then one tag, and
|
|
234
|
+
* `key account` is `key-account`.
|
|
235
|
+
*
|
|
236
|
+
* Both sides run this: the backend writes the result into `normalizedName` and
|
|
237
|
+
* holds it unique, and the frontend runs it to tell a person, before they
|
|
238
|
+
* press the button, that the tag they are typing already exists.
|
|
239
|
+
*/
|
|
240
|
+
export declare function normalizeTagName(name: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const ANNOTATION_ENTITY_KINDS = [
|
|
2
|
+
"cluster",
|
|
3
|
+
"organization",
|
|
4
|
+
"cluster-plan",
|
|
5
|
+
"cluster-plan-type",
|
|
6
|
+
"generation",
|
|
7
|
+
"channel",
|
|
8
|
+
"sales-plan",
|
|
9
|
+
"k8s-context"
|
|
10
|
+
];
|
|
11
|
+
const ANNOTATION_ENTITY_KIND_LABELS = {
|
|
12
|
+
cluster: "Cluster",
|
|
13
|
+
organization: "Organization",
|
|
14
|
+
"cluster-plan": "Cluster plan",
|
|
15
|
+
"cluster-plan-type": "Cluster plan type",
|
|
16
|
+
generation: "Generation",
|
|
17
|
+
channel: "Channel",
|
|
18
|
+
"sales-plan": "Sales plan",
|
|
19
|
+
"k8s-context": "Kubernetes context"
|
|
20
|
+
};
|
|
21
|
+
const ANNOTATION_KINDS = ["note", "tag"];
|
|
22
|
+
const ANNOTATION_LOOKUP_MAX_ENTITIES = 3e3;
|
|
23
|
+
const ANNOTATION_LOOKUP_TAGS_MAX = 20;
|
|
24
|
+
const ANNOTATION_ENTITY_MAX = 200;
|
|
25
|
+
const ANNOTATION_BODY_MAX = 4e3;
|
|
26
|
+
const ANNOTATION_TAG_NAME_MAX = 60;
|
|
27
|
+
const ANNOTATION_SEARCH_MAX_LENGTH = 200;
|
|
28
|
+
const ANNOTATION_PAGE_SIZE_DEFAULT = 100;
|
|
29
|
+
const ANNOTATION_PAGE_SIZE_MAX = 500;
|
|
30
|
+
function normalizeTagName(name) {
|
|
31
|
+
return name.trim().toLowerCase().replace(/\s+/g, "-");
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
ANNOTATION_BODY_MAX,
|
|
35
|
+
ANNOTATION_ENTITY_KINDS,
|
|
36
|
+
ANNOTATION_ENTITY_KIND_LABELS,
|
|
37
|
+
ANNOTATION_ENTITY_MAX,
|
|
38
|
+
ANNOTATION_KINDS,
|
|
39
|
+
ANNOTATION_LOOKUP_MAX_ENTITIES,
|
|
40
|
+
ANNOTATION_LOOKUP_TAGS_MAX,
|
|
41
|
+
ANNOTATION_PAGE_SIZE_DEFAULT,
|
|
42
|
+
ANNOTATION_PAGE_SIZE_MAX,
|
|
43
|
+
ANNOTATION_SEARCH_MAX_LENGTH,
|
|
44
|
+
ANNOTATION_TAG_NAME_MAX,
|
|
45
|
+
normalizeTagName
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=Annotation.dto.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/dtos/Annotation.dto.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\n/**\n * The wire types of the annotations of the fleet: the notes and the tags that a\n * Camundi attaches to an entity.\n *\n * An annotation adds CONTEXT that the fleet itself does not hold. A cluster row\n * says how much memory it has; it does not say \"this is the playground of the\n * demo team\". A Camundi writes that here, and the next Camundi reads it.\n *\n * This file holds no logic and no dependency, because control-backend and\n * control-frontend both read it. The rules that read these types are in\n * `../annotations/policy.js`, and they are pure for the same reason.\n *\n * The feature is INTERNAL. No annotation reaches a customer, and no route of\n * another service reads one.\n */\n\n/**\n * Every kind of fleet entity that can carry an annotation.\n *\n * A `const` tuple, not an enum, so it is both the union type and the list that\n * validates a request at run time.\n *\n * The kind is a STRING on the row and not a foreign key, because the entity is\n * in a different database: a cluster belongs to console-backend and an\n * organization to accounts-backend. That is also what keeps an annotation after\n * the entity goes away. See `AnnotationDto.entityLabel`.\n *\n * Add a kind here and in `ANNOTATION_ENTITY_KIND_LABELS` below. The two lists\n * are one `Record`, so a kind with no label does not compile.\n *\n * Every kind here is a THING of the fleet, and none of them is a person. That\n * is a rule and not an accident. A `user` kind was in this list and came out\n * again: an annotation outlives its entity on purpose, which is right for a\n * cluster that somebody deleted and wrong for a colleague who left, and this\n * feature has no retention rule, no reaper, and no way for the person written\n * about to read or correct it. Add a kind that names a PERSON only with those\n * three answered.\n */\nexport const ANNOTATION_ENTITY_KINDS = [\n 'cluster',\n 'organization',\n 'cluster-plan',\n 'cluster-plan-type',\n 'generation',\n 'channel',\n 'sales-plan',\n 'k8s-context',\n] as const\n\nexport type AnnotationEntityKind = (typeof ANNOTATION_ENTITY_KINDS)[number]\n\n/**\n * What a reader sees for each kind, in the singular.\n *\n * The label is here and not in the frontend, because the search page shows\n * results of every kind together and the backend writes the same word into a\n * log line. Two spellings of one kind would read as two kinds.\n */\nexport const ANNOTATION_ENTITY_KIND_LABELS: Record<\n AnnotationEntityKind,\n string\n> = {\n cluster: 'Cluster',\n organization: 'Organization',\n 'cluster-plan': 'Cluster plan',\n 'cluster-plan-type': 'Cluster plan type',\n generation: 'Generation',\n channel: 'Channel',\n 'sales-plan': 'Sales plan',\n 'k8s-context': 'Kubernetes context',\n}\n\n/**\n * What an annotation IS: a written note, or a tag out of the dictionary.\n *\n * One row type carries both, because both answer the same question \u2014 what does\n * a Camundi need to know about this entity? \u2014 and both are read, listed and\n * removed the same way. The difference is what the row points at: a note holds\n * `body`, and a tag holds `tag`.\n */\nexport const ANNOTATION_KINDS = ['note', 'tag'] as const\n\nexport type AnnotationKind = (typeof ANNOTATION_KINDS)[number]\n\n/** Who wrote an annotation. The same shape as `ApprovalActor`. */\nexport interface AnnotationActor {\n userId: string\n email: string\n}\n\n/**\n * One tag of the dictionary.\n *\n * A tag is its own row, and not a string on the annotation, for one reason:\n * a Camundi must be able to ask \"what else carries `partner`?\". A string on\n * each row answers that only with a scan, and it drifts: `Partner`, `partner `\n * and `partner` would be three tags that read as one.\n */\nexport interface AnnotationTagDto {\n id: string\n /** What a reader sees. The first spelling that anybody wrote wins. */\n name: string\n /** `name` through `normalizeTagName`. It is the identity of the tag. */\n normalizedName: string\n createdBy: AnnotationActor\n createdAt: string\n /**\n * How many LIVE entities carry this tag.\n *\n * It is counted at read time and never stored, so a removed assignment\n * lowers it with no second write. A list of the dictionary needs it to sort\n * by use, which is how a Camundi finds the tag that the team already uses\n * instead of inventing a second spelling of it.\n */\n usageCount: number\n}\n\n/**\n * One note, or one tag, on one entity.\n *\n * `entityKind` and `entityId` together name the entity. Neither is checked\n * against the fleet: the entity lives in another service, and an annotation\n * must survive its entity. See `entityLabel`.\n */\nexport interface AnnotationDto {\n id: string\n kind: AnnotationKind\n entityKind: AnnotationEntityKind\n entityId: string\n /**\n * What the entity was CALLED when somebody wrote the annotation.\n *\n * This is the only reason a search result stays readable after the entity is\n * deleted: the id of a cluster that no longer exists says nothing, and the\n * fleet can no longer answer what its name was. The label is a copy on\n * purpose, so it can be stale \u2014 it says what the entity was called then, not\n * what it is called now.\n */\n entityLabel?: string\n /** The text of a note. Absent on a tag. */\n body?: string\n /** The tag of a tag annotation. Absent on a note. */\n tag?: AnnotationTagDto\n createdBy: AnnotationActor\n createdAt: string\n updatedAt: string\n /** True when `body` was changed after it was written. */\n edited: boolean\n /**\n * How many times this row was written. A new one carries 1.\n *\n * An edit sends the version that it read, and the route refuses the write\n * when the row moved on since. Without it the tab that somebody left open at\n * breakfast silently replaces the edit they made at lunch, and neither write\n * tells them that one of the two is gone.\n */\n version: number\n}\n\n/** The annotations of one entity, in one answer. */\nexport interface EntityAnnotationsDto {\n entityKind: AnnotationEntityKind\n entityId: string\n notes: AnnotationDto[]\n tags: AnnotationDto[]\n /**\n * True when the entity carries more than `ANNOTATION_ENTITY_MAX` rows, so\n * the two lists above are the newest of them and not all of them.\n *\n * A panel that showed no sign of this would be a page that quietly stops\n * being the whole story, which is worse for documentation than a page that\n * says where the rest is.\n */\n hasMore: boolean\n}\n\n/**\n * What one entity carries, in the answer of a lookup over many entities.\n *\n * A table of 3000 clusters cannot read 3000 panels. The lookup answers the\n * two questions that a row of such a table needs: which tags, and whether a\n * colleague wrote something that a person must read before they act.\n */\nexport interface AnnotationLookupEntryDto {\n entityId: string\n /**\n * The live tag annotations of the entity, oldest first, and at most\n * `ANNOTATION_LOOKUP_TAGS_MAX` of them.\n */\n tags: AnnotationDto[]\n /** How many live tags the entity carries. More than `tags` holds is cut. */\n tagCount: number\n /** How many live notes the entity carries. */\n noteCount: number\n /** The newest live note, so a row can show it with no second read. */\n latestNote?: AnnotationDto\n}\n\n/**\n * The answer of a lookup. It holds ONLY the entities that carry something,\n * so an entity with no entry carries nothing.\n */\nexport interface AnnotationLookupDto {\n entityKind: AnnotationEntityKind\n entries: AnnotationLookupEntryDto[]\n}\n\n/**\n * The most entities that one lookup names.\n *\n * The same number as the largest cluster bulk operation, which is the table\n * that asks the largest question.\n */\nexport const ANNOTATION_LOOKUP_MAX_ENTITIES = 3000\n\n/**\n * The most tags that a lookup answers for ONE entity.\n *\n * An entity can carry any number of tags. Without this cap, one lookup of\n * 3000 entities has no bound on its rows. A row of a table shows a few chips,\n * and `tagCount` tells it how many it did not get.\n */\nexport const ANNOTATION_LOOKUP_TAGS_MAX = 20\n\n/**\n * The most annotations that the read of ONE entity answers with.\n *\n * The read has no page of its own: a panel is a thread that a person scrolls,\n * not a table they walk. But it cannot be unbounded either \u2014 an entity that\n * collects notes for a year would make every load of that page serialize\n * thousands of rows of up to `ANNOTATION_BODY_MAX` characters each. So the\n * answer is the NEWEST rows up to this number, with `hasMore` to say that\n * older ones exist. The search page reads the rest.\n */\nexport const ANNOTATION_ENTITY_MAX = 200\n\n/**\n * The longest note that a route accepts.\n *\n * A note is context for a colleague and not a document. The ceiling keeps one\n * paste of a log file out of every read of the entity page, and a person who\n * needs more has a handbook page to link to.\n */\nexport const ANNOTATION_BODY_MAX = 4000\n\n/** The longest tag name. A tag is a label, so it is short by design. */\nexport const ANNOTATION_TAG_NAME_MAX = 60\n\n/**\n * The longest free text that the search accepts.\n *\n * The VIEW needs it as much as the route: a field with no ceiling lets a\n * person paste more than the route takes, and the answer is then a 400 that\n * reads like a broken search. The field holds them here instead, and a deep\n * link that carries more is cut to this length rather than breaking the page.\n */\nexport const ANNOTATION_SEARCH_MAX_LENGTH = 200\n\n/** Annotations for each page when the caller asks for no number. */\nexport const ANNOTATION_PAGE_SIZE_DEFAULT = 100\n\n/**\n * The most annotations that one page can hold.\n *\n * The view needs this number too: a page that asked for more rows than the\n * service allows would get a 400 instead of rows.\n */\nexport const ANNOTATION_PAGE_SIZE_MAX = 500\n\n/**\n * The identity of a tag, from what a person typed.\n *\n * The case and the outer spaces go, and every run of inner whitespace becomes\n * one hyphen. `Partner`, ` partner ` and `Partner ` are then one tag, and\n * `key account` is `key-account`.\n *\n * Both sides run this: the backend writes the result into `normalizedName` and\n * holds it unique, and the frontend runs it to tell a person, before they\n * press the button, that the tag they are typing already exists.\n */\nexport function normalizeTagName(name: string): string {\n return name.trim().toLowerCase().replace(/\\s+/g, '-')\n}\n"],
|
|
5
|
+
"mappings": "AA4CO,MAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWO,MAAM,gCAGT;AAAA,EACF,SAAS;AAAA,EACT,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,cAAc;AAAA,EACd,eAAe;AACjB;AAUO,MAAM,mBAAmB,CAAC,QAAQ,KAAK;AAqIvC,MAAM,iCAAiC;AASvC,MAAM,6BAA6B;AAYnC,MAAM,wBAAwB;AAS9B,MAAM,sBAAsB;AAG5B,MAAM,0BAA0B;AAUhC,MAAM,+BAA+B;AAGrC,MAAM,+BAA+B;AAQrC,MAAM,2BAA2B;AAajC,SAAS,iBAAiB,MAAsB;AACrD,SAAO,KAAK,KAAK,EAAE,YAAY,EAAE,QAAQ,QAAQ,GAAG;AACtD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|