@memberjunction/core-entities 6.2.0-edge.2 → 6.2.0-edge.4
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/.tsbuildinfo +1 -1
- package/dist/custom/ConversationForkAccess.d.ts +15 -0
- package/dist/custom/ConversationForkAccess.d.ts.map +1 -0
- package/dist/custom/ConversationForkAccess.js +28 -0
- package/dist/custom/ConversationForkAccess.js.map +1 -0
- package/dist/custom/ConversationWriteAccess.d.ts +16 -0
- package/dist/custom/ConversationWriteAccess.d.ts.map +1 -0
- package/dist/custom/ConversationWriteAccess.js +34 -0
- package/dist/custom/ConversationWriteAccess.js.map +1 -0
- package/dist/custom/FormScope/FormContributionClaims.d.ts +20 -0
- package/dist/custom/FormScope/FormContributionClaims.d.ts.map +1 -0
- package/dist/custom/FormScope/FormContributionClaims.js +33 -0
- package/dist/custom/FormScope/FormContributionClaims.js.map +1 -0
- package/dist/custom/FormScope/FormContributionLifecycle.d.ts +43 -0
- package/dist/custom/FormScope/FormContributionLifecycle.d.ts.map +1 -0
- package/dist/custom/FormScope/FormContributionLifecycle.js +47 -0
- package/dist/custom/FormScope/FormContributionLifecycle.js.map +1 -0
- package/dist/custom/FormScope/FormContributionRow.d.ts +40 -0
- package/dist/custom/FormScope/FormContributionRow.d.ts.map +1 -0
- package/dist/custom/FormScope/FormContributionRow.js +84 -0
- package/dist/custom/FormScope/FormContributionRow.js.map +1 -0
- package/dist/custom/FormScope/FormPanelHides.d.ts +14 -0
- package/dist/custom/FormScope/FormPanelHides.d.ts.map +1 -0
- package/dist/custom/FormScope/FormPanelHides.js +32 -0
- package/dist/custom/FormScope/FormPanelHides.js.map +1 -0
- package/dist/custom/FormScope/FormScopeRules.d.ts +220 -0
- package/dist/custom/FormScope/FormScopeRules.d.ts.map +1 -0
- package/dist/custom/FormScope/FormScopeRules.js +295 -0
- package/dist/custom/FormScope/FormScopeRules.js.map +1 -0
- package/dist/custom/MJConversationBranchEntityExtended.d.ts +30 -0
- package/dist/custom/MJConversationBranchEntityExtended.d.ts.map +1 -0
- package/dist/custom/MJConversationBranchEntityExtended.js +120 -0
- package/dist/custom/MJConversationBranchEntityExtended.js.map +1 -0
- package/dist/custom/MJConversationDetailEntityExtended.d.ts.map +1 -1
- package/dist/custom/MJConversationDetailEntityExtended.js +15 -25
- package/dist/custom/MJConversationDetailEntityExtended.js.map +1 -1
- package/dist/custom/MJDashboardEntityExtended.d.ts.map +1 -1
- package/dist/custom/MJDashboardEntityExtended.js +3 -0
- package/dist/custom/MJDashboardEntityExtended.js.map +1 -1
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.d.ts.map +1 -1
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.js +14 -13
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.js.map +1 -1
- package/dist/engines/FileStorageEngine.d.ts +40 -0
- package/dist/engines/FileStorageEngine.d.ts.map +1 -1
- package/dist/engines/FileStorageEngine.js +49 -0
- package/dist/engines/FileStorageEngine.js.map +1 -1
- package/dist/engines/IdentityClaimEngine.d.ts +15 -2
- package/dist/engines/IdentityClaimEngine.d.ts.map +1 -1
- package/dist/engines/IdentityClaimEngine.js.map +1 -1
- package/dist/engines/QueryEngine.d.ts.map +1 -1
- package/dist/engines/QueryEngine.js +2 -1
- package/dist/engines/QueryEngine.js.map +1 -1
- package/dist/engines/UserInfoEngine.d.ts +16 -10
- package/dist/engines/UserInfoEngine.d.ts.map +1 -1
- package/dist/engines/UserInfoEngine.js +35 -25
- package/dist/engines/UserInfoEngine.js.map +1 -1
- package/dist/engines/artifacts.d.ts.map +1 -1
- package/dist/engines/artifacts.js +1 -0
- package/dist/engines/artifacts.js.map +1 -1
- package/dist/engines/component-metadata.d.ts +3 -1
- package/dist/engines/component-metadata.d.ts.map +1 -1
- package/dist/engines/component-metadata.js +12 -5
- package/dist/engines/component-metadata.js.map +1 -1
- package/dist/engines/conversations.d.ts +359 -34
- package/dist/engines/conversations.d.ts.map +1 -1
- package/dist/engines/conversations.js +611 -57
- package/dist/engines/conversations.js.map +1 -1
- package/dist/engines/interactive-forms.d.ts +128 -9
- package/dist/engines/interactive-forms.d.ts.map +1 -1
- package/dist/engines/interactive-forms.js +268 -14
- package/dist/engines/interactive-forms.js.map +1 -1
- package/dist/generated/entities/__mj.d.ts +6038 -393
- package/dist/generated/entities/__mj.d.ts.map +1 -1
- package/dist/generated/entities/__mj.js +26601 -20397
- package/dist/generated/entities/__mj.js.map +1 -1
- package/dist/generated/remote_operations.d.ts +262 -0
- package/dist/generated/remote_operations.d.ts.map +1 -1
- package/dist/generated/remote_operations.js +126 -0
- package/dist/generated/remote_operations.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/readme.md +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
|
|
2
|
+
/** The MJ Authorization that lets a person start a fork of a conversation (Fork from here, Edit or Regenerate as a fork). */
|
|
3
|
+
export declare const CONVERSATIONS_FORK_AUTHORIZATION = "Conversations: Fork";
|
|
4
|
+
/**
|
|
5
|
+
* True when `user` holds {@link CONVERSATIONS_FORK_AUTHORIZATION} through a role: an Allow grant and
|
|
6
|
+
* no Deny on any of the user's roles (a grant of a parent authorization counts). False without a user
|
|
7
|
+
* or a provider, and when the authorization is missing from the provider's metadata or inactive, so a
|
|
8
|
+
* deployment that has not synced it fails closed.
|
|
9
|
+
*/
|
|
10
|
+
export declare function UserCanFork(user: UserInfo | null | undefined, provider: IMetadataProvider | null | undefined): boolean;
|
|
11
|
+
/** The `MJ: User Settings` key of a person's forking switch; the value `off` turns forking off for them. */
|
|
12
|
+
export declare const CONVERSATIONS_FORKING_SETTING_KEY = "mj.conversations.forking.v1";
|
|
13
|
+
/** True unless the stored forking setting is `off`: no setting, an empty one or `on` mean forking is on. */
|
|
14
|
+
export declare function IsForkingSettingOn(value: string | null | undefined): boolean;
|
|
15
|
+
//# sourceMappingURL=ConversationForkAccess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationForkAccess.d.ts","sourceRoot":"","sources":["../../src/custom/ConversationForkAccess.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErG,6HAA6H;AAC7H,eAAO,MAAM,gCAAgC,wBAAwB,CAAC;AAEtE;;;;;GAKG;AACH,wBAAgB,WAAW,CACvB,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,EACjC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,GAC/C,OAAO,CAWT;AAED,4GAA4G;AAC5G,eAAO,MAAM,iCAAiC,gCAAgC,CAAC;AAE/E,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE5E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AuthorizationEvaluator } from '@memberjunction/core';
|
|
2
|
+
/** The MJ Authorization that lets a person start a fork of a conversation (Fork from here, Edit or Regenerate as a fork). */
|
|
3
|
+
export const CONVERSATIONS_FORK_AUTHORIZATION = 'Conversations: Fork';
|
|
4
|
+
/**
|
|
5
|
+
* True when `user` holds {@link CONVERSATIONS_FORK_AUTHORIZATION} through a role: an Allow grant and
|
|
6
|
+
* no Deny on any of the user's roles (a grant of a parent authorization counts). False without a user
|
|
7
|
+
* or a provider, and when the authorization is missing from the provider's metadata or inactive, so a
|
|
8
|
+
* deployment that has not synced it fails closed.
|
|
9
|
+
*/
|
|
10
|
+
export function UserCanFork(user, provider) {
|
|
11
|
+
if (!user || !provider) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const authorizations = provider.Authorizations ?? [];
|
|
15
|
+
const wanted = CONVERSATIONS_FORK_AUTHORIZATION.toLowerCase();
|
|
16
|
+
const grant = authorizations.find((a) => a.Name?.trim().toLowerCase() === wanted);
|
|
17
|
+
if (!grant) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return new AuthorizationEvaluator().UserCanExecuteWithAncestors(grant, user, authorizations);
|
|
21
|
+
}
|
|
22
|
+
/** The `MJ: User Settings` key of a person's forking switch; the value `off` turns forking off for them. */
|
|
23
|
+
export const CONVERSATIONS_FORKING_SETTING_KEY = 'mj.conversations.forking.v1';
|
|
24
|
+
/** True unless the stored forking setting is `off`: no setting, an empty one or `on` mean forking is on. */
|
|
25
|
+
export function IsForkingSettingOn(value) {
|
|
26
|
+
return (value ?? '').trim().toLowerCase() !== 'off';
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ConversationForkAccess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationForkAccess.js","sourceRoot":"","sources":["../../src/custom/ConversationForkAccess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAyC,MAAM,sBAAsB,CAAC;AAErG,6HAA6H;AAC7H,MAAM,CAAC,MAAM,gCAAgC,GAAG,qBAAqB,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACvB,IAAiC,EACjC,QAA8C;IAE9C,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,IAAI,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,gCAAgC,CAAC,WAAW,EAAE,CAAC;IAC9D,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;IAClF,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,sBAAsB,EAAE,CAAC,2BAA2B,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AACjG,CAAC;AAED,4GAA4G;AAC5G,MAAM,CAAC,MAAM,iCAAiC,GAAG,6BAA6B,CAAC;AAE/E,4GAA4G;AAC5G,MAAM,UAAU,kBAAkB,CAAC,KAAgC;IAC/D,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
2
|
+
/** Resource type ID for conversations in the resource permission system. */
|
|
3
|
+
export declare const CONVERSATIONS_RESOURCE_TYPE_ID = "81D4BC3D-9FEB-EF11-B01A-286B35C04427";
|
|
4
|
+
export interface ConversationWriteDecision {
|
|
5
|
+
Allowed: boolean;
|
|
6
|
+
Reason: string | null;
|
|
7
|
+
/** True only when the conversation loaded and the user is its owner. */
|
|
8
|
+
IsOwner: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Whether a user may write rows that belong to a conversation: the owner, or a user with
|
|
12
|
+
* an Edit or Owner grant. Server-side only; a non-database provider trusts the enforcement
|
|
13
|
+
* that already ran upstream.
|
|
14
|
+
*/
|
|
15
|
+
export declare function UserMayWriteConversation(provider: IMetadataProvider, user: UserInfo | null | undefined, conversationId: string): Promise<ConversationWriteDecision>;
|
|
16
|
+
//# sourceMappingURL=ConversationWriteAccess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationWriteAccess.d.ts","sourceRoot":"","sources":["../../src/custom/ConversationWriteAccess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKnE,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,yCAAyC,CAAC;AAErF,MAAM,WAAW,yBAAyB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC1C,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,yBAAyB,CAAC,CAuBpC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
2
|
+
import { ResourcePermissionEngine } from './ResourcePermissions/ResourcePermissionEngine.js';
|
|
3
|
+
/** Resource type ID for conversations in the resource permission system. */
|
|
4
|
+
export const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
|
|
5
|
+
/**
|
|
6
|
+
* Whether a user may write rows that belong to a conversation: the owner, or a user with
|
|
7
|
+
* an Edit or Owner grant. Server-side only; a non-database provider trusts the enforcement
|
|
8
|
+
* that already ran upstream.
|
|
9
|
+
*/
|
|
10
|
+
export async function UserMayWriteConversation(provider, user, conversationId) {
|
|
11
|
+
if (provider?.ProviderType !== 'Database' || !user) {
|
|
12
|
+
return { Allowed: true, Reason: null, IsOwner: false };
|
|
13
|
+
}
|
|
14
|
+
const conversation = await provider.GetEntityObject('MJ: Conversations', user);
|
|
15
|
+
if (!(await conversation.Load(conversationId))) {
|
|
16
|
+
return { Allowed: true, Reason: null, IsOwner: false };
|
|
17
|
+
}
|
|
18
|
+
if (conversation.UserID && UUIDsEqual(conversation.UserID, user.ID)) {
|
|
19
|
+
return { Allowed: true, Reason: null, IsOwner: true };
|
|
20
|
+
}
|
|
21
|
+
const engine = ResourcePermissionEngine.GetProviderInstance(provider, ResourcePermissionEngine);
|
|
22
|
+
await engine.Config(false, user);
|
|
23
|
+
const grant = engine
|
|
24
|
+
.GetUserAvailableResources(user, CONVERSATIONS_RESOURCE_TYPE_ID)
|
|
25
|
+
.find((p) => UUIDsEqual(p.ResourceRecordID, conversationId));
|
|
26
|
+
if (!grant) {
|
|
27
|
+
return { Allowed: false, Reason: 'You do not have access to this conversation.', IsOwner: false };
|
|
28
|
+
}
|
|
29
|
+
if (grant.PermissionLevel === 'Edit' || grant.PermissionLevel === 'Owner') {
|
|
30
|
+
return { Allowed: true, Reason: null, IsOwner: false };
|
|
31
|
+
}
|
|
32
|
+
return { Allowed: false, Reason: 'You have view-only access to this conversation.', IsOwner: false };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ConversationWriteAccess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationWriteAccess.js","sourceRoot":"","sources":["../../src/custom/ConversationWriteAccess.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAC;AAE1F,4EAA4E;AAC5E,MAAM,CAAC,MAAM,8BAA8B,GAAG,sCAAsC,CAAC;AASrF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC1C,QAA2B,EAC3B,IAAiC,EACjC,cAAsB;IAEtB,IAAI,QAAQ,EAAE,YAAY,KAAK,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC;QACjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAuB,mBAAmB,EAAE,IAAI,CAAC,CAAC;IACrG,IAAI,CAAC,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,wBAAwB,CAAC,mBAAmB,CAA2B,QAAQ,EAAE,wBAAwB,CAA6B,CAAC;IACtJ,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM;SACf,yBAAyB,CAAC,IAAI,EAAE,8BAA8B,CAAC;SAC/D,IAAI,CAAC,CAAC,CAA6B,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,8CAA8C,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACtG,CAAC;IACD,IAAI,KAAK,CAAC,eAAe,KAAK,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,OAAO,EAAE,CAAC;QACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iDAAiD,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACzG,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FormContributionSpecColumns } from './FormContributionRow.js';
|
|
2
|
+
/**
|
|
3
|
+
* The claim rules of `MJ: Entity Form Contributions`, checked in code before anything is written.
|
|
4
|
+
*
|
|
5
|
+
* The database enforces the same rules with CHECK constraints, but a refused row save comes after
|
|
6
|
+
* its component was written. Lives here, beside the spec-to-row mapper, so the server and the
|
|
7
|
+
* browser can check a row the same way.
|
|
8
|
+
*/
|
|
9
|
+
/** The columns the claim rules read. */
|
|
10
|
+
export type ContributionClaimColumns = Pick<FormContributionSpecColumns, 'Presentation' | 'Inclusion' | 'ChromeGroup' | 'RelatedEntityID' | 'RelatedJoinField' | 'ReplacesSectionKey' | 'ReplacesSectionKeys' | 'ReplacesFieldNames' | 'InSectionKey' | 'SectionPosition'>;
|
|
11
|
+
/**
|
|
12
|
+
* Why the database would refuse this row's claim, or null when it would not.
|
|
13
|
+
*
|
|
14
|
+
* Checks `CK_EntityFormContribution_OneClaim` (a related grid, one section, several sections,
|
|
15
|
+
* fields of one section, or a place inside a section — at most one), `BareNoChrome`,
|
|
16
|
+
* `JoinNeedsRelated` and `SectionPositionNeedsSection`. The message names the spec fields, so an
|
|
17
|
+
* agent can correct its spec.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ContributionClaimRefusal(row: ContributionClaimColumns): string | null;
|
|
20
|
+
//# sourceMappingURL=FormContributionClaims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionClaims.d.ts","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionClaims.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAEzE;;;;;;GAMG;AAEH,wCAAwC;AACxC,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,2BAA2B,EACjE,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,iBAAiB,GAAG,kBAAkB,GACrF,oBAAoB,GAAG,qBAAqB,GAAG,oBAAoB,GAAG,cAAc,GAAG,iBAAiB,CAAC,CAAC;AAWhH;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,GAAG,IAAI,CAerF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Each claim column, with the spec field an author sets to make that claim. */
|
|
2
|
+
const CLAIMS = [
|
|
3
|
+
{ Column: 'RelatedEntityID', SpecField: 'relatedEntity' },
|
|
4
|
+
{ Column: 'ReplacesSectionKey', SpecField: 'replacesSectionKey' },
|
|
5
|
+
{ Column: 'ReplacesSectionKeys', SpecField: 'replacesSectionKeys' },
|
|
6
|
+
{ Column: 'ReplacesFieldNames', SpecField: 'replacesFieldNames' },
|
|
7
|
+
{ Column: 'InSectionKey', SpecField: 'inSectionKey' },
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* Why the database would refuse this row's claim, or null when it would not.
|
|
11
|
+
*
|
|
12
|
+
* Checks `CK_EntityFormContribution_OneClaim` (a related grid, one section, several sections,
|
|
13
|
+
* fields of one section, or a place inside a section — at most one), `BareNoChrome`,
|
|
14
|
+
* `JoinNeedsRelated` and `SectionPositionNeedsSection`. The message names the spec fields, so an
|
|
15
|
+
* agent can correct its spec.
|
|
16
|
+
*/
|
|
17
|
+
export function ContributionClaimRefusal(row) {
|
|
18
|
+
const made = CLAIMS.filter((claim) => row[claim.Column] != null).map((claim) => claim.SpecField);
|
|
19
|
+
if (made.length > 1) {
|
|
20
|
+
return `A form contribution makes one claim at most, but this one sets ${made.join(' and ')}. Keep one of them.`;
|
|
21
|
+
}
|
|
22
|
+
if (row.Presentation === 'bare' && (row.Inclusion != null || row.ChromeGroup != null)) {
|
|
23
|
+
return 'A bare panel is never a rail item, so it takes no inclusion or chromeGroup.';
|
|
24
|
+
}
|
|
25
|
+
if (row.RelatedJoinField != null && row.RelatedEntityID == null) {
|
|
26
|
+
return 'relatedJoinField qualifies a related-grid claim, so it needs relatedEntity.';
|
|
27
|
+
}
|
|
28
|
+
if (row.SectionPosition != null && row.ReplacesFieldNames == null && row.InSectionKey == null) {
|
|
29
|
+
return 'sectionPosition places a panel inside a section, so it needs inSectionKey or replacesFieldNames.';
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=FormContributionClaims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionClaims.js","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionClaims.ts"],"names":[],"mappings":"AAeA,gFAAgF;AAChF,MAAM,MAAM,GAAiF;IACzF,EAAE,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,eAAe,EAAE;IACzD,EAAE,MAAM,EAAE,oBAAoB,EAAE,SAAS,EAAE,oBAAoB,EAAE;IACjE,EAAE,MAAM,EAAE,qBAAqB,EAAE,SAAS,EAAE,qBAAqB,EAAE;IACnE,EAAE,MAAM,EAAE,oBAAoB,EAAE,SAAS,EAAE,oBAAoB,EAAE;IACjE,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE;CACxD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAA6B;IAClE,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjG,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO,kEAAkE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC;IACrH,CAAC;IACD,IAAI,GAAG,CAAC,YAAY,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,EAAE,CAAC;QACpF,OAAO,6EAA6E,CAAC;IACzF,CAAC;IACD,IAAI,GAAG,CAAC,gBAAgB,IAAI,IAAI,IAAI,GAAG,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;QAC9D,OAAO,6EAA6E,CAAC;IACzF,CAAC;IACD,IAAI,GAAG,CAAC,eAAe,IAAI,IAAI,IAAI,GAAG,CAAC,kBAAkB,IAAI,IAAI,IAAI,GAAG,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;QAC5F,OAAO,kGAAkG,CAAC;IAC9G,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { MJComponentEntity, MJEntityFormContributionEntity } from '../../generated/entities/__mj.js';
|
|
2
|
+
/**
|
|
3
|
+
* How a form or panel goes live and is retired, as both write paths apply it: the server actions
|
|
4
|
+
* an agent calls, and the form's Manage drawer a person uses. Lives in a package both depend on,
|
|
5
|
+
* so the two cannot disagree about which row an activation retires.
|
|
6
|
+
*/
|
|
7
|
+
/** A form or panel's lifecycle, as the row stores it. */
|
|
8
|
+
export type FormLifecycleStatus = MJEntityFormContributionEntity['Status'];
|
|
9
|
+
/** The status of the Component a form or panel renders. */
|
|
10
|
+
export type FormComponentStatus = NonNullable<MJComponentEntity['Status']>;
|
|
11
|
+
/**
|
|
12
|
+
* The Component status that mirrors a form or panel's lifecycle: a live version is `Published`,
|
|
13
|
+
* a draft is `Draft`, a retired one is `Deprecated`. So a Component read on its own still says
|
|
14
|
+
* whether it is live. An unknown status reads as retired.
|
|
15
|
+
*/
|
|
16
|
+
export declare function FormLifecycleComponentStatus(status: FormLifecycleStatus): FormComponentStatus;
|
|
17
|
+
/** The columns that place a form or panel row: its entity, audience, status and key. */
|
|
18
|
+
export interface FormScopedRow {
|
|
19
|
+
ID: string;
|
|
20
|
+
EntityID: string;
|
|
21
|
+
Status: string;
|
|
22
|
+
Scope: string;
|
|
23
|
+
UserID: string | null;
|
|
24
|
+
RoleID: string | null;
|
|
25
|
+
/** Panels only. A full custom form has no key. */
|
|
26
|
+
ContributionKey?: string | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Whether two rows are for the same audience: the same scope, the same owner for a `User` row and
|
|
30
|
+
* the same role for a `Role` row. Every `Global` row is for the same audience.
|
|
31
|
+
*/
|
|
32
|
+
export declare function SameFormAudience(a: Pick<FormScopedRow, 'Scope' | 'UserID' | 'RoleID'>, b: Pick<FormScopedRow, 'Scope' | 'UserID' | 'RoleID'>): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The Active panels that activating `target` must retire first: the same entity, the same
|
|
35
|
+
* audience and the same key, other than the target itself. A panel with no key has none: two
|
|
36
|
+
* keyless panels are two panels.
|
|
37
|
+
*
|
|
38
|
+
* `UQ_EntityFormContribution_Key` allows one Active row per entity, key and audience, so these are
|
|
39
|
+
* demoted before the target is promoted, in the same transaction. Keys are trimmed and compared
|
|
40
|
+
* without regard to case, which mirrors the index's case-insensitive collation.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ActiveContributionSiblings<T extends FormScopedRow>(rows: readonly T[], target: FormScopedRow): T[];
|
|
43
|
+
//# sourceMappingURL=FormContributionLifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionLifecycle.d.ts","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionLifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAEvG;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,MAAM,mBAAmB,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;AAE3E,2DAA2D;AAC3D,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAO7F;AAED,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,EACrD,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,GACtD,OAAO,CAKT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,aAAa,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,CAAC,EAAE,CASlH"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
2
|
+
/**
|
|
3
|
+
* The Component status that mirrors a form or panel's lifecycle: a live version is `Published`,
|
|
4
|
+
* a draft is `Draft`, a retired one is `Deprecated`. So a Component read on its own still says
|
|
5
|
+
* whether it is live. An unknown status reads as retired.
|
|
6
|
+
*/
|
|
7
|
+
export function FormLifecycleComponentStatus(status) {
|
|
8
|
+
switch (status) {
|
|
9
|
+
case 'Active': return 'Published';
|
|
10
|
+
case 'Pending': return 'Draft';
|
|
11
|
+
case 'Inactive': return 'Deprecated';
|
|
12
|
+
default: return 'Deprecated';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether two rows are for the same audience: the same scope, the same owner for a `User` row and
|
|
17
|
+
* the same role for a `Role` row. Every `Global` row is for the same audience.
|
|
18
|
+
*/
|
|
19
|
+
export function SameFormAudience(a, b) {
|
|
20
|
+
if (a.Scope !== b.Scope)
|
|
21
|
+
return false;
|
|
22
|
+
if (a.Scope === 'User')
|
|
23
|
+
return UUIDsEqual(a.UserID ?? '', b.UserID ?? '');
|
|
24
|
+
if (a.Scope === 'Role')
|
|
25
|
+
return UUIDsEqual(a.RoleID ?? '', b.RoleID ?? '');
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The Active panels that activating `target` must retire first: the same entity, the same
|
|
30
|
+
* audience and the same key, other than the target itself. A panel with no key has none: two
|
|
31
|
+
* keyless panels are two panels.
|
|
32
|
+
*
|
|
33
|
+
* `UQ_EntityFormContribution_Key` allows one Active row per entity, key and audience, so these are
|
|
34
|
+
* demoted before the target is promoted, in the same transaction. Keys are trimmed and compared
|
|
35
|
+
* without regard to case, which mirrors the index's case-insensitive collation.
|
|
36
|
+
*/
|
|
37
|
+
export function ActiveContributionSiblings(rows, target) {
|
|
38
|
+
const key = (target.ContributionKey ?? '').trim().toLowerCase();
|
|
39
|
+
if (!key)
|
|
40
|
+
return [];
|
|
41
|
+
return rows.filter((row) => row.Status === 'Active'
|
|
42
|
+
&& !UUIDsEqual(row.ID, target.ID)
|
|
43
|
+
&& UUIDsEqual(row.EntityID, target.EntityID)
|
|
44
|
+
&& (row.ContributionKey ?? '').trim().toLowerCase() === key
|
|
45
|
+
&& SameFormAudience(row, target));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=FormContributionLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionLifecycle.js","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionLifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAepD;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAA2B;IACpE,QAAQ,MAAM,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC,CAAC,OAAO,WAAW,CAAC;QAClC,KAAK,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC;QAC/B,KAAK,UAAU,CAAC,CAAC,OAAO,YAAY,CAAC;QACrC,OAAO,CAAC,CAAC,OAAO,YAAY,CAAC;IACjC,CAAC;AACL,CAAC;AAcD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC5B,CAAqD,EACrD,CAAqD;IAErD,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAA0B,IAAkB,EAAE,MAAqB;IACzG,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CACvB,GAAG,CAAC,MAAM,KAAK,QAAQ;WACpB,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;WAC9B,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;WACzC,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG;WACxD,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type FormContributionSpec } from '@memberjunction/interactive-component-types/forms';
|
|
2
|
+
import type { MJEntityFormContributionEntity } from '../../generated/entities/__mj.js';
|
|
3
|
+
/**
|
|
4
|
+
* The spec-to-row mapping for `MJ: Entity Form Contributions`.
|
|
5
|
+
*
|
|
6
|
+
* The Create and Modify Form Contribution actions, and the Manage drawer's
|
|
7
|
+
* `FormPanelAdminService.SetPlacement` (`@memberjunction/ng-base-forms`), write rows through
|
|
8
|
+
* {@link ApplyContributionSpecToRow}, so the same spec produces the same row on every path.
|
|
9
|
+
* Lives here because both the server and the browser depend on this package.
|
|
10
|
+
*/
|
|
11
|
+
/** What {@link ApplyContributionSpecToRow} needs beyond the spec. */
|
|
12
|
+
export interface ContributionRowOptions {
|
|
13
|
+
/** The ID of the entity `spec.relatedEntity` names, or null. */
|
|
14
|
+
relatedEntityID: string | null;
|
|
15
|
+
/** The registered name of that entity, which the derived key embeds. */
|
|
16
|
+
relatedEntityName: string | null;
|
|
17
|
+
/** The component name that seeds the key of a panel with no other key. */
|
|
18
|
+
componentName: string | null;
|
|
19
|
+
}
|
|
20
|
+
/** The contribution columns a spec's `formContribution` block decides. */
|
|
21
|
+
export type FormContributionSpecColumns = Pick<MJEntityFormContributionEntity, 'Slot' | 'SortKey' | 'Presentation' | 'Title' | 'Icon' | 'Configuration' | 'Inclusion' | 'ChromeGroup' | 'RelatedEntityID' | 'RelatedJoinField' | 'ReplacesSectionKey' | 'ReplacesSectionKeys' | 'ReplacesFieldNames' | 'InSectionKey' | 'SectionPosition' | 'ContributionKey'>;
|
|
22
|
+
/**
|
|
23
|
+
* Writes every column a contribution spec decides onto a row, and clears each claim column the
|
|
24
|
+
* spec does not set, so a row that changes its claim keeps nothing of the old one.
|
|
25
|
+
*
|
|
26
|
+
* The row it writes satisfies these CHECK constraints: `ReplacesFieldNamesShape` and
|
|
27
|
+
* `ReplacesSectionKeysShape` (an empty name list is stored as null), `JoinNeedsRelated` (a join
|
|
28
|
+
* field only with a related entity), `SectionPositionNeedsSection` (a position only for a panel
|
|
29
|
+
* drawn inside a section) and `BareNoChrome` (no Inclusion or ChromeGroup on a bare panel). It
|
|
30
|
+
* does not check `OneClaim`: a spec that makes two claims produces a row the database refuses.
|
|
31
|
+
*
|
|
32
|
+
* The caller resolves the related entity, because that needs metadata, and writes the columns
|
|
33
|
+
* that are not in the spec (scope, owner, status, precedence, names).
|
|
34
|
+
*/
|
|
35
|
+
export declare function ApplyContributionSpecToRow(row: FormContributionSpecColumns, spec: FormContributionSpec, opts: ContributionRowOptions): void;
|
|
36
|
+
/** The columns a spec decides, on a new object, for checking a spec before any row is written. */
|
|
37
|
+
export declare function ContributionSpecColumns(spec: FormContributionSpec, opts: ContributionRowOptions): FormContributionSpecColumns;
|
|
38
|
+
/** The names in a `ReplacesFieldNames` or `ReplacesSectionKeys` cell. Empty for a cell that is not a JSON array. */
|
|
39
|
+
export declare function ParseClaimedFieldNames(raw: string | null | undefined): string[];
|
|
40
|
+
//# sourceMappingURL=FormContributionRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionRow.d.ts","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionRow.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,KAAK,oBAAoB,EAC5B,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAEpF;;;;;;;GAOG;AAEH,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACnC,gEAAgE;IAChE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,0EAA0E;IAC1E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,0EAA0E;AAC1E,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,8BAA8B,EACvE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,eAAe,GAAG,WAAW,GAAG,aAAa,GACtG,iBAAiB,GAAG,kBAAkB,GAAG,oBAAoB,GAAG,qBAAqB,GAAG,oBAAoB,GAC5G,cAAc,GAAG,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;AAE9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACtC,GAAG,EAAE,2BAA2B,EAChC,IAAI,EAAE,oBAAoB,EAC1B,IAAI,EAAE,sBAAsB,GAC7B,IAAI,CAKN;AAED,kGAAkG;AAClG,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,sBAAsB,GAAG,2BAA2B,CAS7H;AAED,oHAAoH;AACpH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAI/E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { SafeJSONParse } from '@memberjunction/global';
|
|
2
|
+
import { DEFAULT_FORM_CONTRIBUTION_SLOT, ResolveContributionWriteKey, } from '@memberjunction/interactive-component-types/forms';
|
|
3
|
+
/**
|
|
4
|
+
* Writes every column a contribution spec decides onto a row, and clears each claim column the
|
|
5
|
+
* spec does not set, so a row that changes its claim keeps nothing of the old one.
|
|
6
|
+
*
|
|
7
|
+
* The row it writes satisfies these CHECK constraints: `ReplacesFieldNamesShape` and
|
|
8
|
+
* `ReplacesSectionKeysShape` (an empty name list is stored as null), `JoinNeedsRelated` (a join
|
|
9
|
+
* field only with a related entity), `SectionPositionNeedsSection` (a position only for a panel
|
|
10
|
+
* drawn inside a section) and `BareNoChrome` (no Inclusion or ChromeGroup on a bare panel). It
|
|
11
|
+
* does not check `OneClaim`: a spec that makes two claims produces a row the database refuses.
|
|
12
|
+
*
|
|
13
|
+
* The caller resolves the related entity, because that needs metadata, and writes the columns
|
|
14
|
+
* that are not in the spec (scope, owner, status, precedence, names).
|
|
15
|
+
*/
|
|
16
|
+
export function ApplyContributionSpecToRow(row, spec, opts) {
|
|
17
|
+
applyPlacement(row, spec);
|
|
18
|
+
applyChrome(row, spec);
|
|
19
|
+
applyClaims(row, spec, opts.relatedEntityID);
|
|
20
|
+
row.ContributionKey = ResolveContributionWriteKey(spec, opts.relatedEntityName, opts.componentName);
|
|
21
|
+
}
|
|
22
|
+
/** The columns a spec decides, on a new object, for checking a spec before any row is written. */
|
|
23
|
+
export function ContributionSpecColumns(spec, opts) {
|
|
24
|
+
const row = {
|
|
25
|
+
Slot: DEFAULT_FORM_CONTRIBUTION_SLOT, SortKey: 0, Presentation: 'panel', Title: null, Icon: null,
|
|
26
|
+
Configuration: null, Inclusion: null, ChromeGroup: null, RelatedEntityID: null, RelatedJoinField: null,
|
|
27
|
+
ReplacesSectionKey: null, ReplacesSectionKeys: null, ReplacesFieldNames: null, InSectionKey: null,
|
|
28
|
+
SectionPosition: null, ContributionKey: null,
|
|
29
|
+
};
|
|
30
|
+
ApplyContributionSpecToRow(row, spec, opts);
|
|
31
|
+
return row;
|
|
32
|
+
}
|
|
33
|
+
/** The names in a `ReplacesFieldNames` or `ReplacesSectionKeys` cell. Empty for a cell that is not a JSON array. */
|
|
34
|
+
export function ParseClaimedFieldNames(raw) {
|
|
35
|
+
if (!raw || raw.trim().length === 0)
|
|
36
|
+
return [];
|
|
37
|
+
const parsed = SafeJSONParse(raw, false);
|
|
38
|
+
return Array.isArray(parsed) ? cleanNames(parsed) : [];
|
|
39
|
+
}
|
|
40
|
+
function applyPlacement(row, spec) {
|
|
41
|
+
row.Slot = spec.slot ?? DEFAULT_FORM_CONTRIBUTION_SLOT;
|
|
42
|
+
row.SortKey = spec.sortKey ?? 0;
|
|
43
|
+
row.Presentation = spec.presentation;
|
|
44
|
+
row.Title = spec.title;
|
|
45
|
+
row.Icon = spec.icon ?? null;
|
|
46
|
+
row.Configuration = spec.configuration && Object.keys(spec.configuration).length > 0
|
|
47
|
+
? JSON.stringify(spec.configuration) : null;
|
|
48
|
+
}
|
|
49
|
+
/** A bare panel is never a rail item, so it carries no rail metadata. */
|
|
50
|
+
function applyChrome(row, spec) {
|
|
51
|
+
const bare = spec.presentation === 'bare';
|
|
52
|
+
row.Inclusion = bare ? null : spec.inclusion ?? null;
|
|
53
|
+
row.ChromeGroup = bare ? null : spec.chromeGroup ?? null;
|
|
54
|
+
}
|
|
55
|
+
function applyClaims(row, spec, relatedEntityID) {
|
|
56
|
+
row.RelatedEntityID = relatedEntityID;
|
|
57
|
+
row.RelatedJoinField = relatedEntityID ? spec.relatedJoinField?.trim() || null : null;
|
|
58
|
+
const fieldNames = cleanNames(spec.replacesFieldNames);
|
|
59
|
+
row.ReplacesFieldNames = jsonArrayOrNull(fieldNames);
|
|
60
|
+
// One section is stored in the single-key column whichever spec field named it.
|
|
61
|
+
const sections = cleanNames([
|
|
62
|
+
...(spec.replacesSectionKey ? [spec.replacesSectionKey] : []),
|
|
63
|
+
...(spec.replacesSectionKeys ?? []),
|
|
64
|
+
]);
|
|
65
|
+
row.ReplacesSectionKey = sections.length === 1 ? sections[0] : null;
|
|
66
|
+
row.ReplacesSectionKeys = sections.length > 1 ? JSON.stringify(sections) : null;
|
|
67
|
+
const inSection = spec.inSectionKey?.trim() || null;
|
|
68
|
+
row.InSectionKey = inSection;
|
|
69
|
+
row.SectionPosition = inSection || fieldNames.length > 0 ? spec.sectionPosition ?? null : null;
|
|
70
|
+
}
|
|
71
|
+
/** Trimmed, non-empty names without repeats, in their first-seen order. */
|
|
72
|
+
function cleanNames(names) {
|
|
73
|
+
const out = [];
|
|
74
|
+
for (const raw of names ?? []) {
|
|
75
|
+
const name = typeof raw === 'string' ? raw.trim() : '';
|
|
76
|
+
if (name.length > 0 && !out.includes(name))
|
|
77
|
+
out.push(name);
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
function jsonArrayOrNull(names) {
|
|
82
|
+
return names.length > 0 ? JSON.stringify(names) : null;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=FormContributionRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormContributionRow.js","sourceRoot":"","sources":["../../../src/custom/FormScope/FormContributionRow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACH,8BAA8B,EAC9B,2BAA2B,GAE9B,MAAM,mDAAmD,CAAC;AA4B3D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CACtC,GAAgC,EAChC,IAA0B,EAC1B,IAA4B;IAE5B,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACvB,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC7C,GAAG,CAAC,eAAe,GAAG,2BAA2B,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;AACxG,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,uBAAuB,CAAC,IAA0B,EAAE,IAA4B;IAC5F,MAAM,GAAG,GAAgC;QACrC,IAAI,EAAE,8BAA8B,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;QAChG,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI;QACtG,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;QACjG,eAAe,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI;KAC/C,CAAC;IACF,0BAA0B,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC;AACf,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,sBAAsB,CAAC,GAA8B;IACjE,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,aAAa,CAAW,GAAG,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAS,cAAc,CAAC,GAAgC,EAAE,IAA0B;IAChF,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,8BAA8B,CAAC;IACvD,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;IAChC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACrC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACvB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;IAC7B,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC;QAChF,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,yEAAyE;AACzE,SAAS,WAAW,CAAC,GAAgC,EAAE,IAA0B;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC;IAC1C,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;IACrD,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC;AAC7D,CAAC;AAED,SAAS,WAAW,CAAC,GAAgC,EAAE,IAA0B,EAAE,eAA8B;IAC7G,GAAG,CAAC,eAAe,GAAG,eAAe,CAAC;IACtC,GAAG,CAAC,gBAAgB,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtF,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACvD,GAAG,CAAC,kBAAkB,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAErD,gFAAgF;IAChF,MAAM,QAAQ,GAAG,UAAU,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC;KACtC,CAAC,CAAC;IACH,GAAG,CAAC,kBAAkB,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,GAAG,CAAC,mBAAmB,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhF,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACpD,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,eAAe,GAAG,SAAS,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACnG,CAAC;AAED,2EAA2E;AAC3E,SAAS,UAAU,CAAC,KAA2C;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAe;IACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a user's hidden panels are stored.
|
|
3
|
+
*
|
|
4
|
+
* A user can hide a panel someone else put on their form and bring it back later. The list is an
|
|
5
|
+
* `MJ: User Settings` value per entity: a JSON array of panel keys. Lives here so the browser,
|
|
6
|
+
* which applies the hides, and the server, which reports the form a user sees, read one key.
|
|
7
|
+
*/
|
|
8
|
+
/** `MJ: User Settings` key prefix for the per-entity list of hidden panels. */
|
|
9
|
+
export declare const FORM_PANEL_HIDE_SETTING_PREFIX = "mj.formPanels.hidden.";
|
|
10
|
+
/** The settings key for one entity. Trimmed and lowercased, so case variants share one row. */
|
|
11
|
+
export declare function FormPanelHideSettingKey(entityName: string): string;
|
|
12
|
+
/** The hidden keys in a stored setting, trimmed and without repeats. A missing or malformed value hides nothing. */
|
|
13
|
+
export declare function ParseHiddenFormPanelKeys(raw: string | null | undefined): string[];
|
|
14
|
+
//# sourceMappingURL=FormPanelHides.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormPanelHides.d.ts","sourceRoot":"","sources":["../../../src/custom/FormScope/FormPanelHides.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,8BAA8B,0BAA0B,CAAC;AAEtE,+FAA+F;AAC/F,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,oHAAoH;AACpH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAWjF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SafeJSONParse } from '@memberjunction/global';
|
|
2
|
+
/**
|
|
3
|
+
* Where a user's hidden panels are stored.
|
|
4
|
+
*
|
|
5
|
+
* A user can hide a panel someone else put on their form and bring it back later. The list is an
|
|
6
|
+
* `MJ: User Settings` value per entity: a JSON array of panel keys. Lives here so the browser,
|
|
7
|
+
* which applies the hides, and the server, which reports the form a user sees, read one key.
|
|
8
|
+
*/
|
|
9
|
+
/** `MJ: User Settings` key prefix for the per-entity list of hidden panels. */
|
|
10
|
+
export const FORM_PANEL_HIDE_SETTING_PREFIX = 'mj.formPanels.hidden.';
|
|
11
|
+
/** The settings key for one entity. Trimmed and lowercased, so case variants share one row. */
|
|
12
|
+
export function FormPanelHideSettingKey(entityName) {
|
|
13
|
+
return FORM_PANEL_HIDE_SETTING_PREFIX + (entityName ?? '').trim().toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
/** The hidden keys in a stored setting, trimmed and without repeats. A missing or malformed value hides nothing. */
|
|
16
|
+
export function ParseHiddenFormPanelKeys(raw) {
|
|
17
|
+
if (!raw)
|
|
18
|
+
return [];
|
|
19
|
+
const parsed = SafeJSONParse(raw, false);
|
|
20
|
+
if (!Array.isArray(parsed))
|
|
21
|
+
return [];
|
|
22
|
+
const keys = [];
|
|
23
|
+
for (const item of parsed) {
|
|
24
|
+
if (typeof item !== 'string')
|
|
25
|
+
continue;
|
|
26
|
+
const key = item.trim();
|
|
27
|
+
if (key && !keys.includes(key))
|
|
28
|
+
keys.push(key);
|
|
29
|
+
}
|
|
30
|
+
return keys;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=FormPanelHides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormPanelHides.js","sourceRoot":"","sources":["../../../src/custom/FormScope/FormPanelHides.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;;GAMG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAC;AAEtE,+FAA+F;AAC/F,MAAM,UAAU,uBAAuB,CAAC,UAAkB;IACtD,OAAO,8BAA8B,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpF,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,wBAAwB,CAAC,GAA8B;IACnE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,aAAa,CAAU,GAAG,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QACxB,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|