Skip to content

Commit dca80ed

Browse files
authored
Merge pull request #280 from os2display/release/2.3.0
Release 2.3.0
2 parents 2fdf3d6 + f618eb7 commit dca80ed

17 files changed

+1384
-13
lines changed

.github/workflows/pr.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ jobs:
5454
docker compose run --rm playwright npx playwright install --with-deps
5555
docker compose run --rm playwright npx playwright test --retries 3
5656
57-
5857
- uses: actions/upload-artifact@v4
5958
if: always()
6059
with:

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55

66
## [Unreleased]
77

8+
## [2.3.0] - 2025-03-24
9+
10+
- [#279](https://github.com/os2display/display-admin-client/pull/279)
11+
- Eventdatabase v2 feed source - Change subscription endpoint.
12+
- Eventdatabase v2 feed source - Fixed options load.
13+
- [#271](https://github.com/os2display/display-admin-client/pull/271)
14+
- Added new feed source: Eventdatabasen v2.
15+
816
## [2.2.0] - 2025-03-17
917

1018
- [#273](https://github.com/os2display/display-admin-client/pull/273)

src/components/feed-sources/feed-source-form.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import FormInput from "../util/forms/form-input";
1313
import CalendarApiFeedType from "./templates/calendar-api-feed-type";
1414
import NotifiedFeedType from "./templates/notified-feed-type";
1515
import EventDatabaseApiFeedType from "./templates/event-database-feed-type";
16+
import EventDatabaseApiV2FeedType from "./templates/event-database-v2-feed-type";
1617

1718
/**
1819
* The feed-source form component.
@@ -97,6 +98,13 @@ function FeedSourceForm({
9798
mode={mode}
9899
/>
99100
)}
101+
{feedSource?.feedType === "App\\Feed\\EventDatabaseApiV2FeedType" && (
102+
<EventDatabaseApiV2FeedType
103+
handleInput={handleSecretInput}
104+
formStateObject={feedSource.secrets}
105+
mode={mode}
106+
/>
107+
)}
100108
{feedSource?.feedType === "App\\Feed\\NotifiedFeedType" && (
101109
<NotifiedFeedType
102110
handleInput={handleSecretInput}

src/components/feed-sources/feed-source-manager.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ function FeedSourceManager({
6767
host: "",
6868
},
6969
},
70+
{
71+
value: "App\\Feed\\EventDatabaseApiV2FeedType",
72+
title: t("event-database-api-v2-feed-type.title"),
73+
key: "7",
74+
secretsDefault: {
75+
host: "",
76+
apikey: "",
77+
},
78+
},
7079
{
7180
value: "App\\Feed\\NotifiedFeedType",
7281
title: t("dynamic-fields.notified-feed-type.title"),
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { React } from "react";
2+
import PropTypes from "prop-types";
3+
import { useTranslation } from "react-i18next";
4+
import FormInput from "../../util/forms/form-input";
5+
6+
const EventDatabaseApiV2FeedType = ({ handleInput, formStateObject, mode }) => {
7+
const { t } = useTranslation("common", {
8+
keyPrefix: "event-database-api-v2-feed-type",
9+
});
10+
return (
11+
<>
12+
<FormInput
13+
name="host"
14+
type="text"
15+
className="mb-2"
16+
label={t("host")}
17+
onChange={handleInput}
18+
value={formStateObject?.host}
19+
/>
20+
<FormInput
21+
name="apikey"
22+
type="text"
23+
label={t("apikey")}
24+
onChange={handleInput}
25+
placeholder={
26+
mode === "PUT" ? t("redacted-value-input-placeholder") : ""
27+
}
28+
value={formStateObject?.apikey}
29+
/>
30+
</>
31+
);
32+
};
33+
34+
EventDatabaseApiV2FeedType.propTypes = {
35+
handleInput: PropTypes.func,
36+
formStateObject: PropTypes.shape({
37+
host: PropTypes.string.isRequired,
38+
apikey: PropTypes.string,
39+
}),
40+
mode: PropTypes.string,
41+
};
42+
43+
export default EventDatabaseApiV2FeedType;

src/components/slide/content/feed-selector.jsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import MultiSelectComponent from "../../util/forms/multiselect-dropdown/multi-dr
1212
import idFromUrl from "../../util/helpers/id-from-url";
1313
import ContentForm from "./content-form";
1414
import MultiselectFromEndpoint from "./multiselect-from-endpoint";
15-
import PosterSelector from "./poster-selector";
15+
import PosterSelectorV1 from "./poster/poster-selector-v1";
16+
import PosterSelectorV2 from "./poster/poster-selector-v2";
1617

1718
/**
1819
* Feed selector.
@@ -96,9 +97,19 @@ function FeedSelector({
9697
onChange(newValue);
9798
};
9899

99-
const configurationChange = ({ target }) => {
100+
const configurationChange = ({ target = null, targets = null }) => {
100101
const configuration = { ...value.configuration };
101-
set(configuration, target.id, target.value);
102+
103+
if (target !== null) {
104+
set(configuration, target.id, target.value);
105+
}
106+
107+
if (targets !== null) {
108+
targets.forEach(({ id, value: targetValue }) => {
109+
set(configuration, id, targetValue);
110+
});
111+
}
112+
102113
const newValue = { ...value, configuration };
103114
onChange(newValue);
104115
};
@@ -129,10 +140,21 @@ function FeedSelector({
129140
}
130141
if (element?.input === "poster-selector") {
131142
return (
132-
<PosterSelector
143+
<PosterSelectorV1
144+
key={element.key}
145+
feedSource={feedSourceData}
146+
configurationChange={configurationChange}
147+
getValueFromConfiguration={getValueFromConfiguration}
148+
/>
149+
);
150+
}
151+
if (element?.input === "poster-selector-v2") {
152+
return (
153+
<PosterSelectorV2
133154
key={element.key}
134155
feedSource={feedSourceData}
135156
configurationChange={configurationChange}
157+
configuration={value.configuration}
136158
getValueFromConfiguration={getValueFromConfiguration}
137159
/>
138160
);
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import dayjs from "dayjs";
2+
import localeDa from "dayjs/locale/da";
3+
import localStorageKeys from "../../../util/local-storage-keys";
4+
5+
const capitalize = (s) => {
6+
return s.charAt(0).toUpperCase() + s.slice(1);
7+
};
8+
9+
const formatDate = (date, format) => {
10+
if (!date) return "";
11+
return capitalize(
12+
dayjs(date)
13+
.locale(localeDa)
14+
.format(format ?? "LLLL")
15+
);
16+
};
17+
18+
const loadDropdownOptions = (url, headers, inputValue, callback, type) => {
19+
const params = {
20+
type,
21+
display: "options",
22+
};
23+
24+
if (inputValue) {
25+
params.name = inputValue;
26+
}
27+
28+
const query = new URLSearchParams(params);
29+
30+
fetch(`${url}?${query}`, {
31+
headers,
32+
})
33+
.then((response) => response.json())
34+
.then((data) => {
35+
callback(data);
36+
})
37+
.catch(() => {
38+
callback([]);
39+
});
40+
};
41+
42+
const loadDropdownOptionsPromise = (url, headers, inputValue, type) => {
43+
return new Promise((resolve, reject) => {
44+
const params = {
45+
entityType: type,
46+
};
47+
48+
if (inputValue) {
49+
params.search = inputValue;
50+
}
51+
52+
const query = new URLSearchParams(params);
53+
fetch(`${url}?${query}`, {
54+
headers,
55+
})
56+
.then((response) => response.json())
57+
.then((data) => {
58+
resolve(data);
59+
})
60+
.catch((reason) => {
61+
reject(reason);
62+
});
63+
});
64+
};
65+
66+
const getHeaders = () => {
67+
const apiToken = localStorage.getItem(localStorageKeys.API_TOKEN);
68+
const tenantKey = JSON.parse(
69+
localStorage.getItem(localStorageKeys.SELECTED_TENANT)
70+
);
71+
72+
const headers = {
73+
authorization: `Bearer ${apiToken ?? ""}`,
74+
};
75+
76+
if (tenantKey) {
77+
headers["Authorization-Tenant-Key"] = tenantKey.tenantKey;
78+
}
79+
80+
return headers;
81+
};
82+
83+
export {
84+
formatDate,
85+
capitalize,
86+
loadDropdownOptions,
87+
getHeaders,
88+
loadDropdownOptionsPromise,
89+
};

src/components/slide/content/poster-selector.jsx renamed to src/components/slide/content/poster/poster-selector-v1.jsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import AsyncSelect from "react-select/async";
66
import Col from "react-bootstrap/Col";
77
import dayjs from "dayjs";
88
import localeDa from "dayjs/locale/da";
9-
import Select from "../../util/forms/select";
10-
import FormInput from "../../util/forms/form-input";
11-
import FormCheckbox from "../../util/forms/form-checkbox";
12-
import localStorageKeys from "../../util/local-storage-keys";
9+
import Select from "../../../util/forms/select";
10+
import FormInput from "../../../util/forms/form-input";
11+
import FormCheckbox from "../../../util/forms/form-checkbox";
12+
import localStorageKeys from "../../../util/local-storage-keys";
1313

1414
/**
1515
* @param {object} props Props.
@@ -19,7 +19,7 @@ import localStorageKeys from "../../util/local-storage-keys";
1919
* @param {Function} props.configurationChange Configuration onChange.
2020
* @returns {object} PosterSelector component.
2121
*/
22-
function PosterSelector({
22+
function PosterSelectorV1({
2323
feedSource,
2424
getValueFromConfiguration,
2525
configurationChange,
@@ -650,7 +650,7 @@ function PosterSelector({
650650
<th scope="col">
651651
{t("poster-selector.table-price")}
652652
</th>
653-
<th scope="col"> </th>
653+
<th scope="col" />
654654
</tr>
655655
</thead>
656656
<tbody>
@@ -890,7 +890,7 @@ function PosterSelector({
890890
/* eslint-enable jsx-a11y/control-has-associated-label */
891891
}
892892

893-
PosterSelector.propTypes = {
893+
PosterSelectorV1.propTypes = {
894894
getValueFromConfiguration: PropTypes.func.isRequired,
895895
configurationChange: PropTypes.func.isRequired,
896896
feedSource: PropTypes.shape({
@@ -903,4 +903,4 @@ PosterSelector.propTypes = {
903903
}).isRequired,
904904
};
905905

906-
export default PosterSelector;
906+
export default PosterSelectorV1;

0 commit comments

Comments
 (0)