@vonaffenfels/contentful-teasermanager 1.1.52 → 1.1.54

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.
Files changed (25) hide show
  1. package/dist/{_base_slate-editor_src_dev_testComponents_TestStory2_js.js → TestStory.js} +8 -8
  2. package/dist/{_base_slate-editor_src_dev_testComponents_TestStory_js.js → TestStory2.js} +8 -8
  3. package/dist/{_base_slate-editor_src_dev_testComponents_TestStory3_js.js → TestStory3.js} +2 -2
  4. package/dist/index.07e598363ffb4e0123dd.hot-update.js +11 -0
  5. package/dist/index.07e598363ffb4e0123dd.hot-update.json +1 -0
  6. package/dist/index.0d1613509edd22e9248f.hot-update.js +22 -0
  7. package/dist/index.0d1613509edd22e9248f.hot-update.json +1 -0
  8. package/dist/index.0ec04034fe489f78cde4.hot-update.js +22 -0
  9. package/dist/index.0ec04034fe489f78cde4.hot-update.json +1 -0
  10. package/dist/index.139c010356b53a858854.hot-update.js +254 -0
  11. package/dist/index.139c010356b53a858854.hot-update.json +1 -0
  12. package/dist/index.248976de3ac65b567b42.hot-update.js +22 -0
  13. package/dist/index.248976de3ac65b567b42.hot-update.json +1 -0
  14. package/dist/index.be6397413907713e60e7.hot-update.js +22 -0
  15. package/dist/index.be6397413907713e60e7.hot-update.json +1 -0
  16. package/dist/index.ff7cfd658909fc7ee335.hot-update.js +11 -0
  17. package/dist/index.ff7cfd658909fc7ee335.hot-update.json +1 -0
  18. package/dist/index.js +62130 -57640
  19. package/package.json +2 -2
  20. package/src/components/Contentful/ConfigScreen.js +140 -62
  21. package/src/components/Contentful/Dialog.js +58 -48
  22. package/src/components/Contentful/EntryEditor.js +8 -2
  23. package/src/components/Contentful/Page.js +2 -6
  24. package/src/components/NoAccess.js +13 -0
  25. package/src/index.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonaffenfels/contentful-teasermanager",
3
- "version": "1.1.52",
3
+ "version": "1.1.54",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "prepublish": "yarn run build",
@@ -99,7 +99,7 @@
99
99
  "@vonaffenfels/slate-editor": "^1.1.52",
100
100
  "webpack": "5.88.2"
101
101
  },
102
- "gitHead": "88c7407b7b42841eb1d38405a5c24c78bc5e6b7d",
102
+ "gitHead": "f5696a1d623a42c86821e19c6587211bb7274195",
103
103
  "publishConfig": {
104
104
  "access": "public"
105
105
  }
@@ -1,77 +1,155 @@
1
- import React, {Component} from 'react';
1
+ import React, {
2
+ useEffect, useState,
3
+ } from 'react';
2
4
  import {
3
- Heading, Form, TextField, Workbench, Paragraph,
5
+ Form, Workbench,
4
6
  } from '@contentful/forma-36-react-components';
7
+ import {
8
+ Button, DisplayText, Flex,
9
+ FormControl, Subheading, TextInput,
10
+ } from '@contentful/f36-components';
11
+ import {Multiselect} from '@contentful/f36-multiselect';
5
12
  import {css} from 'emotion';
6
13
 
