@webiny/app-admin 6.0.0-rc.2 → 6.0.0-rc.3

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.
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useEffect, useRef } from "react";
2
2
  import { Button, Grid, Icon, IconButton, Input, Switch } from "@webiny/admin-ui";
3
3
  import { Form, useBind } from "@webiny/form";
4
4
  import { validation } from "@webiny/validation";
@@ -42,16 +42,25 @@ export const LexicalLinkForm = ({
42
42
  }))));
43
43
  };
44
44
  const UrlInput = () => {
45
+ const inputRef = useRef(null);
45
46
  const urlBind = useBind({
46
47
  name: "url",
47
48
  validators: validation.create("required,url")
48
49
  });
50
+ useEffect(() => {
51
+ if (inputRef.current) {
52
+ setTimeout(() => {
53
+ inputRef.current?.focus();
54
+ }, 10);
55
+ }
56
+ }, []);
49
57
  const openInNewTab = () => {
50
58
  if (urlBind.validation.isValid !== false && urlBind.value) {
51
59
  window.open(urlBind.value, "_blank");
52
60
  }
53
61
  };
54
62
  return /*#__PURE__*/React.createElement(Input, Object.assign({}, urlBind, {
63
+ inputRef: ref => inputRef.current = ref,
55
64
  variant: "secondary",
56
65
  placeholder: "Enter link",
57
66
  autoFocus: true,
@@ -1 +1 @@
1
- {"version":3,"names":["React","Button","Grid","Icon","IconButton","Input","Switch","Form","useBind","validation","ReactComponent","GlobeIcon","OpenInNew","RemoveLink","LexicalLinkForm","linkData","onSave","removeLink","onSubmit","data","createElement","validateOnFirstSubmit","submitOnEnter","form","className","gap","Column","span","UrlInput","TargetSwitch","variant","text","onClick","icon","label","submit","urlBind","name","validators","create","openInNewTab","isValid","value","window","open","Object","assign","placeholder","autoFocus","startIcon","endIcon","targetBind","defaultValue","checked","onChange"],"sources":["LexicalLinkForm.tsx"],"sourcesContent":["import React from \"react\";\nimport type { FloatingLinkEditorPlugin } from \"@webiny/lexical-editor\";\nimport { Button, Grid, Icon, IconButton, Input, Switch } from \"@webiny/admin-ui\";\nimport { Form, useBind } from \"@webiny/form\";\nimport { validation } from \"@webiny/validation\";\nimport { ReactComponent as GlobeIcon } from \"@webiny/icons/language.svg\";\nimport { ReactComponent as OpenInNew } from \"@webiny/icons/open_in_new.svg\";\nimport { ReactComponent as RemoveLink } from \"@webiny/icons/link_off.svg\";\n\ntype LexicalLinkForm = NonNullable<\n React.ComponentProps<typeof FloatingLinkEditorPlugin>[\"LinkForm\"]\n>;\ntype LinkFormProps = React.ComponentProps<LexicalLinkForm>;\n\nexport const LexicalLinkForm = ({ linkData, onSave, removeLink }: LinkFormProps) => {\n const onSubmit = (data: LinkFormProps[\"linkData\"]) => {\n onSave(data);\n };\n\n return (\n <Form data={linkData} onSubmit={onSubmit} validateOnFirstSubmit submitOnEnter>\n {form => (\n <div className={\"p-md\"}>\n <Grid gap={\"small\"}>\n <Grid.Column span={12}>\n <UrlInput />\n </Grid.Column>\n </Grid>\n <div className={\"flex w-full items-center justify-between mt-sm gap-sm\"}>\n <TargetSwitch />\n <Button\n variant={\"ghost\"}\n text={`Remove link`}\n className={\"text-destructive-primary! [&_svg]:fill-destructive\"}\n onClick={removeLink}\n icon={<Icon label={\"Remove link\"} icon={<RemoveLink />} />}\n />\n <Button variant={\"primary\"} text={`Save`} onClick={form.submit} />\n </div>\n </div>\n )}\n </Form>\n );\n};\n\nconst UrlInput = () => {\n const urlBind = useBind({\n name: \"url\",\n validators: validation.create(\"required,url\")\n });\n\n const openInNewTab = () => {\n if (urlBind.validation.isValid !== false && urlBind.value) {\n window.open(urlBind.value, \"_blank\");\n }\n };\n\n return (\n <Input\n {...urlBind}\n variant={\"secondary\"}\n placeholder={\"Enter link\"}\n autoFocus={true}\n startIcon={<Icon label=\"globe\" icon={<GlobeIcon />} />}\n endIcon={<IconButton variant=\"ghost\" icon={<OpenInNew />} onClick={openInNewTab} />}\n />\n );\n};\n\nconst TargetSwitch = () => {\n const targetBind = useBind({\n name: \"target\",\n defaultValue: \"_self\"\n });\n\n return (\n <Switch\n checked={targetBind.value === \"_blank\"}\n label={\"Open in new tab\"}\n onChange={value => {\n targetBind.onChange(value === true ? \"_blank\" : \"_self\");\n }}\n />\n );\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","useEffect","useRef","Button","Grid","Icon","IconButton","Input","Switch","Form","useBind","validation","ReactComponent","GlobeIcon","OpenInNew","RemoveLink","LexicalLinkForm","linkData","onSave","removeLink","onSubmit","data","createElement","validateOnFirstSubmit","submitOnEnter","form","className","gap","Column","span","UrlInput","TargetSwitch","variant","text","onClick","icon","label","submit","inputRef","urlBind","name","validators","create","current","setTimeout","focus","openInNewTab","isValid","value","window","open","Object","assign","ref","placeholder","autoFocus","startIcon","endIcon","targetBind","defaultValue","checked","onChange"],"sources":["LexicalLinkForm.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport type { FloatingLinkEditorPlugin } from \"@webiny/lexical-editor\";\nimport { Button, Grid, Icon, IconButton, Input, Switch } from \"@webiny/admin-ui\";\nimport { Form, useBind } from \"@webiny/form\";\nimport { validation } from \"@webiny/validation\";\nimport { ReactComponent as GlobeIcon } from \"@webiny/icons/language.svg\";\nimport { ReactComponent as OpenInNew } from \"@webiny/icons/open_in_new.svg\";\nimport { ReactComponent as RemoveLink } from \"@webiny/icons/link_off.svg\";\n\ntype LexicalLinkForm = NonNullable<\n React.ComponentProps<typeof FloatingLinkEditorPlugin>[\"LinkForm\"]\n>;\ntype LinkFormProps = React.ComponentProps<LexicalLinkForm>;\n\nexport const LexicalLinkForm = ({ linkData, onSave, removeLink }: LinkFormProps) => {\n const onSubmit = (data: LinkFormProps[\"linkData\"]) => {\n onSave(data);\n };\n\n return (\n <Form data={linkData} onSubmit={onSubmit} validateOnFirstSubmit submitOnEnter>\n {form => (\n <div className={\"p-md\"}>\n <Grid gap={\"small\"}>\n <Grid.Column span={12}>\n <UrlInput />\n </Grid.Column>\n </Grid>\n <div className={\"flex w-full items-center justify-between mt-sm gap-sm\"}>\n <TargetSwitch />\n <Button\n variant={\"ghost\"}\n text={`Remove link`}\n className={\"text-destructive-primary! [&_svg]:fill-destructive\"}\n onClick={removeLink}\n icon={<Icon label={\"Remove link\"} icon={<RemoveLink />} />}\n />\n <Button variant={\"primary\"} text={`Save`} onClick={form.submit} />\n </div>\n </div>\n )}\n </Form>\n );\n};\n\nconst UrlInput = () => {\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n const urlBind = useBind({\n name: \"url\",\n validators: validation.create(\"required,url\")\n });\n\n useEffect(() => {\n if (inputRef.current) {\n setTimeout(() => {\n inputRef.current?.focus();\n }, 10);\n }\n }, []);\n\n const openInNewTab = () => {\n if (urlBind.validation.isValid !== false && urlBind.value) {\n window.open(urlBind.value, \"_blank\");\n }\n };\n\n return (\n <Input\n {...urlBind}\n inputRef={ref => (inputRef.current = ref)}\n variant={\"secondary\"}\n placeholder={\"Enter link\"}\n autoFocus={true}\n startIcon={<Icon label=\"globe\" icon={<GlobeIcon />} />}\n endIcon={<IconButton variant=\"ghost\" icon={<OpenInNew />} onClick={openInNewTab} />}\n />\n );\n};\n\nconst TargetSwitch = () => {\n const targetBind = useBind({\n name: \"target\",\n defaultValue: \"_self\"\n });\n\n return (\n <Switch\n checked={targetBind.value === \"_blank\"}\n label={\"Open in new tab\"}\n onChange={value => {\n targetBind.onChange(value === true ? \"_blank\" : \"_self\");\n }}\n />\n );\n};\n"],"mappings":"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","ignoreList":[]}
@@ -6,10 +6,12 @@ declare function CanUseTeams({ children }: ChildrenProps): React.JSX.Element | n
6
6
  declare function CanUsePrivateFiles({ children }: ChildrenProps): React.JSX.Element | null;
7
7
  declare function CanUseFileManagerThreatDetection({ children }: ChildrenProps): React.JSX.Element | null;
8
8
  declare function CanUseWorkflows({ children }: ChildrenProps): React.JSX.Element | null;
9
+ declare function CanUseHcmsFieldPermissions({ children }: ChildrenProps): React.JSX.Element | null;
9
10
  export declare const Wcp: {
10
11
  CanUseTeams: typeof CanUseTeams;
11
12
  CanUsePrivateFiles: typeof CanUsePrivateFiles;
12
13
  CanUseFileManagerThreatDetection: typeof CanUseFileManagerThreatDetection;
13
14
  CanUseWorkflows: typeof CanUseWorkflows;
15
+ CanUseHcmsFieldPermissions: typeof CanUseHcmsFieldPermissions;
14
16
  };
15
17
  export {};
package/components/Wcp.js CHANGED
@@ -24,11 +24,18 @@ function CanUseWorkflows({
24
24
  const wcp = useWcp();
25
25
  return wcp.canUseWorkflows() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
26
26
  }
27
+ function CanUseHcmsFieldPermissions({
28
+ children
29
+ }) {
30
+ const wcp = useWcp();
31
+ return wcp.canUseHcmsFieldPermissions() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
32
+ }
27
33
  export const Wcp = {
28
34
  CanUseTeams,
29
35
  CanUsePrivateFiles,
30
36
  CanUseFileManagerThreatDetection,
31
- CanUseWorkflows
37
+ CanUseWorkflows,
38
+ CanUseHcmsFieldPermissions
32
39
  };
33
40
 
34
41
  //# sourceMappingURL=Wcp.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["React","useWcp","CanUseTeams","children","wcp","canUseTeams","createElement","Fragment","CanUsePrivateFiles","canUsePrivateFiles","CanUseFileManagerThreatDetection","canUseFileManagerThreatDetection","CanUseWorkflows","canUseWorkflows","Wcp"],"sources":["Wcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { useWcp } from \"~/presentation/wcp/useWcp.js\";\n\ninterface ChildrenProps {\n children: React.ReactNode;\n}\n\nfunction CanUseTeams({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseTeams() ? <>{children}</> : null;\n}\n\nfunction CanUsePrivateFiles({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUsePrivateFiles() ? <>{children}</> : null;\n}\n\nfunction CanUseFileManagerThreatDetection({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseFileManagerThreatDetection() ? <>{children}</> : null;\n}\n\nfunction CanUseWorkflows({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseWorkflows() ? <>{children}</> : null;\n}\n\nexport const Wcp = {\n CanUseTeams,\n CanUsePrivateFiles,\n CanUseFileManagerThreatDetection,\n CanUseWorkflows\n};\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,MAAM;AAMf,SAASC,WAAWA,CAAC;EAAEC;AAAwB,CAAC,EAAE;EAC9C,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACC,WAAW,CAAC,CAAC,gBAAGL,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACrD;AAEA,SAASK,kBAAkBA,CAAC;EAAEL;AAAwB,CAAC,EAAE;EACrD,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACK,kBAAkB,CAAC,CAAC,gBAAGT,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC5D;AAEA,SAASO,gCAAgCA,CAAC;EAAEP;AAAwB,CAAC,EAAE;EACnE,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACO,gCAAgC,CAAC,CAAC,gBAAGX,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC1E;AAEA,SAASS,eAAeA,CAAC;EAAET;AAAwB,CAAC,EAAE;EAClD,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACS,eAAe,CAAC,CAAC,gBAAGb,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACzD;AAEA,OAAO,MAAMW,GAAG,GAAG;EACfZ,WAAW;EACXM,kBAAkB;EAClBE,gCAAgC;EAChCE;AACJ,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["React","useWcp","CanUseTeams","children","wcp","canUseTeams","createElement","Fragment","CanUsePrivateFiles","canUsePrivateFiles","CanUseFileManagerThreatDetection","canUseFileManagerThreatDetection","CanUseWorkflows","canUseWorkflows","CanUseHcmsFieldPermissions","canUseHcmsFieldPermissions","Wcp"],"sources":["Wcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { useWcp } from \"~/presentation/wcp/useWcp.js\";\n\ninterface ChildrenProps {\n children: React.ReactNode;\n}\n\nfunction CanUseTeams({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseTeams() ? <>{children}</> : null;\n}\n\nfunction CanUsePrivateFiles({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUsePrivateFiles() ? <>{children}</> : null;\n}\n\nfunction CanUseFileManagerThreatDetection({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseFileManagerThreatDetection() ? <>{children}</> : null;\n}\n\nfunction CanUseWorkflows({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseWorkflows() ? <>{children}</> : null;\n}\n\nfunction CanUseHcmsFieldPermissions({ children }: ChildrenProps) {\n const wcp = useWcp();\n return wcp.canUseHcmsFieldPermissions() ? <>{children}</> : null;\n}\n\nexport const Wcp = {\n CanUseTeams,\n CanUsePrivateFiles,\n CanUseFileManagerThreatDetection,\n CanUseWorkflows,\n CanUseHcmsFieldPermissions\n};\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,MAAM;AAMf,SAASC,WAAWA,CAAC;EAAEC;AAAwB,CAAC,EAAE;EAC9C,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACC,WAAW,CAAC,CAAC,gBAAGL,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACrD;AAEA,SAASK,kBAAkBA,CAAC;EAAEL;AAAwB,CAAC,EAAE;EACrD,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACK,kBAAkB,CAAC,CAAC,gBAAGT,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC5D;AAEA,SAASO,gCAAgCA,CAAC;EAAEP;AAAwB,CAAC,EAAE;EACnE,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACO,gCAAgC,CAAC,CAAC,gBAAGX,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC1E;AAEA,SAASS,eAAeA,CAAC;EAAET;AAAwB,CAAC,EAAE;EAClD,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACS,eAAe,CAAC,CAAC,gBAAGb,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACzD;AAEA,SAASW,0BAA0BA,CAAC;EAAEX;AAAwB,CAAC,EAAE;EAC7D,MAAMC,GAAG,GAAGH,MAAM,CAAC,CAAC;EACpB,OAAOG,GAAG,CAACW,0BAA0B,CAAC,CAAC,gBAAGf,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACpE;AAEA,OAAO,MAAMa,GAAG,GAAG;EACfd,WAAW;EACXM,kBAAkB;EAClBE,gCAAgC;EAChCE,eAAe;EACfE;AACJ,CAAC","ignoreList":[]}
@@ -1,3 +1,4 @@
1
+ export { useDialogs } from "../../components/Dialogs/useDialogs.js";
1
2
  export { Logo } from "../../base/ui/Logo.js";
2
3
  export { TenantSelector } from "../../base/ui/TenantSelector.js";
3
4
  export { LexicalEditor } from "../../components/LexicalEditor/LexicalEditor.js";
@@ -1,3 +1,4 @@
1
+ export { useDialogs } from "../../components/Dialogs/useDialogs.js";
1
2
  export { Logo } from "../../base/ui/Logo.js";
2
3
  export { TenantSelector } from "../../base/ui/TenantSelector.js";
3
4
  export { LexicalEditor } from "../../components/LexicalEditor/LexicalEditor.js";
@@ -1 +1 @@
1
- {"version":3,"names":["Logo","TenantSelector","LexicalEditor"],"sources":["ui.ts"],"sourcesContent":["export { Logo } from \"~/base/ui/Logo.js\";\nexport { TenantSelector } from \"~/base/ui/TenantSelector.js\";\nexport { LexicalEditor } from \"~/components/LexicalEditor/LexicalEditor.js\";\n"],"mappings":"AAAA,SAASA,IAAI;AACb,SAASC,cAAc;AACvB,SAASC,aAAa","ignoreList":[]}
1
+ {"version":3,"names":["useDialogs","Logo","TenantSelector","LexicalEditor"],"sources":["ui.ts"],"sourcesContent":["export { useDialogs } from \"~/components/Dialogs/useDialogs.js\";\nexport { Logo } from \"~/base/ui/Logo.js\";\nexport { TenantSelector } from \"~/base/ui/TenantSelector.js\";\nexport { LexicalEditor } from \"~/components/LexicalEditor/LexicalEditor.js\";\n"],"mappings":"AAAA,SAASA,UAAU;AACnB,SAASC,IAAI;AACb,SAASC,cAAc;AACvB,SAASC,aAAa","ignoreList":[]}
@@ -9,6 +9,7 @@ export declare class ReactLicense implements ILicense {
9
9
  canUseFeature(featureId: keyof typeof WCP_FEATURE_LABEL): boolean;
10
10
  canUseFileManagerThreatDetection(): boolean;
11
11
  canUseFolderLevelPermissions(): boolean;
12
+ canUseHcmsFieldPermissions(): boolean;
12
13
  canUsePrivateFiles(): boolean;
13
14
  canUseRecordLocking(): boolean;
14
15
  canUseTeams(): boolean;
@@ -20,6 +20,9 @@ export class ReactLicense {
20
20
  canUseFolderLevelPermissions() {
21
21
  return this.license.canUseFolderLevelPermissions();
22
22
  }
23
+ canUseHcmsFieldPermissions() {
24
+ return this.license.canUseHcmsFieldPermissions();
25
+ }
23
26
  canUsePrivateFiles() {
24
27
  return this.license.canUsePrivateFiles();
25
28
  }
@@ -1 +1 @@
1
- {"version":3,"names":["ReactLicense","constructor","license","getProject","canUseAacl","canUseAuditLogs","canUseFeature","featureId","canUseFileManagerThreatDetection","canUseFolderLevelPermissions","canUsePrivateFiles","canUseRecordLocking","canUseTeams","getRawLicense","canUseWorkflows","toDto"],"sources":["ReactLicense.ts"],"sourcesContent":["import type { DecryptedWcpProjectLicense, ILicense, WcpProject } from \"@webiny/wcp/types.js\";\nimport type { WCP_FEATURE_LABEL } from \"@webiny/wcp\";\n\nexport class ReactLicense implements ILicense {\n private readonly license: ILicense;\n\n constructor(license: ILicense) {\n this.license = license;\n }\n\n getProject(): WcpProject | null {\n return this.license.getProject();\n }\n\n canUseAacl(): boolean {\n return this.license.canUseAacl();\n }\n\n canUseAuditLogs(): boolean {\n return this.license.canUseAuditLogs();\n }\n\n canUseFeature(featureId: keyof typeof WCP_FEATURE_LABEL): boolean {\n return this.license.canUseFeature(featureId);\n }\n\n canUseFileManagerThreatDetection(): boolean {\n return this.license.canUseFileManagerThreatDetection();\n }\n\n canUseFolderLevelPermissions(): boolean {\n return this.license.canUseFolderLevelPermissions();\n }\n\n canUsePrivateFiles(): boolean {\n return this.license.canUsePrivateFiles();\n }\n\n canUseRecordLocking(): boolean {\n return this.license.canUseRecordLocking();\n }\n\n canUseTeams(): boolean {\n return this.license.canUseTeams();\n }\n\n getRawLicense(): DecryptedWcpProjectLicense | null {\n return this.license.getRawLicense();\n }\n\n public canUseWorkflows(): boolean {\n return this.license.canUseWorkflows();\n }\n\n toDto(): DecryptedWcpProjectLicense | null {\n return this.license.toDto();\n }\n}\n"],"mappings":"AAGA,OAAO,MAAMA,YAAY,CAAqB;EAG1CC,WAAWA,CAACC,OAAiB,EAAE;IAC3B,IAAI,CAACA,OAAO,GAAGA,OAAO;EAC1B;EAEAC,UAAUA,CAAA,EAAsB;IAC5B,OAAO,IAAI,CAACD,OAAO,CAACC,UAAU,CAAC,CAAC;EACpC;EAEAC,UAAUA,CAAA,EAAY;IAClB,OAAO,IAAI,CAACF,OAAO,CAACE,UAAU,CAAC,CAAC;EACpC;EAEAC,eAAeA,CAAA,EAAY;IACvB,OAAO,IAAI,CAACH,OAAO,CAACG,eAAe,CAAC,CAAC;EACzC;EAEAC,aAAaA,CAACC,SAAyC,EAAW;IAC9D,OAAO,IAAI,CAACL,OAAO,CAACI,aAAa,CAACC,SAAS,CAAC;EAChD;EAEAC,gCAAgCA,CAAA,EAAY;IACxC,OAAO,IAAI,CAACN,OAAO,CAACM,gCAAgC,CAAC,CAAC;EAC1D;EAEAC,4BAA4BA,CAAA,EAAY;IACpC,OAAO,IAAI,CAACP,OAAO,CAACO,4BAA4B,CAAC,CAAC;EACtD;EAEAC,kBAAkBA,CAAA,EAAY;IAC1B,OAAO,IAAI,CAACR,OAAO,CAACQ,kBAAkB,CAAC,CAAC;EAC5C;EAEAC,mBAAmBA,CAAA,EAAY;IAC3B,OAAO,IAAI,CAACT,OAAO,CAACS,mBAAmB,CAAC,CAAC;EAC7C;EAEAC,WAAWA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACV,OAAO,CAACU,WAAW,CAAC,CAAC;EACrC;EAEAC,aAAaA,CAAA,EAAsC;IAC/C,OAAO,IAAI,CAACX,OAAO,CAACW,aAAa,CAAC,CAAC;EACvC;EAEOC,eAAeA,CAAA,EAAY;IAC9B,OAAO,IAAI,CAACZ,OAAO,CAACY,eAAe,CAAC,CAAC;EACzC;EAEAC,KAAKA,CAAA,EAAsC;IACvC,OAAO,IAAI,CAACb,OAAO,CAACa,KAAK,CAAC,CAAC;EAC/B;AACJ","ignoreList":[]}
1
+ {"version":3,"names":["ReactLicense","constructor","license","getProject","canUseAacl","canUseAuditLogs","canUseFeature","featureId","canUseFileManagerThreatDetection","canUseFolderLevelPermissions","canUseHcmsFieldPermissions","canUsePrivateFiles","canUseRecordLocking","canUseTeams","getRawLicense","canUseWorkflows","toDto"],"sources":["ReactLicense.ts"],"sourcesContent":["import type { DecryptedWcpProjectLicense, ILicense, WcpProject } from \"@webiny/wcp/types.js\";\nimport type { WCP_FEATURE_LABEL } from \"@webiny/wcp\";\n\nexport class ReactLicense implements ILicense {\n private readonly license: ILicense;\n\n constructor(license: ILicense) {\n this.license = license;\n }\n\n getProject(): WcpProject | null {\n return this.license.getProject();\n }\n\n canUseAacl(): boolean {\n return this.license.canUseAacl();\n }\n\n canUseAuditLogs(): boolean {\n return this.license.canUseAuditLogs();\n }\n\n canUseFeature(featureId: keyof typeof WCP_FEATURE_LABEL): boolean {\n return this.license.canUseFeature(featureId);\n }\n\n canUseFileManagerThreatDetection(): boolean {\n return this.license.canUseFileManagerThreatDetection();\n }\n\n canUseFolderLevelPermissions(): boolean {\n return this.license.canUseFolderLevelPermissions();\n }\n\n canUseHcmsFieldPermissions(): boolean {\n return this.license.canUseHcmsFieldPermissions();\n }\n\n canUsePrivateFiles(): boolean {\n return this.license.canUsePrivateFiles();\n }\n\n canUseRecordLocking(): boolean {\n return this.license.canUseRecordLocking();\n }\n\n canUseTeams(): boolean {\n return this.license.canUseTeams();\n }\n\n getRawLicense(): DecryptedWcpProjectLicense | null {\n return this.license.getRawLicense();\n }\n\n public canUseWorkflows(): boolean {\n return this.license.canUseWorkflows();\n }\n\n toDto(): DecryptedWcpProjectLicense | null {\n return this.license.toDto();\n }\n}\n"],"mappings":"AAGA,OAAO,MAAMA,YAAY,CAAqB;EAG1CC,WAAWA,CAACC,OAAiB,EAAE;IAC3B,IAAI,CAACA,OAAO,GAAGA,OAAO;EAC1B;EAEAC,UAAUA,CAAA,EAAsB;IAC5B,OAAO,IAAI,CAACD,OAAO,CAACC,UAAU,CAAC,CAAC;EACpC;EAEAC,UAAUA,CAAA,EAAY;IAClB,OAAO,IAAI,CAACF,OAAO,CAACE,UAAU,CAAC,CAAC;EACpC;EAEAC,eAAeA,CAAA,EAAY;IACvB,OAAO,IAAI,CAACH,OAAO,CAACG,eAAe,CAAC,CAAC;EACzC;EAEAC,aAAaA,CAACC,SAAyC,EAAW;IAC9D,OAAO,IAAI,CAACL,OAAO,CAACI,aAAa,CAACC,SAAS,CAAC;EAChD;EAEAC,gCAAgCA,CAAA,EAAY;IACxC,OAAO,IAAI,CAACN,OAAO,CAACM,gCAAgC,CAAC,CAAC;EAC1D;EAEAC,4BAA4BA,CAAA,EAAY;IACpC,OAAO,IAAI,CAACP,OAAO,CAACO,4BAA4B,CAAC,CAAC;EACtD;EAEAC,0BAA0BA,CAAA,EAAY;IAClC,OAAO,IAAI,CAACR,OAAO,CAACQ,0BAA0B,CAAC,CAAC;EACpD;EAEAC,kBAAkBA,CAAA,EAAY;IAC1B,OAAO,IAAI,CAACT,OAAO,CAACS,kBAAkB,CAAC,CAAC;EAC5C;EAEAC,mBAAmBA,CAAA,EAAY;IAC3B,OAAO,IAAI,CAACV,OAAO,CAACU,mBAAmB,CAAC,CAAC;EAC7C;EAEAC,WAAWA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACX,OAAO,CAACW,WAAW,CAAC,CAAC;EACrC;EAEAC,aAAaA,CAAA,EAAsC;IAC/C,OAAO,IAAI,CAACZ,OAAO,CAACY,aAAa,CAAC,CAAC;EACvC;EAEOC,eAAeA,CAAA,EAAY;IAC9B,OAAO,IAAI,CAACb,OAAO,CAACa,eAAe,CAAC,CAAC;EACzC;EAEAC,KAAKA,CAAA,EAAsC;IACvC,OAAO,IAAI,CAACd,OAAO,CAACc,KAAK,CAAC,CAAC;EAC/B;AACJ","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/app-admin",
3
- "version": "6.0.0-rc.2",
3
+ "version": "6.0.0-rc.3",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "description": "A collection of plugins that together form a complete admin interface, customizable and extensible with Webiny apps and plugins.",
@@ -15,28 +15,28 @@
15
15
  "@apollo/react-hooks": "3.1.5",
16
16
  "@emotion/react": "11.10.8",
17
17
  "@emotion/styled": "11.10.6",
18
- "@iconify/json": "2.2.443",
18
+ "@iconify/json": "2.2.445",
19
19
  "@monaco-editor/react": "4.7.0",
20
20
  "@svgr/webpack": "6.5.1",
21
21
  "@types/mime": "2.0.3",
22
22
  "@types/react": "18.2.79",
23
- "@webiny/admin-ui": "6.0.0-rc.2",
24
- "@webiny/app": "6.0.0-rc.2",
23
+ "@webiny/admin-ui": "6.0.0-rc.3",
24
+ "@webiny/app": "6.0.0-rc.3",
25
25
  "@webiny/di": "0.2.3",
26
- "@webiny/feature": "6.0.0-rc.2",
27
- "@webiny/form": "6.0.0-rc.2",
28
- "@webiny/icons": "6.0.0-rc.2",
29
- "@webiny/lexical-converter": "6.0.0-rc.2",
30
- "@webiny/lexical-editor": "6.0.0-rc.2",
31
- "@webiny/lexical-theme": "6.0.0-rc.2",
32
- "@webiny/plugins": "6.0.0-rc.2",
33
- "@webiny/react-composition": "6.0.0-rc.2",
34
- "@webiny/react-properties": "6.0.0-rc.2",
35
- "@webiny/telemetry": "6.0.0-rc.2",
36
- "@webiny/ui": "6.0.0-rc.2",
37
- "@webiny/utils": "6.0.0-rc.2",
38
- "@webiny/validation": "6.0.0-rc.2",
39
- "@webiny/wcp": "6.0.0-rc.2",
26
+ "@webiny/feature": "6.0.0-rc.3",
27
+ "@webiny/form": "6.0.0-rc.3",
28
+ "@webiny/icons": "6.0.0-rc.3",
29
+ "@webiny/lexical-converter": "6.0.0-rc.3",
30
+ "@webiny/lexical-editor": "6.0.0-rc.3",
31
+ "@webiny/lexical-theme": "6.0.0-rc.3",
32
+ "@webiny/plugins": "6.0.0-rc.3",
33
+ "@webiny/react-composition": "6.0.0-rc.3",
34
+ "@webiny/react-properties": "6.0.0-rc.3",
35
+ "@webiny/telemetry": "6.0.0-rc.3",
36
+ "@webiny/ui": "6.0.0-rc.3",
37
+ "@webiny/utils": "6.0.0-rc.3",
38
+ "@webiny/validation": "6.0.0-rc.3",
39
+ "@webiny/wcp": "6.0.0-rc.3",
40
40
  "apollo-cache": "1.3.5",
41
41
  "apollo-client": "2.6.10",
42
42
  "apollo-link": "1.2.14",
@@ -59,7 +59,7 @@
59
59
  "react-dom": "18.2.0",
60
60
  "react-draggable": "4.5.0",
61
61
  "react-resizable": "3.1.3",
62
- "react-resizable-panels": "4.6.5",
62
+ "react-resizable-panels": "4.7.0",
63
63
  "react-transition-group": "4.4.5",
64
64
  "react-virtualized": "9.22.6",
65
65
  "reset-css": "5.0.2",
@@ -76,7 +76,7 @@
76
76
  "@types/react-transition-group": "4.4.12",
77
77
  "@types/store": "2.0.5",
78
78
  "@types/tinycolor2": "1.4.6",
79
- "@webiny/build-tools": "6.0.0-rc.2",
79
+ "@webiny/build-tools": "6.0.0-rc.3",
80
80
  "rimraf": "6.1.3",
81
81
  "typescript": "5.9.3",
82
82
  "vitest": "4.0.18"
@@ -102,5 +102,5 @@
102
102
  ]
103
103
  }
104
104
  },
105
- "gitHead": "5facada4cbb8617cc60e3c98be0f1839f44be38e"
105
+ "gitHead": "228fe25e1a17f248d566bce1c33d11c291955513"
106
106
  }
@@ -7,6 +7,7 @@ import { usePermissionValue } from "./PermissionValueContext.js";
7
7
  import { useAuthentication } from "../exports/admin/security.js";
8
8
  const NO_ACCESS = "no";
9
9
  const FULL_ACCESS = "full";
10
+ const READ_ONLY_ACCESS = "read-only";
10
11
  const CUSTOM_ACCESS = "custom";
11
12
  const RWD_OPTIONS = [{
12
13
  value: "r",
@@ -92,7 +93,7 @@ function EntitySection({
92
93
  if (hasAction(entity, "rwd")) {
93
94
  columns.push(/*#__PURE__*/React.createElement(Grid.Column, {
94
95
  span: 12,
95
- key: "pw"
96
+ key: "rwd"
96
97
  }, /*#__PURE__*/React.createElement(Bind, {
97
98
  name: `${entity.id}RWD`
98
99
  }, /*#__PURE__*/React.createElement(Select, {
@@ -157,22 +158,29 @@ export const PermissionRenderer = ({
157
158
  });
158
159
  const entities = schema.entities || [];
159
160
  const hasEntities = entities.length > 0;
160
- const accessLevelOptions = hasEntities ? [{
161
- value: NO_ACCESS,
162
- label: "No access"
163
- }, {
164
- value: FULL_ACCESS,
165
- label: "Full access"
166
- }, {
167
- value: CUSTOM_ACCESS,
168
- label: "Custom access"
169
- }] : [{
170
- value: NO_ACCESS,
171
- label: "No access"
172
- }, {
173
- value: FULL_ACCESS,
174
- label: "Full access"
175
- }];
161
+ const accessLevelOptions = useMemo(() => {
162
+ const options = [{
163
+ value: NO_ACCESS,
164
+ label: "No access"
165
+ }];
166
+ if (schema.readOnlyAccess) {
167
+ options.push({
168
+ value: READ_ONLY_ACCESS,
169
+ label: "Read-only access"
170
+ });
171
+ }
172
+ options.push({
173
+ value: FULL_ACCESS,
174
+ label: "Full access"
175
+ });
176
+ if (hasEntities) {
177
+ options.push({
178
+ value: CUSTOM_ACCESS,
179
+ label: "Custom access"
180
+ });
181
+ }
182
+ return options;
183
+ }, [schema, hasEntities]);
176
184
  return /*#__PURE__*/React.createElement(Form, {
177
185
  data: formData,
178
186
  onChange: onFormChange
@@ -1 +1 @@
1
- {"version":3,"names":["React","Fragment","useCallback","useMemo","CheckboxGroup","Grid","Select","Form","CannotUseAaclAlert","PermissionInfo","PermissionsGroup","usePermissionForm","usePermissionValue","useAuthentication","NO_ACCESS","FULL_ACCESS","CUSTOM_ACCESS","RWD_OPTIONS","value","label","PW_OPTIONS","hasAction","entity","name","actions","some","a","buildScopeOptions","options","scopes","includes","push","BUILTIN_ACTIONS","Set","getCustomActions","filter","has","EntitySection","data","cannotUseAAcl","Bind","setValue","scopeField","id","currentScope","scopeDisabled","customActions","customActionsValue","map","onCustomActionsChange","selected","selectedSet","action","columns","createElement","Column","span","key","beforeChange","cb","disabled","description","items","opt","length","onChange","title","PermissionRenderer","schema","identity","getPermission","formData","onFormChange","entities","hasEntities","accessLevelOptions","className","accessLevel"],"sources":["PermissionRenderer.tsx"],"sourcesContent":["import React, { Fragment, useCallback, useMemo } from \"react\";\nimport { CheckboxGroup, Grid, Select } from \"@webiny/admin-ui\";\nimport { Form } from \"@webiny/form\";\nimport type { BindComponent } from \"@webiny/form\";\nimport {\n CannotUseAaclAlert,\n PermissionInfo,\n PermissionsGroup\n} from \"../components/Permissions/index.js\";\nimport { usePermissionForm } from \"./usePermissionForm.js\";\nimport type { AaclPermission } from \"../features/wcp/types.js\";\nimport type { ActionDefinition, PermissionSchema, EntityDefinition } from \"./types.js\";\nimport { usePermissionValue } from \"./PermissionValueContext.js\";\nimport { useAuthentication } from \"~/exports/admin/security.js\";\n\nexport interface PermissionRendererProps {\n schema: PermissionSchema;\n}\n\nconst NO_ACCESS = \"no\";\nconst FULL_ACCESS = \"full\";\nconst CUSTOM_ACCESS = \"custom\";\n\nconst RWD_OPTIONS = [\n { value: \"r\", label: \"Read\" },\n { value: \"rw\", label: \"Read, write\" },\n { value: \"rwd\", label: \"Read, write, delete\" }\n];\n\nconst PW_OPTIONS = [\n { value: \"p\", label: \"Publish\" },\n { value: \"u\", label: \"Unpublish\" }\n];\n\nfunction hasAction(entity: EntityDefinition, name: string): boolean {\n return entity.actions?.some(a => a.name === name) ?? false;\n}\n\nfunction buildScopeOptions(entity: EntityDefinition) {\n const options = [{ value: NO_ACCESS, label: \"No access\" }];\n\n if (entity.scopes.includes(\"full\")) {\n options.push({ value: FULL_ACCESS, label: \"Full access\" });\n }\n\n if (entity.scopes.includes(\"own\")) {\n options.push({ value: \"own\", label: \"Only entries created by the user\" });\n }\n\n return options;\n}\n\nconst BUILTIN_ACTIONS = new Set([\"rwd\", \"pw\"]);\n\nfunction getCustomActions(entity: EntityDefinition): ActionDefinition[] {\n return (entity.actions ?? []).filter(a => !BUILTIN_ACTIONS.has(a.name));\n}\n\ninterface EntitySectionProps {\n entity: EntityDefinition;\n data: Record<string, any>;\n cannotUseAAcl: boolean;\n Bind: BindComponent;\n setValue: (name: string, value: any) => void;\n}\n\nfunction EntitySection({ entity, data, cannotUseAAcl, Bind, setValue }: EntitySectionProps) {\n const scopeField = `${entity.id}AccessScope`;\n const currentScope = data[scopeField];\n const scopeDisabled = cannotUseAAcl || !currentScope || currentScope === NO_ACCESS;\n const customActions = useMemo(() => getCustomActions(entity), [entity]);\n\n // Derive the selected values array from individual boolean form fields.\n const customActionsValue = useMemo(() => {\n return customActions.filter(a => data[`${entity.id}Action_${a.name}`]).map(a => a.name);\n }, [data, customActions, entity.id]);\n\n const onCustomActionsChange = useCallback(\n (selected: string[]) => {\n const selectedSet = new Set(selected);\n for (const action of customActions) {\n setValue(`${entity.id}Action_${action.name}`, selectedSet.has(action.name));\n }\n },\n [customActions, entity.id, setValue]\n );\n\n const columns = [\n <Grid.Column span={12} key={\"access\"}>\n <Bind\n name={scopeField}\n beforeChange={(value: string, cb: (v: string) => void) => {\n if (value === \"own\" && hasAction(entity, \"rwd\")) {\n setValue(`${entity.id}RWD`, \"rwd\");\n }\n cb(value);\n }}\n >\n <Select\n label={\"Access Scope\"}\n disabled={cannotUseAAcl}\n options={buildScopeOptions(entity)}\n />\n </Bind>\n </Grid.Column>\n ];\n\n if (hasAction(entity, \"rwd\")) {\n columns.push(\n <Grid.Column span={12} key={\"pw\"}>\n <Bind name={`${entity.id}RWD`}>\n <Select\n label={\"Primary Actions\"}\n disabled={scopeDisabled || currentScope === \"own\"}\n options={RWD_OPTIONS}\n />\n </Bind>\n </Grid.Column>\n );\n }\n\n if (hasAction(entity, \"pw\")) {\n columns.push(\n <Grid.Column span={12} key={\"pw\"}>\n <Bind name={`${entity.id}PW`}>\n <CheckboxGroup\n label={\"Publishing actions\"}\n description={\"Publishing-related actions that can be performed on entries.\"}\n items={PW_OPTIONS.map(opt => ({\n ...opt,\n disabled: scopeDisabled\n }))}\n />\n </Bind>\n </Grid.Column>\n );\n }\n\n if (customActions.length > 0) {\n columns.push(\n <Grid.Column span={12} key={\"other\"}>\n <CheckboxGroup\n label={\"Other Actions\"}\n value={customActionsValue}\n onChange={onCustomActionsChange}\n items={customActions.map(action => ({\n value: action.name,\n label: action.label || action.name,\n disabled: scopeDisabled\n }))}\n />\n </Grid.Column>\n );\n }\n\n return (\n <PermissionsGroup title={entity.title || entity.id}>\n <Grid>{columns}</Grid>\n </PermissionsGroup>\n );\n}\n\nexport const PermissionRenderer = ({ schema }: PermissionRendererProps) => {\n const { value, onChange } = usePermissionValue();\n const { identity } = useAuthentication();\n\n const cannotUseAAcl = useMemo(() => {\n return !identity.getPermission<AaclPermission>(\"aacl\", true);\n }, []);\n\n const { formData, onFormChange } = usePermissionForm(schema, { value, onChange });\n\n const entities = schema.entities || [];\n const hasEntities = entities.length > 0;\n\n const accessLevelOptions = hasEntities\n ? [\n { value: NO_ACCESS, label: \"No access\" },\n { value: FULL_ACCESS, label: \"Full access\" },\n { value: CUSTOM_ACCESS, label: \"Custom access\" }\n ]\n : [\n { value: NO_ACCESS, label: \"No access\" },\n { value: FULL_ACCESS, label: \"Full access\" }\n ];\n\n return (\n <Form data={formData} onChange={onFormChange}>\n {({ data, Bind, setValue }) => (\n <Fragment>\n <Grid className={\"pt-md\"}>\n <Grid.Column span={12}>\n {data.accessLevel === CUSTOM_ACCESS && cannotUseAAcl && (\n <CannotUseAaclAlert />\n )}\n </Grid.Column>\n </Grid>\n <Grid className={\"pt-md\"}>\n <Grid.Column span={6}>\n <PermissionInfo title={\"Access Level\"} />\n </Grid.Column>\n <Grid.Column span={6}>\n <Bind name={\"accessLevel\"}>\n <Select options={accessLevelOptions} />\n </Bind>\n </Grid.Column>\n </Grid>\n {data.accessLevel === CUSTOM_ACCESS && hasEntities && (\n <div className={\"mt-lg\"}>\n {entities.map(entity => (\n <EntitySection\n key={entity.id}\n entity={entity}\n data={data}\n cannotUseAAcl={cannotUseAAcl}\n Bind={Bind}\n setValue={setValue}\n />\n ))}\n </div>\n )}\n </Fragment>\n )}\n </Form>\n );\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","Fragment","useCallback","useMemo","CheckboxGroup","Grid","Select","Form","CannotUseAaclAlert","PermissionInfo","PermissionsGroup","usePermissionForm","usePermissionValue","useAuthentication","NO_ACCESS","FULL_ACCESS","READ_ONLY_ACCESS","CUSTOM_ACCESS","RWD_OPTIONS","value","label","PW_OPTIONS","hasAction","entity","name","actions","some","a","buildScopeOptions","options","scopes","includes","push","BUILTIN_ACTIONS","Set","getCustomActions","filter","has","EntitySection","data","cannotUseAAcl","Bind","setValue","scopeField","id","currentScope","scopeDisabled","customActions","customActionsValue","map","onCustomActionsChange","selected","selectedSet","action","columns","createElement","Column","span","key","beforeChange","cb","disabled","description","items","opt","length","onChange","title","PermissionRenderer","schema","identity","getPermission","formData","onFormChange","entities","hasEntities","accessLevelOptions","readOnlyAccess","className","accessLevel"],"sources":["PermissionRenderer.tsx"],"sourcesContent":["import React, { Fragment, useCallback, useMemo } from \"react\";\nimport { CheckboxGroup, Grid, Select } from \"@webiny/admin-ui\";\nimport { Form } from \"@webiny/form\";\nimport type { BindComponent } from \"@webiny/form\";\nimport {\n CannotUseAaclAlert,\n PermissionInfo,\n PermissionsGroup\n} from \"../components/Permissions/index.js\";\nimport { usePermissionForm } from \"./usePermissionForm.js\";\nimport type { AaclPermission } from \"../features/wcp/types.js\";\nimport type { ActionDefinition, PermissionSchema, EntityDefinition } from \"./types.js\";\nimport { usePermissionValue } from \"./PermissionValueContext.js\";\nimport { useAuthentication } from \"~/exports/admin/security.js\";\n\nexport interface PermissionRendererProps {\n schema: PermissionSchema;\n}\n\nconst NO_ACCESS = \"no\";\nconst FULL_ACCESS = \"full\";\nconst READ_ONLY_ACCESS = \"read-only\";\nconst CUSTOM_ACCESS = \"custom\";\n\nconst RWD_OPTIONS = [\n { value: \"r\", label: \"Read\" },\n { value: \"rw\", label: \"Read, write\" },\n { value: \"rwd\", label: \"Read, write, delete\" }\n];\n\nconst PW_OPTIONS = [\n { value: \"p\", label: \"Publish\" },\n { value: \"u\", label: \"Unpublish\" }\n];\n\nfunction hasAction(entity: EntityDefinition, name: string): boolean {\n return entity.actions?.some(a => a.name === name) ?? false;\n}\n\nfunction buildScopeOptions(entity: EntityDefinition) {\n const options = [{ value: NO_ACCESS, label: \"No access\" }];\n\n if (entity.scopes.includes(\"full\")) {\n options.push({ value: FULL_ACCESS, label: \"Full access\" });\n }\n\n if (entity.scopes.includes(\"own\")) {\n options.push({ value: \"own\", label: \"Only entries created by the user\" });\n }\n\n return options;\n}\n\nconst BUILTIN_ACTIONS = new Set([\"rwd\", \"pw\"]);\n\nfunction getCustomActions(entity: EntityDefinition): ActionDefinition[] {\n return (entity.actions ?? []).filter(a => !BUILTIN_ACTIONS.has(a.name));\n}\n\ninterface EntitySectionProps {\n entity: EntityDefinition;\n data: Record<string, any>;\n cannotUseAAcl: boolean;\n Bind: BindComponent;\n setValue: (name: string, value: any) => void;\n}\n\nfunction EntitySection({ entity, data, cannotUseAAcl, Bind, setValue }: EntitySectionProps) {\n const scopeField = `${entity.id}AccessScope`;\n const currentScope = data[scopeField];\n const scopeDisabled = cannotUseAAcl || !currentScope || currentScope === NO_ACCESS;\n const customActions = useMemo(() => getCustomActions(entity), [entity]);\n\n // Derive the selected values array from individual boolean form fields.\n const customActionsValue = useMemo(() => {\n return customActions.filter(a => data[`${entity.id}Action_${a.name}`]).map(a => a.name);\n }, [data, customActions, entity.id]);\n\n const onCustomActionsChange = useCallback(\n (selected: string[]) => {\n const selectedSet = new Set(selected);\n for (const action of customActions) {\n setValue(`${entity.id}Action_${action.name}`, selectedSet.has(action.name));\n }\n },\n [customActions, entity.id, setValue]\n );\n\n const columns = [\n <Grid.Column span={12} key={\"access\"}>\n <Bind\n name={scopeField}\n beforeChange={(value: string, cb: (v: string) => void) => {\n if (value === \"own\" && hasAction(entity, \"rwd\")) {\n setValue(`${entity.id}RWD`, \"rwd\");\n }\n cb(value);\n }}\n >\n <Select\n label={\"Access Scope\"}\n disabled={cannotUseAAcl}\n options={buildScopeOptions(entity)}\n />\n </Bind>\n </Grid.Column>\n ];\n\n if (hasAction(entity, \"rwd\")) {\n columns.push(\n <Grid.Column span={12} key={\"rwd\"}>\n <Bind name={`${entity.id}RWD`}>\n <Select\n label={\"Primary Actions\"}\n disabled={scopeDisabled || currentScope === \"own\"}\n options={RWD_OPTIONS}\n />\n </Bind>\n </Grid.Column>\n );\n }\n\n if (hasAction(entity, \"pw\")) {\n columns.push(\n <Grid.Column span={12} key={\"pw\"}>\n <Bind name={`${entity.id}PW`}>\n <CheckboxGroup\n label={\"Publishing actions\"}\n description={\"Publishing-related actions that can be performed on entries.\"}\n items={PW_OPTIONS.map(opt => ({\n ...opt,\n disabled: scopeDisabled\n }))}\n />\n </Bind>\n </Grid.Column>\n );\n }\n\n if (customActions.length > 0) {\n columns.push(\n <Grid.Column span={12} key={\"other\"}>\n <CheckboxGroup\n label={\"Other Actions\"}\n value={customActionsValue}\n onChange={onCustomActionsChange}\n items={customActions.map(action => ({\n value: action.name,\n label: action.label || action.name,\n disabled: scopeDisabled\n }))}\n />\n </Grid.Column>\n );\n }\n\n return (\n <PermissionsGroup title={entity.title || entity.id}>\n <Grid>{columns}</Grid>\n </PermissionsGroup>\n );\n}\n\nexport const PermissionRenderer = ({ schema }: PermissionRendererProps) => {\n const { value, onChange } = usePermissionValue();\n const { identity } = useAuthentication();\n\n const cannotUseAAcl = useMemo(() => {\n return !identity.getPermission<AaclPermission>(\"aacl\", true);\n }, []);\n\n const { formData, onFormChange } = usePermissionForm(schema, { value, onChange });\n\n const entities = schema.entities || [];\n const hasEntities = entities.length > 0;\n\n const accessLevelOptions = useMemo(() => {\n const options = [{ value: NO_ACCESS, label: \"No access\" }];\n\n if (schema.readOnlyAccess) {\n options.push({ value: READ_ONLY_ACCESS, label: \"Read-only access\" });\n }\n\n options.push({ value: FULL_ACCESS, label: \"Full access\" });\n\n if (hasEntities) {\n options.push({ value: CUSTOM_ACCESS, label: \"Custom access\" });\n }\n\n return options;\n }, [schema, hasEntities]);\n\n return (\n <Form data={formData} onChange={onFormChange}>\n {({ data, Bind, setValue }) => (\n <Fragment>\n <Grid className={\"pt-md\"}>\n <Grid.Column span={12}>\n {data.accessLevel === CUSTOM_ACCESS && cannotUseAAcl && (\n <CannotUseAaclAlert />\n )}\n </Grid.Column>\n </Grid>\n <Grid className={\"pt-md\"}>\n <Grid.Column span={6}>\n <PermissionInfo title={\"Access Level\"} />\n </Grid.Column>\n <Grid.Column span={6}>\n <Bind name={\"accessLevel\"}>\n <Select options={accessLevelOptions} />\n </Bind>\n </Grid.Column>\n </Grid>\n {data.accessLevel === CUSTOM_ACCESS && hasEntities && (\n <div className={\"mt-lg\"}>\n {entities.map(entity => (\n <EntitySection\n key={entity.id}\n entity={entity}\n data={data}\n cannotUseAAcl={cannotUseAAcl}\n Bind={Bind}\n setValue={setValue}\n />\n ))}\n </div>\n )}\n </Fragment>\n )}\n </Form>\n );\n};\n"],"mappings":"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","ignoreList":[]}
@@ -50,11 +50,20 @@ export interface EntityDefinition {
50
50
  export interface PermissionSchemaConfig {
51
51
  /** Permission prefix — used to filter permissions from the array */
52
52
  prefix: string;
53
- /** Permission object emitted on "full access". All properties are spread onto the permission. */
54
- fullAccess: {
55
- name: string;
53
+ /**
54
+ * Full access configuration.
55
+ * - `true` — emits `{ name: "${prefix}.*" }`.
56
+ * - `{ ...extras }` — emits `{ name: "${prefix}.*", ...extras }`.
57
+ */
58
+ fullAccess: boolean | {
56
59
  [key: string]: any;
57
60
  };
61
+ /**
62
+ * Read-only access configuration. When defined, the schema supports a read-only tier.
63
+ * - `true` — emits `{ name: "${prefix}.*", rwd: "r" }`.
64
+ * - `Permission[]` — emits the array as-is.
65
+ */
66
+ readOnlyAccess?: boolean | Permission[];
58
67
  /** Entity definitions (optional — simple apps have none) */
59
68
  entities?: EntityDefinition[];
60
69
  }
@@ -63,11 +72,20 @@ export interface PermissionSchemaConfig {
63
72
  */
64
73
  export interface PermissionSchema {
65
74
  prefix: string;
66
- /** Permission object emitted on "full access". All properties are spread onto the permission. */
67
- fullAccess: {
68
- name: string;
75
+ /**
76
+ * Full access configuration.
77
+ * - `true` — emits `{ name: "${prefix}.*" }`.
78
+ * - `{ ...extras }` — emits `{ name: "${prefix}.*", ...extras }`.
79
+ */
80
+ fullAccess: boolean | {
69
81
  [key: string]: any;
70
82
  };
83
+ /**
84
+ * Read-only access configuration. When defined, the schema supports a read-only tier.
85
+ * - `true` — emits `{ name: "${prefix}.*", rwd: "r" }`.
86
+ * - `Permission[]` — emits the array as-is.
87
+ */
88
+ readOnlyAccess?: boolean | Permission[];
71
89
  entities?: EntityDefinition[];
72
90
  }
73
91
  /**
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type React from \"react\";\n\n/**\n * A single permission object from the API.\n */\nexport interface Permission {\n name: string;\n [key: string]: any;\n}\n\n/**\n * An action definition on an entity.\n *\n * Built-in actions:\n * - `{ name: \"rwd\" }` — read/write/delete single-select (serialized as joined string, e.g. \"rw\")\n * - `{ name: \"pw\" }` — publish/unpublish multi-select (serialized as joined string, e.g. \"pu\")\n *\n * Custom actions:\n * - `{ name: \"install\", label: \"Install\" }` — boolean flag (serialized as `install: true`)\n */\nexport interface ActionDefinition {\n /** Key on the permission object (e.g. \"rwd\", \"pw\", \"install\") */\n name: string;\n /** Display label for the UI. Required for custom actions; ignored for built-in \"rwd\"/\"pw\". */\n label?: string;\n}\n\n/**\n * Defines an entity within a permission schema.\n */\nexport interface EntityDefinition {\n /** Unique ID, used for form field naming: ${id}AccessScope, ${id}RWD, etc. */\n id: string;\n /** Display title for the UI renderer (e.g. \"Files\", \"Settings\") */\n title?: string;\n /** Permission name emitted for this entity (e.g. \"fm.file\") */\n permission: string;\n /** Available access scopes */\n scopes: (\"full\" | \"own\")[];\n /** Action definitions for this entity */\n actions?: ActionDefinition[];\n /** Dependency on another entity */\n dependsOn?: {\n /** ID of parent entity */\n entity: string;\n /** Required action character (e.g. \"r\") */\n requires: string;\n };\n}\n\n/**\n * Configuration for creating a permission schema.\n */\nexport interface PermissionSchemaConfig {\n /** Permission prefix — used to filter permissions from the array */\n prefix: string;\n /** Permission object emitted on \"full access\". All properties are spread onto the permission. */\n fullAccess: { name: string; [key: string]: any };\n /** Entity definitions (optional — simple apps have none) */\n entities?: EntityDefinition[];\n}\n\n/**\n * A compiled permission schema returned by `createPermissionSchema`.\n */\nexport interface PermissionSchema {\n prefix: string;\n /** Permission object emitted on \"full access\". All properties are spread onto the permission. */\n fullAccess: { name: string; [key: string]: any };\n entities?: EntityDefinition[];\n}\n\n/**\n * Options passed to the `usePermissionForm` hook.\n */\nexport interface UsePermissionFormOptions {\n value: Permission[];\n onChange: (value: Permission[]) => void;\n /** Merge extra fields into deserialized form data (for CMS endpoints, resource scopes, etc.) */\n deserialize?: (permissions: Permission[]) => Record<string, any>;\n /** Transform or extend the core-serialized permissions (for CMS endpoints, resource scopes, etc.) */\n serialize?: (formData: Record<string, any>, corePermissions: Permission[]) => Permission[];\n}\n\n/**\n * Return value of `usePermissionForm`.\n */\nexport interface UsePermissionFormResult {\n formData: Record<string, any>;\n onFormChange: (data: Record<string, any>) => void;\n}\n\n/**\n * Configuration for a permission renderer registered via AdminConfig.\n *\n * Either `schema` or `element` must be provided:\n * - `schema`: uses the built-in PermissionRenderer for auto-generated UI.\n * - `element`: uses a custom React element for full control.\n */\nexport type PermissionRendererConfig = PermissionRendererConfigBase &\n (\n | { schema: PermissionSchema; element?: never }\n | { schema?: never; element: React.ReactElement }\n );\n\ninterface PermissionRendererConfigBase {\n name: string;\n title: string;\n description?: string;\n icon?: React.ReactElement;\n system?: boolean;\n}\n\n/**\n * Item that may have an owner (used for own-scope permission checks).\n */\nexport interface OwnableItem {\n createdBy?: { id: string } | null;\n}\n\n/**\n * Extract the union of entity definitions from a schema config type.\n */\ntype EntitiesOf<S extends PermissionSchemaConfig> = S extends {\n entities: ReadonlyArray<infer E extends EntityDefinition>;\n}\n ? E\n : never;\n\n/**\n * Extract entity IDs whose actions array contains an action with the given name.\n */\ntype EntityIdWithAction<S extends PermissionSchemaConfig, A extends string> = {\n [K in EntitiesOf<S> as K extends { actions: ReadonlyArray<infer Act> }\n ? Act extends { name: A }\n ? K[\"id\"]\n : never\n : never]: never;\n} extends infer M\n ? keyof M & string\n : never;\n\n/**\n * Entity IDs that have the \"rwd\" action.\n */\nexport type RwdEntityId<S extends PermissionSchemaConfig> = EntityIdWithAction<S, \"rwd\">;\n\n/**\n * Entity IDs that have the \"pw\" action.\n */\nexport type PwEntityId<S extends PermissionSchemaConfig> = EntityIdWithAction<S, \"pw\">;\n\n/**\n * All entity IDs in the schema.\n */\nexport type AllEntityIds<S extends PermissionSchemaConfig> = EntitiesOf<S>[\"id\"];\n\n/**\n * Custom (non-builtin) action names across all entities.\n */\nexport type CustomActionNames<S extends PermissionSchemaConfig> = Exclude<\n EntitiesOf<S> extends { actions: ReadonlyArray<infer Act extends ActionDefinition> }\n ? Act[\"name\"]\n : never,\n \"rwd\" | \"pw\"\n>;\n\n/**\n * The return type of `usePermissions(schema)`.\n *\n * When the schema has literal entity types, methods are narrowed to only accept valid entity IDs.\n * When the schema is dynamically typed, all methods accept `string`.\n */\nexport type UsePermissionsResult<S extends PermissionSchemaConfig> =\n string extends AllEntityIds<S> ? UsePermissionsResultUntyped : UsePermissionsResultTyped<S>;\n\nexport interface UsePermissionsResultUntyped {\n canAccess: (entityId: string) => boolean;\n canRead: (entityId: string) => boolean;\n canCreate: (entityId: string) => boolean;\n canEdit: (entityId: string, item?: OwnableItem) => boolean;\n canDelete: (entityId: string, item?: OwnableItem) => boolean;\n canPublish: (entityId: string) => boolean;\n canUnpublish: (entityId: string) => boolean;\n canAction: (action: string, entityId: string) => boolean;\n}\n\n/**\n * Action values accepted by `HasPermission`.\n *\n * Built-in actions are always available; custom action names from the schema are inferred automatically.\n */\nexport type HasPermissionAction<S extends PermissionSchemaConfig> =\n | \"read\"\n | \"create\"\n | \"edit\"\n | \"delete\"\n | \"publish\"\n | \"unpublish\"\n | CustomActionNames<S>;\n\n/**\n * Props for a schema-bound `HasPermission` component created via `createHasPermission`.\n *\n * Exactly one of `entity`, `any`, or `all` must be provided.\n */\nexport type HasPermissionProps<S extends PermissionSchemaConfig> =\n | SingleEntityProps<S>\n | AnyEntitiesProps<S>\n | AllEntitiesProps<S>;\n\ninterface SingleEntityProps<S extends PermissionSchemaConfig> {\n entity: AllEntityIds<S>;\n any?: never;\n all?: never;\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ninterface AnyEntitiesProps<S extends PermissionSchemaConfig> {\n entity?: never;\n any: AllEntityIds<S>[];\n all?: never;\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ninterface AllEntitiesProps<S extends PermissionSchemaConfig> {\n entity?: never;\n any?: never;\n all: AllEntityIds<S>[];\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ntype UsePermissionsResultTyped<S extends PermissionSchemaConfig> = {\n canAccess: (entityId: AllEntityIds<S>) => boolean;\n canAction: (\n action: CustomActionNames<S> extends never ? string : CustomActionNames<S>,\n entityId: AllEntityIds<S>\n ) => boolean;\n} & ([RwdEntityId<S>] extends [never]\n ? {\n canRead: (entityId: string) => boolean;\n canCreate: (entityId: string) => boolean;\n canEdit: (entityId: string, item?: OwnableItem) => boolean;\n canDelete: (entityId: string, item?: OwnableItem) => boolean;\n }\n : {\n canRead: (entityId: RwdEntityId<S>) => boolean;\n canCreate: (entityId: RwdEntityId<S>) => boolean;\n canEdit: (entityId: RwdEntityId<S>, item?: OwnableItem) => boolean;\n canDelete: (entityId: RwdEntityId<S>, item?: OwnableItem) => boolean;\n }) &\n ([PwEntityId<S>] extends [never]\n ? {\n canPublish: (entityId: string) => boolean;\n canUnpublish: (entityId: string) => boolean;\n }\n : {\n canPublish: (entityId: PwEntityId<S>) => boolean;\n canUnpublish: (entityId: PwEntityId<S>) => boolean;\n });\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type React from \"react\";\n\n/**\n * A single permission object from the API.\n */\nexport interface Permission {\n name: string;\n [key: string]: any;\n}\n\n/**\n * An action definition on an entity.\n *\n * Built-in actions:\n * - `{ name: \"rwd\" }` — read/write/delete single-select (serialized as joined string, e.g. \"rw\")\n * - `{ name: \"pw\" }` — publish/unpublish multi-select (serialized as joined string, e.g. \"pu\")\n *\n * Custom actions:\n * - `{ name: \"install\", label: \"Install\" }` — boolean flag (serialized as `install: true`)\n */\nexport interface ActionDefinition {\n /** Key on the permission object (e.g. \"rwd\", \"pw\", \"install\") */\n name: string;\n /** Display label for the UI. Required for custom actions; ignored for built-in \"rwd\"/\"pw\". */\n label?: string;\n}\n\n/**\n * Defines an entity within a permission schema.\n */\nexport interface EntityDefinition {\n /** Unique ID, used for form field naming: ${id}AccessScope, ${id}RWD, etc. */\n id: string;\n /** Display title for the UI renderer (e.g. \"Files\", \"Settings\") */\n title?: string;\n /** Permission name emitted for this entity (e.g. \"fm.file\") */\n permission: string;\n /** Available access scopes */\n scopes: (\"full\" | \"own\")[];\n /** Action definitions for this entity */\n actions?: ActionDefinition[];\n /** Dependency on another entity */\n dependsOn?: {\n /** ID of parent entity */\n entity: string;\n /** Required action character (e.g. \"r\") */\n requires: string;\n };\n}\n\n/**\n * Configuration for creating a permission schema.\n */\nexport interface PermissionSchemaConfig {\n /** Permission prefix — used to filter permissions from the array */\n prefix: string;\n /**\n * Full access configuration.\n * - `true` — emits `{ name: \"${prefix}.*\" }`.\n * - `{ ...extras }` emits `{ name: \"${prefix}.*\", ...extras }`.\n */\n fullAccess: boolean | { [key: string]: any };\n /**\n * Read-only access configuration. When defined, the schema supports a read-only tier.\n * - `true` — emits `{ name: \"${prefix}.*\", rwd: \"r\" }`.\n * - `Permission[]` — emits the array as-is.\n */\n readOnlyAccess?: boolean | Permission[];\n /** Entity definitions (optional — simple apps have none) */\n entities?: EntityDefinition[];\n}\n\n/**\n * A compiled permission schema returned by `createPermissionSchema`.\n */\nexport interface PermissionSchema {\n prefix: string;\n /**\n * Full access configuration.\n * - `true` — emits `{ name: \"${prefix}.*\" }`.\n * - `{ ...extras }` emits `{ name: \"${prefix}.*\", ...extras }`.\n */\n fullAccess: boolean | { [key: string]: any };\n /**\n * Read-only access configuration. When defined, the schema supports a read-only tier.\n * - `true` — emits `{ name: \"${prefix}.*\", rwd: \"r\" }`.\n * - `Permission[]` — emits the array as-is.\n */\n readOnlyAccess?: boolean | Permission[];\n entities?: EntityDefinition[];\n}\n\n/**\n * Options passed to the `usePermissionForm` hook.\n */\nexport interface UsePermissionFormOptions {\n value: Permission[];\n onChange: (value: Permission[]) => void;\n /** Merge extra fields into deserialized form data (for CMS endpoints, resource scopes, etc.) */\n deserialize?: (permissions: Permission[]) => Record<string, any>;\n /** Transform or extend the core-serialized permissions (for CMS endpoints, resource scopes, etc.) */\n serialize?: (formData: Record<string, any>, corePermissions: Permission[]) => Permission[];\n}\n\n/**\n * Return value of `usePermissionForm`.\n */\nexport interface UsePermissionFormResult {\n formData: Record<string, any>;\n onFormChange: (data: Record<string, any>) => void;\n}\n\n/**\n * Configuration for a permission renderer registered via AdminConfig.\n *\n * Either `schema` or `element` must be provided:\n * - `schema`: uses the built-in PermissionRenderer for auto-generated UI.\n * - `element`: uses a custom React element for full control.\n */\nexport type PermissionRendererConfig = PermissionRendererConfigBase &\n (\n | { schema: PermissionSchema; element?: never }\n | { schema?: never; element: React.ReactElement }\n );\n\ninterface PermissionRendererConfigBase {\n name: string;\n title: string;\n description?: string;\n icon?: React.ReactElement;\n system?: boolean;\n}\n\n/**\n * Item that may have an owner (used for own-scope permission checks).\n */\nexport interface OwnableItem {\n createdBy?: { id: string } | null;\n}\n\n/**\n * Extract the union of entity definitions from a schema config type.\n */\ntype EntitiesOf<S extends PermissionSchemaConfig> = S extends {\n entities: ReadonlyArray<infer E extends EntityDefinition>;\n}\n ? E\n : never;\n\n/**\n * Extract entity IDs whose actions array contains an action with the given name.\n */\ntype EntityIdWithAction<S extends PermissionSchemaConfig, A extends string> = {\n [K in EntitiesOf<S> as K extends { actions: ReadonlyArray<infer Act> }\n ? Act extends { name: A }\n ? K[\"id\"]\n : never\n : never]: never;\n} extends infer M\n ? keyof M & string\n : never;\n\n/**\n * Entity IDs that have the \"rwd\" action.\n */\nexport type RwdEntityId<S extends PermissionSchemaConfig> = EntityIdWithAction<S, \"rwd\">;\n\n/**\n * Entity IDs that have the \"pw\" action.\n */\nexport type PwEntityId<S extends PermissionSchemaConfig> = EntityIdWithAction<S, \"pw\">;\n\n/**\n * All entity IDs in the schema.\n */\nexport type AllEntityIds<S extends PermissionSchemaConfig> = EntitiesOf<S>[\"id\"];\n\n/**\n * Custom (non-builtin) action names across all entities.\n */\nexport type CustomActionNames<S extends PermissionSchemaConfig> = Exclude<\n EntitiesOf<S> extends { actions: ReadonlyArray<infer Act extends ActionDefinition> }\n ? Act[\"name\"]\n : never,\n \"rwd\" | \"pw\"\n>;\n\n/**\n * The return type of `usePermissions(schema)`.\n *\n * When the schema has literal entity types, methods are narrowed to only accept valid entity IDs.\n * When the schema is dynamically typed, all methods accept `string`.\n */\nexport type UsePermissionsResult<S extends PermissionSchemaConfig> =\n string extends AllEntityIds<S> ? UsePermissionsResultUntyped : UsePermissionsResultTyped<S>;\n\nexport interface UsePermissionsResultUntyped {\n canAccess: (entityId: string) => boolean;\n canRead: (entityId: string) => boolean;\n canCreate: (entityId: string) => boolean;\n canEdit: (entityId: string, item?: OwnableItem) => boolean;\n canDelete: (entityId: string, item?: OwnableItem) => boolean;\n canPublish: (entityId: string) => boolean;\n canUnpublish: (entityId: string) => boolean;\n canAction: (action: string, entityId: string) => boolean;\n}\n\n/**\n * Action values accepted by `HasPermission`.\n *\n * Built-in actions are always available; custom action names from the schema are inferred automatically.\n */\nexport type HasPermissionAction<S extends PermissionSchemaConfig> =\n | \"read\"\n | \"create\"\n | \"edit\"\n | \"delete\"\n | \"publish\"\n | \"unpublish\"\n | CustomActionNames<S>;\n\n/**\n * Props for a schema-bound `HasPermission` component created via `createHasPermission`.\n *\n * Exactly one of `entity`, `any`, or `all` must be provided.\n */\nexport type HasPermissionProps<S extends PermissionSchemaConfig> =\n | SingleEntityProps<S>\n | AnyEntitiesProps<S>\n | AllEntitiesProps<S>;\n\ninterface SingleEntityProps<S extends PermissionSchemaConfig> {\n entity: AllEntityIds<S>;\n any?: never;\n all?: never;\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ninterface AnyEntitiesProps<S extends PermissionSchemaConfig> {\n entity?: never;\n any: AllEntityIds<S>[];\n all?: never;\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ninterface AllEntitiesProps<S extends PermissionSchemaConfig> {\n entity?: never;\n any?: never;\n all: AllEntityIds<S>[];\n action?: HasPermissionAction<S>;\n children: React.ReactNode;\n}\n\ntype UsePermissionsResultTyped<S extends PermissionSchemaConfig> = {\n canAccess: (entityId: AllEntityIds<S>) => boolean;\n canAction: (\n action: CustomActionNames<S> extends never ? string : CustomActionNames<S>,\n entityId: AllEntityIds<S>\n ) => boolean;\n} & ([RwdEntityId<S>] extends [never]\n ? {\n canRead: (entityId: string) => boolean;\n canCreate: (entityId: string) => boolean;\n canEdit: (entityId: string, item?: OwnableItem) => boolean;\n canDelete: (entityId: string, item?: OwnableItem) => boolean;\n }\n : {\n canRead: (entityId: RwdEntityId<S>) => boolean;\n canCreate: (entityId: RwdEntityId<S>) => boolean;\n canEdit: (entityId: RwdEntityId<S>, item?: OwnableItem) => boolean;\n canDelete: (entityId: RwdEntityId<S>, item?: OwnableItem) => boolean;\n }) &\n ([PwEntityId<S>] extends [never]\n ? {\n canPublish: (entityId: string) => boolean;\n canUnpublish: (entityId: string) => boolean;\n }\n : {\n canPublish: (entityId: PwEntityId<S>) => boolean;\n canUnpublish: (entityId: PwEntityId<S>) => boolean;\n });\n"],"mappings":"","ignoreList":[]}
@@ -3,6 +3,34 @@ function hasAction(entity, name) {
3
3
  return entity.actions?.some(a => a.name === name) ?? false;
4
4
  }
5
5
 
6
+ /** Resolve fullAccess config into a concrete Permission object. */
7
+ function resolveFullAccess(schema) {
8
+ const name = `${schema.prefix}.*`;
9
+ if (schema.fullAccess === true) {
10
+ return {
11
+ name
12
+ };
13
+ }
14
+ return {
15
+ name,
16
+ ...schema.fullAccess
17
+ };
18
+ }
19
+
20
+ /** Resolve readOnlyAccess config into a concrete Permission[]. */
21
+ function resolveReadOnlyAccess(schema) {
22
+ if (!schema.readOnlyAccess) {
23
+ return undefined;
24
+ }
25
+ if (schema.readOnlyAccess === true) {
26
+ return [{
27
+ name: `${schema.prefix}.*`,
28
+ rwd: "r"
29
+ }];
30
+ }
31
+ return schema.readOnlyAccess;
32
+ }
33
+
6
34
  /**
7
35
  * Deserialize Permission[] into form data based on the schema.
8
36
  */
@@ -13,8 +41,16 @@ function deserializePermissions(schema, value) {
13
41
  };
14
42
  }
15
43
 
44
+ // Check for read-only access by looking for the synthetic marker permission.
45
+ if (value.some(p => p.name === `$${schema.prefix}.readonly`)) {
46
+ return {
47
+ accessLevel: "read-only"
48
+ };
49
+ }
50
+
16
51
  // Check for full access: either wildcard or the schema's fullAccess permission.
17
- const hasFullAccess = value.some(p => p.name === "*" || p.name === schema.fullAccess.name);
52
+ const fullAccessName = `${schema.prefix}.*`;
53
+ const hasFullAccess = value.some(p => p.name === "*" || p.name === fullAccessName);
18
54
  if (hasFullAccess) {
19
55
  return {
20
56
  accessLevel: "full"
@@ -67,14 +103,18 @@ function deserializePermissions(schema, value) {
67
103
  */
68
104
  function serializePermissions(schema, formData, currentValue) {
69
105
  // Start by filtering out all permissions belonging to this schema's prefix.
70
- const filtered = Array.isArray(currentValue) ? currentValue.filter(p => !p.name.startsWith(schema.prefix)) : [];
106
+ const filtered = Array.isArray(currentValue) ? currentValue.filter(p => !p.name.startsWith(schema.prefix) && !p.name.startsWith(`$${schema.prefix}`)) : [];
71
107
  if (formData.accessLevel === "no" || !formData.accessLevel) {
72
108
  return filtered;
73
109
  }
74
110
  if (formData.accessLevel === "full") {
111
+ return [...filtered, resolveFullAccess(schema)];
112
+ }
113
+ const readOnlyPermissions = resolveReadOnlyAccess(schema);
114
+ if (formData.accessLevel === "read-only" && readOnlyPermissions) {
75
115
  return [...filtered, {
76
- ...schema.fullAccess
77
- }];
116
+ name: `$${schema.prefix}.readonly`
117
+ }, ...readOnlyPermissions];
78
118
  }
79
119
  const entities = schema.entities || [];
80
120
 
@@ -199,7 +239,7 @@ export function usePermissionForm(schema, options) {
199
239
  if (options.serialize) {
200
240
  result = options.serialize(data, result.filter(p => p.name.startsWith(schema.prefix)));
201
241
  // Re-add non-schema permissions that were filtered out.
202
- const nonSchemaPermissions = Array.isArray(value) ? value.filter(p => !p.name.startsWith(schema.prefix)) : [];
242
+ const nonSchemaPermissions = Array.isArray(value) ? value.filter(p => !p.name.startsWith(schema.prefix) && !p.name.startsWith(`$${schema.prefix}`)) : [];
203
243
  result = [...nonSchemaPermissions, ...result];
204
244
  }
205
245
  onChange(result);
@@ -1 +1 @@
1
- {"version":3,"names":["useMemo","useCallback","hasAction","entity","name","actions","some","a","deserializePermissions","schema","value","Array","isArray","accessLevel","hasFullAccess","p","fullAccess","ownPermissions","filter","startsWith","prefix","length","data","entities","perm","find","permission","own","id","action","rwd","pw","split","serializePermissions","formData","currentValue","filtered","entityMap","Map","set","resolvedScopes","scope","resolvedScope","dependsOn","parentScope","get","has","delete","parentEntity","parentRwd","includes","requires","permissions","join","push","usePermissionForm","options","onChange","deserialize","extra","onFormChange","result","serialize","nonSchemaPermissions"],"sources":["usePermissionForm.ts"],"sourcesContent":["import { useMemo, useCallback } from \"react\";\nimport type {\n Permission,\n PermissionSchema,\n EntityDefinition,\n UsePermissionFormOptions,\n UsePermissionFormResult\n} from \"./types.js\";\n\nfunction hasAction(entity: EntityDefinition, name: string): boolean {\n return entity.actions?.some(a => a.name === name) ?? false;\n}\n\n/**\n * Deserialize Permission[] into form data based on the schema.\n */\nfunction deserializePermissions(\n schema: PermissionSchema,\n value: Permission[]\n): Record<string, any> {\n if (!Array.isArray(value)) {\n return { accessLevel: \"no\" };\n }\n\n // Check for full access: either wildcard or the schema's fullAccess permission.\n const hasFullAccess = value.some(p => p.name === \"*\" || p.name === schema.fullAccess.name);\n if (hasFullAccess) {\n return { accessLevel: \"full\" };\n }\n\n // Filter permissions that belong to this schema's prefix.\n const ownPermissions = value.filter(p => p.name.startsWith(schema.prefix));\n if (ownPermissions.length === 0) {\n return { accessLevel: \"no\" };\n }\n\n // Custom access level — extract per-entity form fields.\n const data: Record<string, any> = { accessLevel: \"custom\" };\n const entities = schema.entities || [];\n\n for (const entity of entities) {\n const perm = ownPermissions.find(p => p.name === entity.permission);\n if (!perm) {\n continue;\n }\n\n // Access scope: \"own\" if perm.own === true, else \"full\".\n if (perm.own === true) {\n data[`${entity.id}AccessScope`] = \"own\";\n } else {\n data[`${entity.id}AccessScope`] = \"full\";\n }\n\n // Process actions.\n for (const action of entity.actions ?? []) {\n if (action.name === \"rwd\") {\n data[`${entity.id}RWD`] = perm.rwd || \"r\";\n } else if (action.name === \"pw\") {\n data[`${entity.id}PW`] = perm.pw ? perm.pw.split(\"\") : [];\n } else {\n // Custom boolean action.\n data[`${entity.id}Action_${action.name}`] = perm[action.name] === true;\n }\n }\n }\n\n return data;\n}\n\n/**\n * Serialize form data into Permission[] based on the schema.\n */\nfunction serializePermissions(\n schema: PermissionSchema,\n formData: Record<string, any>,\n currentValue: Permission[]\n): Permission[] {\n // Start by filtering out all permissions belonging to this schema's prefix.\n const filtered = Array.isArray(currentValue)\n ? currentValue.filter(p => !p.name.startsWith(schema.prefix))\n : [];\n\n if (formData.accessLevel === \"no\" || !formData.accessLevel) {\n return filtered;\n }\n\n if (formData.accessLevel === \"full\") {\n return [...filtered, { ...schema.fullAccess }];\n }\n\n const entities = schema.entities || [];\n\n // Custom access — build entity permissions.\n // First, build a map of entity definitions by ID for dependency lookups.\n const entityMap = new Map<string, EntityDefinition>();\n for (const entity of entities) {\n entityMap.set(entity.id, entity);\n }\n\n // Resolve cascading \"own\" scopes: if a parent is \"own\", children must be \"own\" too.\n const resolvedScopes = new Map<string, string>();\n for (const entity of entities) {\n const scope = formData[`${entity.id}AccessScope`];\n if (!scope || scope === \"no\") {\n continue;\n }\n\n let resolvedScope = scope;\n\n // If this entity depends on a parent and the parent scope is \"own\",\n // force this entity's scope to \"own\" as well.\n if (entity.dependsOn) {\n const parentScope = resolvedScopes.get(entity.dependsOn.entity);\n if (parentScope === \"own\") {\n resolvedScope = \"own\";\n }\n }\n\n resolvedScopes.set(entity.id, resolvedScope);\n }\n\n // Prune resolved scopes based on dependencies (must run before building permissions\n // so that transitive dependencies are properly pruned).\n for (const entity of entities) {\n if (!entity.dependsOn || !resolvedScopes.has(entity.id)) {\n continue;\n }\n\n const parentScope = resolvedScopes.get(entity.dependsOn.entity);\n if (!parentScope) {\n // Parent entity is not enabled — prune child.\n resolvedScopes.delete(entity.id);\n continue;\n }\n\n const parentEntity = entityMap.get(entity.dependsOn.entity);\n if (parentEntity && hasAction(parentEntity, \"rwd\")) {\n const parentRwd =\n parentScope === \"own\" ? \"rwd\" : formData[`${entity.dependsOn.entity}RWD`] || \"r\";\n if (!parentRwd.includes(entity.dependsOn.requires)) {\n // Parent doesn't have the required action — prune child.\n resolvedScopes.delete(entity.id);\n }\n }\n }\n\n // Build permissions from the pruned resolved scopes.\n const permissions: Permission[] = [];\n\n for (const entity of entities) {\n const scope = resolvedScopes.get(entity.id);\n if (!scope) {\n continue;\n }\n\n const perm: Permission = {\n name: entity.permission\n };\n\n if (scope === \"own\") {\n perm.own = true;\n if (hasAction(entity, \"rwd\")) {\n perm.rwd = \"rwd\";\n }\n } else if (hasAction(entity, \"rwd\")) {\n perm.rwd = formData[`${entity.id}RWD`] || \"r\";\n }\n\n // Process non-rwd actions.\n for (const action of entity.actions ?? []) {\n if (action.name === \"rwd\") {\n continue; // Already handled above.\n }\n\n if (action.name === \"pw\") {\n const pw: string[] = formData[`${entity.id}PW`] || [];\n if (pw.length > 0) {\n perm.pw = pw.join(\"\");\n }\n } else {\n // Custom boolean action.\n if (formData[`${entity.id}Action_${action.name}`]) {\n perm[action.name] = true;\n }\n }\n }\n\n permissions.push(perm);\n }\n\n return [...filtered, ...permissions];\n}\n\n/**\n * Hook that bridges a permission schema with a Form component.\n *\n * Handles bidirectional transformation between Permission[] and form data,\n * with optional custom serialize/deserialize callbacks for app-specific needs.\n */\nexport function usePermissionForm(\n schema: PermissionSchema,\n options: UsePermissionFormOptions\n): UsePermissionFormResult {\n const { value, onChange } = options;\n\n const formData = useMemo(() => {\n let data = deserializePermissions(schema, value);\n\n // Merge custom deserialized data if provided.\n if (options.deserialize) {\n const extra = options.deserialize(Array.isArray(value) ? value : []);\n data = { ...data, ...extra };\n }\n\n return data;\n }, []);\n\n const onFormChange = useCallback(\n (data: Record<string, any>) => {\n let result = serializePermissions(schema, data, value);\n\n // Apply custom serializer if provided.\n if (options.serialize) {\n result = options.serialize(\n data,\n result.filter(p => p.name.startsWith(schema.prefix))\n );\n // Re-add non-schema permissions that were filtered out.\n const nonSchemaPermissions = Array.isArray(value)\n ? value.filter(p => !p.name.startsWith(schema.prefix))\n : [];\n result = [...nonSchemaPermissions, ...result];\n }\n\n onChange(result);\n },\n [value]\n );\n\n return { formData, onFormChange };\n}\n\n// Export the pure functions for unit testing.\nexport { deserializePermissions, serializePermissions };\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["useMemo","useCallback","hasAction","entity","name","actions","some","a","resolveFullAccess","schema","prefix","fullAccess","resolveReadOnlyAccess","readOnlyAccess","undefined","rwd","deserializePermissions","value","Array","isArray","accessLevel","p","fullAccessName","hasFullAccess","ownPermissions","filter","startsWith","length","data","entities","perm","find","permission","own","id","action","pw","split","serializePermissions","formData","currentValue","filtered","readOnlyPermissions","entityMap","Map","set","resolvedScopes","scope","resolvedScope","dependsOn","parentScope","get","has","delete","parentEntity","parentRwd","includes","requires","permissions","join","push","usePermissionForm","options","onChange","deserialize","extra","onFormChange","result","serialize","nonSchemaPermissions"],"sources":["usePermissionForm.ts"],"sourcesContent":["import { useMemo, useCallback } from \"react\";\nimport type {\n Permission,\n PermissionSchema,\n EntityDefinition,\n UsePermissionFormOptions,\n UsePermissionFormResult\n} from \"./types.js\";\n\nfunction hasAction(entity: EntityDefinition, name: string): boolean {\n return entity.actions?.some(a => a.name === name) ?? false;\n}\n\n/** Resolve fullAccess config into a concrete Permission object. */\nfunction resolveFullAccess(schema: PermissionSchema): Permission {\n const name = `${schema.prefix}.*`;\n if (schema.fullAccess === true) {\n return { name };\n }\n return { name, ...schema.fullAccess };\n}\n\n/** Resolve readOnlyAccess config into a concrete Permission[]. */\nfunction resolveReadOnlyAccess(schema: PermissionSchema): Permission[] | undefined {\n if (!schema.readOnlyAccess) {\n return undefined;\n }\n if (schema.readOnlyAccess === true) {\n return [{ name: `${schema.prefix}.*`, rwd: \"r\" }];\n }\n return schema.readOnlyAccess;\n}\n\n/**\n * Deserialize Permission[] into form data based on the schema.\n */\nfunction deserializePermissions(\n schema: PermissionSchema,\n value: Permission[]\n): Record<string, any> {\n if (!Array.isArray(value)) {\n return { accessLevel: \"no\" };\n }\n\n // Check for read-only access by looking for the synthetic marker permission.\n if (value.some(p => p.name === `$${schema.prefix}.readonly`)) {\n return { accessLevel: \"read-only\" };\n }\n\n // Check for full access: either wildcard or the schema's fullAccess permission.\n const fullAccessName = `${schema.prefix}.*`;\n const hasFullAccess = value.some(p => p.name === \"*\" || p.name === fullAccessName);\n if (hasFullAccess) {\n return { accessLevel: \"full\" };\n }\n\n // Filter permissions that belong to this schema's prefix.\n const ownPermissions = value.filter(p => p.name.startsWith(schema.prefix));\n if (ownPermissions.length === 0) {\n return { accessLevel: \"no\" };\n }\n\n // Custom access level — extract per-entity form fields.\n const data: Record<string, any> = { accessLevel: \"custom\" };\n const entities = schema.entities || [];\n\n for (const entity of entities) {\n const perm = ownPermissions.find(p => p.name === entity.permission);\n if (!perm) {\n continue;\n }\n\n // Access scope: \"own\" if perm.own === true, else \"full\".\n if (perm.own === true) {\n data[`${entity.id}AccessScope`] = \"own\";\n } else {\n data[`${entity.id}AccessScope`] = \"full\";\n }\n\n // Process actions.\n for (const action of entity.actions ?? []) {\n if (action.name === \"rwd\") {\n data[`${entity.id}RWD`] = perm.rwd || \"r\";\n } else if (action.name === \"pw\") {\n data[`${entity.id}PW`] = perm.pw ? perm.pw.split(\"\") : [];\n } else {\n // Custom boolean action.\n data[`${entity.id}Action_${action.name}`] = perm[action.name] === true;\n }\n }\n }\n\n return data;\n}\n\n/**\n * Serialize form data into Permission[] based on the schema.\n */\nfunction serializePermissions(\n schema: PermissionSchema,\n formData: Record<string, any>,\n currentValue: Permission[]\n): Permission[] {\n // Start by filtering out all permissions belonging to this schema's prefix.\n const filtered = Array.isArray(currentValue)\n ? currentValue.filter(\n p => !p.name.startsWith(schema.prefix) && !p.name.startsWith(`$${schema.prefix}`)\n )\n : [];\n\n if (formData.accessLevel === \"no\" || !formData.accessLevel) {\n return filtered;\n }\n\n if (formData.accessLevel === \"full\") {\n return [...filtered, resolveFullAccess(schema)];\n }\n\n const readOnlyPermissions = resolveReadOnlyAccess(schema);\n if (formData.accessLevel === \"read-only\" && readOnlyPermissions) {\n return [...filtered, { name: `$${schema.prefix}.readonly` }, ...readOnlyPermissions];\n }\n\n const entities = schema.entities || [];\n\n // Custom access — build entity permissions.\n // First, build a map of entity definitions by ID for dependency lookups.\n const entityMap = new Map<string, EntityDefinition>();\n for (const entity of entities) {\n entityMap.set(entity.id, entity);\n }\n\n // Resolve cascading \"own\" scopes: if a parent is \"own\", children must be \"own\" too.\n const resolvedScopes = new Map<string, string>();\n for (const entity of entities) {\n const scope = formData[`${entity.id}AccessScope`];\n if (!scope || scope === \"no\") {\n continue;\n }\n\n let resolvedScope = scope;\n\n // If this entity depends on a parent and the parent scope is \"own\",\n // force this entity's scope to \"own\" as well.\n if (entity.dependsOn) {\n const parentScope = resolvedScopes.get(entity.dependsOn.entity);\n if (parentScope === \"own\") {\n resolvedScope = \"own\";\n }\n }\n\n resolvedScopes.set(entity.id, resolvedScope);\n }\n\n // Prune resolved scopes based on dependencies (must run before building permissions\n // so that transitive dependencies are properly pruned).\n for (const entity of entities) {\n if (!entity.dependsOn || !resolvedScopes.has(entity.id)) {\n continue;\n }\n\n const parentScope = resolvedScopes.get(entity.dependsOn.entity);\n if (!parentScope) {\n // Parent entity is not enabled — prune child.\n resolvedScopes.delete(entity.id);\n continue;\n }\n\n const parentEntity = entityMap.get(entity.dependsOn.entity);\n if (parentEntity && hasAction(parentEntity, \"rwd\")) {\n const parentRwd =\n parentScope === \"own\" ? \"rwd\" : formData[`${entity.dependsOn.entity}RWD`] || \"r\";\n if (!parentRwd.includes(entity.dependsOn.requires)) {\n // Parent doesn't have the required action — prune child.\n resolvedScopes.delete(entity.id);\n }\n }\n }\n\n // Build permissions from the pruned resolved scopes.\n const permissions: Permission[] = [];\n\n for (const entity of entities) {\n const scope = resolvedScopes.get(entity.id);\n if (!scope) {\n continue;\n }\n\n const perm: Permission = {\n name: entity.permission\n };\n\n if (scope === \"own\") {\n perm.own = true;\n if (hasAction(entity, \"rwd\")) {\n perm.rwd = \"rwd\";\n }\n } else if (hasAction(entity, \"rwd\")) {\n perm.rwd = formData[`${entity.id}RWD`] || \"r\";\n }\n\n // Process non-rwd actions.\n for (const action of entity.actions ?? []) {\n if (action.name === \"rwd\") {\n continue; // Already handled above.\n }\n\n if (action.name === \"pw\") {\n const pw: string[] = formData[`${entity.id}PW`] || [];\n if (pw.length > 0) {\n perm.pw = pw.join(\"\");\n }\n } else {\n // Custom boolean action.\n if (formData[`${entity.id}Action_${action.name}`]) {\n perm[action.name] = true;\n }\n }\n }\n\n permissions.push(perm);\n }\n\n return [...filtered, ...permissions];\n}\n\n/**\n * Hook that bridges a permission schema with a Form component.\n *\n * Handles bidirectional transformation between Permission[] and form data,\n * with optional custom serialize/deserialize callbacks for app-specific needs.\n */\nexport function usePermissionForm(\n schema: PermissionSchema,\n options: UsePermissionFormOptions\n): UsePermissionFormResult {\n const { value, onChange } = options;\n\n const formData = useMemo(() => {\n let data = deserializePermissions(schema, value);\n\n // Merge custom deserialized data if provided.\n if (options.deserialize) {\n const extra = options.deserialize(Array.isArray(value) ? value : []);\n data = { ...data, ...extra };\n }\n\n return data;\n }, []);\n\n const onFormChange = useCallback(\n (data: Record<string, any>) => {\n let result = serializePermissions(schema, data, value);\n\n // Apply custom serializer if provided.\n if (options.serialize) {\n result = options.serialize(\n data,\n result.filter(p => p.name.startsWith(schema.prefix))\n );\n // Re-add non-schema permissions that were filtered out.\n const nonSchemaPermissions = Array.isArray(value)\n ? value.filter(\n p =>\n !p.name.startsWith(schema.prefix) &&\n !p.name.startsWith(`$${schema.prefix}`)\n )\n : [];\n result = [...nonSchemaPermissions, ...result];\n }\n\n onChange(result);\n },\n [value]\n );\n\n return { formData, onFormChange };\n}\n\n// Export the pure functions for unit testing.\nexport { deserializePermissions, serializePermissions };\n"],"mappings":"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","ignoreList":[]}
@@ -24,7 +24,8 @@ function getEntity(entityMap, entityId) {
24
24
  return entity;
25
25
  }
26
26
  function buildResult(schema, identity) {
27
- const hasFullAccess = !!identity.getPermission(schema.fullAccess.name);
27
+ const fullAccessName = `${schema.prefix}.*`;
28
+ const hasFullAccess = !!identity.getPermission(fullAccessName);
28
29
  const entityMap = buildEntityMap(schema);
29
30
  const canAccess = entityId => {
30
31
  if (hasFullAccess) {
@@ -1 +1 @@
1
- {"version":3,"names":["useIdentity","cache","WeakMap","buildEntityMap","schema","map","Map","entity","entities","actions","Set","action","add","name","set","id","permission","hasOwn","scopes","includes","getEntity","entityMap","entityId","get","Error","buildResult","identity","hasFullAccess","getPermission","fullAccess","canAccess","permissions","getPermissions","length","canRead","some","rwd","canCreate","canEdit","item","own","createdBy","canDelete","canPublish","pw","canUnpublish","canAction","createUsePermissions","usePermissions","byIdentityId","result"],"sources":["usePermissions.ts"],"sourcesContent":["import { useIdentity } from \"~/presentation/security/hooks/useIdentity.js\";\nimport type { Identity } from \"~/domain/Identity.js\";\nimport type { PermissionSchemaConfig } from \"./types.js\";\nimport type { OwnableItem } from \"./types.js\";\nimport type { UsePermissionsResult } from \"./types.js\";\n\ninterface EntityLookup {\n permission: string;\n actions: Set<string>;\n hasOwn: boolean;\n}\n\n// Module-level cache: schema -> identityId -> result.\nconst cache = new WeakMap<PermissionSchemaConfig, Map<string, UsePermissionsResult<any>>>();\n\nfunction buildEntityMap(schema: PermissionSchemaConfig): Map<string, EntityLookup> {\n const map = new Map<string, EntityLookup>();\n for (const entity of schema.entities ?? []) {\n const actions = new Set<string>();\n for (const action of entity.actions ?? []) {\n actions.add(action.name);\n }\n map.set(entity.id, {\n permission: entity.permission,\n actions,\n hasOwn: entity.scopes.includes(\"own\")\n });\n }\n return map;\n}\n\nfunction getEntity(entityMap: Map<string, EntityLookup>, entityId: string): EntityLookup {\n const entity = entityMap.get(entityId);\n if (!entity) {\n throw new Error(`Unknown entity \"${entityId}\" in permission schema.`);\n }\n return entity;\n}\n\nfunction buildResult<S extends PermissionSchemaConfig>(\n schema: S,\n identity: Identity\n): UsePermissionsResult<S> {\n const hasFullAccess = !!identity.getPermission(schema.fullAccess.name);\n const entityMap = buildEntityMap(schema);\n\n const canAccess = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n return permissions.length > 0;\n };\n\n const canRead = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"r\");\n });\n };\n\n const canCreate = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"w\");\n });\n };\n\n const canEdit = (entityId: string, item?: OwnableItem): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (permission.own) {\n if (!item?.createdBy) {\n return true;\n }\n return item.createdBy.id === identity.id;\n }\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"w\");\n });\n };\n\n const canDelete = (entityId: string, item?: OwnableItem): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (permission.own) {\n return item?.createdBy?.id === identity.id;\n }\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"d\");\n });\n };\n\n const canPublish = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission.pw?.includes(\"p\");\n });\n };\n\n const canUnpublish = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission.pw?.includes(\"u\");\n });\n };\n\n const canAction = (action: string, entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission[action] === true;\n });\n };\n\n return {\n canAccess,\n canRead,\n canCreate,\n canEdit,\n canDelete,\n canPublish,\n canUnpublish,\n canAction\n } as UsePermissionsResult<S>;\n}\n\nexport function createUsePermissions<const S extends PermissionSchemaConfig>(\n schema: S\n): () => UsePermissionsResult<S> {\n return function usePermissions(): UsePermissionsResult<S> {\n const { identity } = useIdentity();\n\n let byIdentityId = cache.get(schema);\n if (!byIdentityId) {\n byIdentityId = new Map();\n cache.set(schema, byIdentityId);\n }\n\n let result = byIdentityId.get(identity.id) as UsePermissionsResult<S> | undefined;\n if (!result) {\n result = buildResult(schema, identity);\n byIdentityId.set(identity.id, result as UsePermissionsResult<any>);\n }\n\n return result;\n };\n}\n"],"mappings":"AAAA,SAASA,WAAW;AAYpB;AACA,MAAMC,KAAK,GAAG,IAAIC,OAAO,CAAiE,CAAC;AAE3F,SAASC,cAAcA,CAACC,MAA8B,EAA6B;EAC/E,MAAMC,GAAG,GAAG,IAAIC,GAAG,CAAuB,CAAC;EAC3C,KAAK,MAAMC,MAAM,IAAIH,MAAM,CAACI,QAAQ,IAAI,EAAE,EAAE;IACxC,MAAMC,OAAO,GAAG,IAAIC,GAAG,CAAS,CAAC;IACjC,KAAK,MAAMC,MAAM,IAAIJ,MAAM,CAACE,OAAO,IAAI,EAAE,EAAE;MACvCA,OAAO,CAACG,GAAG,CAACD,MAAM,CAACE,IAAI,CAAC;IAC5B;IACAR,GAAG,CAACS,GAAG,CAACP,MAAM,CAACQ,EAAE,EAAE;MACfC,UAAU,EAAET,MAAM,CAACS,UAAU;MAC7BP,OAAO;MACPQ,MAAM,EAAEV,MAAM,CAACW,MAAM,CAACC,QAAQ,CAAC,KAAK;IACxC,CAAC,CAAC;EACN;EACA,OAAOd,GAAG;AACd;AAEA,SAASe,SAASA,CAACC,SAAoC,EAAEC,QAAgB,EAAgB;EACrF,MAAMf,MAAM,GAAGc,SAAS,CAACE,GAAG,CAACD,QAAQ,CAAC;EACtC,IAAI,CAACf,MAAM,EAAE;IACT,MAAM,IAAIiB,KAAK,CAAC,mBAAmBF,QAAQ,yBAAyB,CAAC;EACzE;EACA,OAAOf,MAAM;AACjB;AAEA,SAASkB,WAAWA,CAChBrB,MAAS,EACTsB,QAAkB,EACK;EACvB,MAAMC,aAAa,GAAG,CAAC,CAACD,QAAQ,CAACE,aAAa,CAACxB,MAAM,CAACyB,UAAU,CAAChB,IAAI,CAAC;EACtE,MAAMQ,SAAS,GAAGlB,cAAc,CAACC,MAAM,CAAC;EAExC,MAAM0B,SAAS,GAAIR,QAAgB,IAAc;IAC7C,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,OAAOe,WAAW,CAACE,MAAM,GAAG,CAAC;EACjC,CAAC;EAED,MAAMC,OAAO,GAAIZ,QAAgB,IAAc;IAC3C,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,IAAI,OAAOA,UAAU,CAACoB,GAAG,KAAK,QAAQ,EAAE;QACpC,OAAO,IAAI;MACf;MACA,OAAOpB,UAAU,CAACoB,GAAG,CAACjB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAMkB,SAAS,GAAIf,QAAgB,IAAc;IAC7C,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,IAAI,OAAOA,UAAU,CAACoB,GAAG,KAAK,QAAQ,EAAE;QACpC,OAAO,IAAI;MACf;MACA,OAAOpB,UAAU,CAACoB,GAAG,CAACjB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAMmB,OAAO,GAAGA,CAAChB,QAAgB,EAAEiB,IAAkB,KAAc;IAC/D,IAAIZ,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,IAAIA,UAAU,CAACwB,GAAG,EAAE;QAChB,IAAI,CAACD,IAAI,EAAEE,SAAS,EAAE;UAClB,OAAO,IAAI;QACf;QACA,OAAOF,IAAI,CAACE,SAAS,CAAC1B,EAAE,KAAKW,QAAQ,CAACX,EAAE;MAC5C;MACA,IAAI,OAAOC,UAAU,CAACoB,GAAG,KAAK,QAAQ,EAAE;QACpC,OAAO,IAAI;MACf;MACA,OAAOpB,UAAU,CAACoB,GAAG,CAACjB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAMuB,SAAS,GAAGA,CAACpB,QAAgB,EAAEiB,IAAkB,KAAc;IACjE,IAAIZ,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,IAAIA,UAAU,CAACwB,GAAG,EAAE;QAChB,OAAOD,IAAI,EAAEE,SAAS,EAAE1B,EAAE,KAAKW,QAAQ,CAACX,EAAE;MAC9C;MACA,IAAI,OAAOC,UAAU,CAACoB,GAAG,KAAK,QAAQ,EAAE;QACpC,OAAO,IAAI;MACf;MACA,OAAOpB,UAAU,CAACoB,GAAG,CAACjB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAMwB,UAAU,GAAIrB,QAAgB,IAAc;IAC9C,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,OAAOA,UAAU,CAAC4B,EAAE,EAAEzB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAM0B,YAAY,GAAIvB,QAAgB,IAAc;IAChD,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,OAAOA,UAAU,CAAC4B,EAAE,EAAEzB,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC,CAAC;EACN,CAAC;EAED,MAAM2B,SAAS,GAAGA,CAACnC,MAAc,EAAEW,QAAgB,KAAc;IAC7D,IAAIK,aAAa,EAAE;MACf,OAAO,IAAI;IACf;IACA,MAAMpB,MAAM,GAAGa,SAAS,CAACC,SAAS,EAAEC,QAAQ,CAAC;IAC7C,MAAMS,WAAW,GAAGL,QAAQ,CAACM,cAAc,CAACzB,MAAM,CAACS,UAAU,CAAC;IAC9D,IAAI,CAACe,WAAW,CAACE,MAAM,EAAE;MACrB,OAAO,KAAK;IAChB;IACA,OAAOF,WAAW,CAACI,IAAI,CAACnB,UAAU,IAAI;MAClC,OAAOA,UAAU,CAACL,MAAM,CAAC,KAAK,IAAI;IACtC,CAAC,CAAC;EACN,CAAC;EAED,OAAO;IACHmB,SAAS;IACTI,OAAO;IACPG,SAAS;IACTC,OAAO;IACPI,SAAS;IACTC,UAAU;IACVE,YAAY;IACZC;EACJ,CAAC;AACL;AAEA,OAAO,SAASC,oBAAoBA,CAChC3C,MAAS,EACoB;EAC7B,OAAO,SAAS4C,cAAcA,CAAA,EAA4B;IACtD,MAAM;MAAEtB;IAAS,CAAC,GAAG1B,WAAW,CAAC,CAAC;IAElC,IAAIiD,YAAY,GAAGhD,KAAK,CAACsB,GAAG,CAACnB,MAAM,CAAC;IACpC,IAAI,CAAC6C,YAAY,EAAE;MACfA,YAAY,GAAG,IAAI3C,GAAG,CAAC,CAAC;MACxBL,KAAK,CAACa,GAAG,CAACV,MAAM,EAAE6C,YAAY,CAAC;IACnC;IAEA,IAAIC,MAAM,GAAGD,YAAY,CAAC1B,GAAG,CAACG,QAAQ,CAACX,EAAE,CAAwC;IACjF,IAAI,CAACmC,MAAM,EAAE;MACTA,MAAM,GAAGzB,WAAW,CAACrB,MAAM,EAAEsB,QAAQ,CAAC;MACtCuB,YAAY,CAACnC,GAAG,CAACY,QAAQ,CAACX,EAAE,EAAEmC,MAAmC,CAAC;IACtE;IAEA,OAAOA,MAAM;EACjB,CAAC;AACL","ignoreList":[]}
1
+ {"version":3,"names":["useIdentity","cache","WeakMap","buildEntityMap","schema","map","Map","entity","entities","actions","Set","action","add","name","set","id","permission","hasOwn","scopes","includes","getEntity","entityMap","entityId","get","Error","buildResult","identity","fullAccessName","prefix","hasFullAccess","getPermission","canAccess","permissions","getPermissions","length","canRead","some","rwd","canCreate","canEdit","item","own","createdBy","canDelete","canPublish","pw","canUnpublish","canAction","createUsePermissions","usePermissions","byIdentityId","result"],"sources":["usePermissions.ts"],"sourcesContent":["import { useIdentity } from \"~/presentation/security/hooks/useIdentity.js\";\nimport type { Identity } from \"~/domain/Identity.js\";\nimport type { PermissionSchemaConfig } from \"./types.js\";\nimport type { OwnableItem } from \"./types.js\";\nimport type { UsePermissionsResult } from \"./types.js\";\n\ninterface EntityLookup {\n permission: string;\n actions: Set<string>;\n hasOwn: boolean;\n}\n\n// Module-level cache: schema -> identityId -> result.\nconst cache = new WeakMap<PermissionSchemaConfig, Map<string, UsePermissionsResult<any>>>();\n\nfunction buildEntityMap(schema: PermissionSchemaConfig): Map<string, EntityLookup> {\n const map = new Map<string, EntityLookup>();\n for (const entity of schema.entities ?? []) {\n const actions = new Set<string>();\n for (const action of entity.actions ?? []) {\n actions.add(action.name);\n }\n map.set(entity.id, {\n permission: entity.permission,\n actions,\n hasOwn: entity.scopes.includes(\"own\")\n });\n }\n return map;\n}\n\nfunction getEntity(entityMap: Map<string, EntityLookup>, entityId: string): EntityLookup {\n const entity = entityMap.get(entityId);\n if (!entity) {\n throw new Error(`Unknown entity \"${entityId}\" in permission schema.`);\n }\n return entity;\n}\n\nfunction buildResult<S extends PermissionSchemaConfig>(\n schema: S,\n identity: Identity\n): UsePermissionsResult<S> {\n const fullAccessName = `${schema.prefix}.*`;\n const hasFullAccess = !!identity.getPermission(fullAccessName);\n const entityMap = buildEntityMap(schema);\n\n const canAccess = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n return permissions.length > 0;\n };\n\n const canRead = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"r\");\n });\n };\n\n const canCreate = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"w\");\n });\n };\n\n const canEdit = (entityId: string, item?: OwnableItem): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (permission.own) {\n if (!item?.createdBy) {\n return true;\n }\n return item.createdBy.id === identity.id;\n }\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"w\");\n });\n };\n\n const canDelete = (entityId: string, item?: OwnableItem): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n if (permission.own) {\n return item?.createdBy?.id === identity.id;\n }\n if (typeof permission.rwd !== \"string\") {\n return true;\n }\n return permission.rwd.includes(\"d\");\n });\n };\n\n const canPublish = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission.pw?.includes(\"p\");\n });\n };\n\n const canUnpublish = (entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission.pw?.includes(\"u\");\n });\n };\n\n const canAction = (action: string, entityId: string): boolean => {\n if (hasFullAccess) {\n return true;\n }\n const entity = getEntity(entityMap, entityId);\n const permissions = identity.getPermissions(entity.permission);\n if (!permissions.length) {\n return false;\n }\n return permissions.some(permission => {\n return permission[action] === true;\n });\n };\n\n return {\n canAccess,\n canRead,\n canCreate,\n canEdit,\n canDelete,\n canPublish,\n canUnpublish,\n canAction\n } as UsePermissionsResult<S>;\n}\n\nexport function createUsePermissions<const S extends PermissionSchemaConfig>(\n schema: S\n): () => UsePermissionsResult<S> {\n return function usePermissions(): UsePermissionsResult<S> {\n const { identity } = useIdentity();\n\n let byIdentityId = cache.get(schema);\n if (!byIdentityId) {\n byIdentityId = new Map();\n cache.set(schema, byIdentityId);\n }\n\n let result = byIdentityId.get(identity.id) as UsePermissionsResult<S> | undefined;\n if (!result) {\n result = buildResult(schema, identity);\n byIdentityId.set(identity.id, result as UsePermissionsResult<any>);\n }\n\n return result;\n };\n}\n"],"mappings":"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","ignoreList":[]}