7
- export default class Config extends Component {
14
+ const Config = ({sdk}) => {
15
+ const [params, setParams] = useState({
16
+ usersWithAccess: {},
17
+ portalsWithAccess: [],
18
+ });
19
+ const [spaceUsers, setSpaceUsers] = useState([]);
8
20
 
9
- constructor(props) {
10
- super(props);
11
- this.state = {parameters: {}};
21
+ const onConfigure = async () => {
22
+ const currentState = await sdk.app.getCurrentState();
12
23
 
13
- // `onConfigure` allows to configure a callback to be
14
- // invoked when a user attempts to install the app or update
15
- // its configuration.
16
- props.sdk.app.onConfigure(() => this.onConfigure());
17
- }
24
+ return {
25
+ parameters: params,
26
+ targetState: currentState,
27
+ };
28
+ };
18
29
 
19
- async componentDidMount() {
20
- // Get current parameters of the app.
21
- // If the app is not installed yet, `parameters` will be `null`.
22
- const parameters = await this.props.sdk.app.getParameters();
30
+ useEffect(() => {
31
+ if (sdk) {
32
+ sdk.app.getParameters().then(params => {
33
+ if (Array.isArray(params?.usersWithAccess)) {
34
+ params.usersWithAccess = {};
35
+ }
23
36
 
24
- this.setState(parameters ? {parameters} : this.state, () => {
25
- // Once preparation has finished, call `setReady` to hide
26
- // the loading screen and present the app to a user.
27
- this.props.sdk.app.setReady();
28
- });
29
- }
37
+ setParams(params);
38
+ sdk.app.setReady();
39
+ });
40
+ sdk.space.getUsers().then(users => {
41
+ setSpaceUsers(users.items.map(v => v.email));
42
+ });
43
+ }
44
+ }, [sdk]);
30
45
 
31
- async onConfigure() {
32
- // This method will be called when a user clicks on "Install"
33
- // or "Save" in the configuration screen.
34
- // for more details see https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#register-an-app-configuration-hook
46
+ useEffect(() => {
47
+ if (sdk) {
48
+ sdk.app.onConfigure(() => onConfigure());
49
+ }
50
+ }, [sdk, params]);
35
51
 
36
- // Get current the state of EditorInterface and other entities
37
- // related to this app installation
38
- const currentState = await this.props.sdk.app.getCurrentState();
52
+ const handleSelectItem = (event, portal) => {
53
+ const {
54
+ checked,
55
+ value,
56
+ } = event.target;
39
57
 
40
- return {
41
- // Parameters to be persisted as the app configuration.
42
- parameters: this.state.parameters,
43
- // In case you don't want to submit any update to app
44
- // locations, you can just pass the currentState as is
45
- targetState: currentState,
46
- };
47
- }
58
+ console.log("ConfigScreen.js:58 / handleSelectItem", params?.usersWithAccess, portal);
59
+ let newValue = params?.usersWithAccess?.[portal] || [];
60
+ if (checked) {
61
+ newValue = [...newValue, value];
62
+ } else {
63
+ newValue = newValue.filter((email) => email !== value);
64
+ }
48
65
 
49
- onFieldChanged(value, field) {
50
- this.setState({
51
- parameters: {
52
- ...this.state.parameters,
53
- [field]: value,
66
+ console.log(
67
+ "ConfigScreen.js:65 / handleSelectItem", params.usersWithAccess, newValue, portal,
68
+ );
69
+ setParams({
70
+ ...params,
71
+ usersWithAccess: {
72
+ ...(params.usersWithAccess || {}),
73
+ [portal]: newValue,
54
74
  },
55
75
  });
56
- }
57
-
58
- render() {
59
- return (
60
- <Workbench className={css({
61
- padding: '80px',
62
- backgroundColor: "#FFF",
63
- })}>
64
- <Form>
65
- <Heading>Configuration</Heading>
66
- <TextField
67
- value={this.state.parameters.contentField}
68
- onChange={e => this.onFieldChanged(e.target.value, "contentField")}
69
- labelText="Content Field Name"
70
- required
71
- />
72
- </Form>
73
- </Workbench>
74
- );
75
- }
76
+ };
77
+
78
+ const addPortal = () => {
79
+ const newPortal = document.getElementsByName("newPortal")[0].value;
80
+ const portals = params.portalsWithAccess || [];
81
+
82
+ if (!newPortal || portals.includes(newPortal)) {
83
+ return;
84
+ }
85
+
86
+ setParams({
87
+ ...params,
88
+ portalsWithAccess: [...portals, newPortal.trim()].filter(Boolean),
89
+ });
90
+ };
91
+
92
+ const removePortal = (portal) => {
93
+ const portals = params.portalsWithAccess || [];
94
+
95
+ setParams({
96
+ ...params,
97
+ portalsWithAccess: portals.filter(v => v !== portal),
98
+ });
99
+ };
100
+
101
+ return (
102
+ <Workbench className={css({
103
+ padding: '80px',
104
+ backgroundColor: "#FFF",
105
+ })}>
106
+ <Form>
107
+ <FormControl>
108
+ <FormControl.Label>Teasermanager Portale mit Zugriffsbeschränkung</FormControl.Label>
109
+ <Flex flexDirection="column" gap={"spacingM"}>
110
+ <Flex flexDirection="row" gap={"spacingM"}>
111
+ <TextInput name="newPortal"/>
112
+ <Button onClick={addPortal} variant="positive">Portal hinzufügen</Button>
113
+ </Flex>
114
+ <Flex flexDirection="column" gap={"spacingM"}>
115
+ {params.portalsWithAccess?.map((portal) => {
116
+ return <Flex flexDirection="row" gap={"spacingM"} key={portal}>
117
+ <Subheading style={{width: "200px"}}>{portal}</Subheading>
118
+ <Button
119
+ variant="negative"
120
+ key={portal}
121
+ onClick={e => removePortal(portal)}>Löschen</Button>
122
+ </Flex>;
123
+ })}
124
+ </Flex>
125
+ </Flex>
126
+ </FormControl>
127
+ {params.portalsWithAccess?.map((portal) => {
128
+ return <FormControl key={portal}>
129
+ <FormControl.Label>{portal} Teasermanager Benutzer</FormControl.Label>
130
+ <Multiselect
131
+ currentSelection={params.usersWithAccess?.[portal]}
132
+ popoverProps={{isFullWidth: true}}
133
+ >
134
+ {spaceUsers.map((userEmail) => {
135
+ const val = userEmail.toLowerCase().replace(/\s/g, '-');
136
+ return (
137
+ <Multiselect.Option
138
+ key={`user-${val}}`}
139
+ itemId={`user-${portal}-${val}}`}
140
+ value={userEmail}
141
+ label={userEmail}
142
+ onSelectItem={e => handleSelectItem(e, portal)}
143
+ isChecked={params.usersWithAccess?.[portal]?.includes(userEmail)}
144
+ />
145
+ );
146
+ })}
147
+ </Multiselect>
148
+ </FormControl>;
149
+ })}
150
+ </Form>
151
+ </Workbench>
152
+ );
153
+ };
76
154
 
77
- }
155
+ export default Config;
@@ -1,48 +1,58 @@
1
- import React, {useEffect, useState} from 'react';
2
- import {NewestArticles} from "./Dialog/NewestArticles";
3
-
4
- const Dialog = ({sdk, portals, getArticleThumbnailUrl}) => {
5
- const [slotState, setSlotState] = useState({});
6
-
7
- const selectEntry = (entry) => {
8
- sdk.close(entry);
9
- }
10
-
11
- const loadSlotStateForPage = async () => {
12
- try {
13
- const apiRoot = sdk.parameters.instance.apiRoot;
14
- const portal = sdk.parameters.invocation.portal;
15
- const pageId = sdk.parameters.invocation.entryId;
16
- const date = sdk.parameters.invocation.date;
17
- const teasermanagerUrl = `${apiRoot}/api/findStateForPage?project=${portal}&page=${pageId}&date=${date.toISOString()}`;
18
- const response = await fetch(teasermanagerUrl).then(res => res.json());
19
-
20
- if (response?.message) {
21
- console.error(response.message);
22
- }
23
-
24
- return response?.data || {};
25
- } catch (e) {
26
- console.error(e);
27
- }
28
- }
29
-
30
- useEffect(() => {
31
- loadSlotStateForPage().then(setSlotState);
32
- }, [sdk.parameters.invocation]);
33
-
34
- return <div style={{backgroundColor: "#FFFFFF", minHeight: "100vh"}}>
35
- <NewestArticles sdk={sdk} onEntryClick={selectEntry} slotState={slotState} getArticleThumbnailUrl={getArticleThumbnailUrl} portals={portals}/>
36
- {/*
37
- <Tabs defaultTab="newest">
38
- <Tabs.List>
39
- <Tabs.Tab panelId="newest">Neuste Artikel</Tabs.Tab>
40
- </Tabs.List>
41
- <Tabs.Panel id="newest">
42
- </Tabs.Panel>
43
- </Tabs>
44
- */}
45
- </div>
46
- };
47
-
48
- export default Dialog;
1
+ import React, {
2
+ useEffect, useState,
3
+ } from 'react';
4
+ import {NewestArticles} from "./Dialog/NewestArticles";
5
+ import {NoAccess} from "../NoAccess";
6
+
7
+ const Dialog = ({
8
+ sdk,
9
+ portals,
10
+ getArticleThumbnailUrl,
11
+ }) => {
12
+ const [slotState, setSlotState] = useState({});
13
+
14
+ const selectEntry = (entry) => {
15
+ sdk.close(entry);
16
+ };
17
+
18
+ const loadSlotStateForPage = async () => {
19
+ try {
20
+ const apiRoot = sdk.parameters.instance.apiRoot;
21
+ const portal = sdk.parameters.invocation.portal;
22
+ const pageId = sdk.parameters.invocation.entryId;
23
+ const date = sdk.parameters.invocation.date;
24
+ const teasermanagerUrl = `${apiRoot}/api/findStateForPage?project=${portal}&page=${pageId}&date=${date.toISOString()}`;
25
+ const response = await fetch(teasermanagerUrl).then(res => res.json());
26
+
27
+ if (response?.message) {
28
+ console.error(response.message);
29
+ }
30
+
31
+ return response?.data || {};
32
+ } catch (e) {
33
+ console.error(e);
34
+ }
35
+ };
36
+
37
+ useEffect(() => {
38
+ loadSlotStateForPage().then(setSlotState);
39
+ }, [sdk.parameters.invocation]);
40
+
41
+ return <div style={{
42
+ backgroundColor: "#FFFFFF",
43
+ minHeight: "100vh",
44
+ }}>
45
+ <NewestArticles sdk={sdk} onEntryClick={selectEntry} slotState={slotState} getArticleThumbnailUrl={getArticleThumbnailUrl} portals={portals}/>
46
+ {/*
47
+ <Tabs defaultTab="newest">
48
+ <Tabs.List>
49
+ <Tabs.Tab panelId="newest">Neuste Artikel</Tabs.Tab>
50
+ </Tabs.List>
51
+ <Tabs.Panel id="newest">
52
+ </Tabs.Panel>
53
+ </Tabs>
54
+ */}
55
+ </div>;
56
+ };
57
+
58
+ export default Dialog;
@@ -2,12 +2,14 @@ import React, {
2
2
  useEffect, useState,
3
3
  } from 'react';
4
4
  import {Teasermanager} from "../Teasermanager";
5
+ import {NoAccess} from "../NoAccess";
5
6
 
6
7
  const Entry = ({sdk}) => {
7
8
  const contentField = sdk.parameters.instance.contentField;
8
9
  const [locale, setLocale] = useState(sdk.locales.default);
9
10
  const [portal, setPortal] = useState();
10
11
  const portalField = sdk?.entry?.fields?.portal;
12
+ const enabled = !sdk?.parameters?.installation?.usersWithAccess?.[portal] || sdk?.parameters?.installation?.usersWithAccess?.[portal]?.includes(sdk?.user?.email);
11
13
 
12
14
  portalField?.onValueChanged(() => {
13
15
  if (portalField.getValue() !== portal) {
@@ -86,7 +88,7 @@ const Entry = ({sdk}) => {
86
88
  console.error(e);
87
89
  alert("Fehler beim speichern!");
88
90
  }
89
- }
91
+ };
90
92
 
91
93
  const loadSlotStateForPage = async (date) => {
92
94
  try {
@@ -102,7 +104,7 @@ const Entry = ({sdk}) => {
102
104
  } catch (e) {
103
105
  console.error(e);
104
106
  }
105
- }
107
+ };
106
108
 
107
109
  const loadTimelineStateForPage = async (fromDate, toDate) => {
108
110
  try {
@@ -118,6 +120,10 @@ const Entry = ({sdk}) => {
118
120
  } catch (e) {
119
121
  console.error(e);
120
122
  }
123
+ };
124
+
125
+ if (!enabled) {
126
+ return <NoAccess sdk={sdk} portal={portal}/>;
121
127
  }
122
128
 
123
129
  return <Teasermanager
@@ -1,13 +1,9 @@
1
1
  import React from 'react';
2
2
  import {Teasermanager} from "../Teasermanager";
3
+ import {NoAccess} from "../NoAccess";
3
4
 
4
5
  const Page = ({sdk}) => {
5
-
6
- const onSlotClick = (slotId, currentDate) => {
7
- console.log("KIENZ_DEBUG: :7 / onSlotClick", {sdk});
8
- }
9
-
10
- return <Teasermanager entryId={"4RvZ6fcUtBIgw2Hw5YILPs"} onSlotClick={onSlotClick} />;
6
+ return <Teasermanager entryId={"4RvZ6fcUtBIgw2Hw5YILPs"} />;
11
7
  };
12
8
 
13
9
  export default Page;
@@ -0,0 +1,13 @@
1
+ import {
2
+ DisplayText, Flex, Paragraph,
3
+ } from "@contentful/f36-components";
4
+
5
+ export const NoAccess = ({sdk}) => {
6
+ return <Flex flexDirection="column" alignItems="center" paddingTop="spacing2Xl">
7
+ <DisplayText>
8
+ Kein Zugriff
9
+ </DisplayText>
10
+ <Paragraph>Bitte wenden Sie sich an einen Administrator wenn sie Zugriff benötigen</Paragraph>
11
+ <Paragraph>Angemeldeter Benutzer: {sdk?.user?.email}</Paragraph>
12
+ </Flex>;
13
+ };
package/src/index.js CHANGED
@@ -12,7 +12,7 @@ import Dialog from "./components/Contentful/Dialog";
12
12
  import Page from "./components/Contentful/Page";
13
13
  import {initContentfulClient} from "./lib/contentfulClient";
14
14
 
15
- export const BaseContentfulApp = (props) => {
15
+ export const BaseContentfulApp = (props = {}) => {
16
16
  init((sdk) => {
17
17
  const rootContainer = document.getElementById('root');
18
18