Skip to content

Commit ed11477

Browse files
committed
Merge branch 'feature/upgrade-guide' of github.com:os2display/display-api-service into feature/upgrade-guide
2 parents 4d96e4e + 15e81d0 commit ed11477

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+664
-1121
lines changed

.github/workflows/playwright.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ jobs:
2222
run: |
2323
docker compose run --rm phpfpm composer install
2424
25+
- name: Copy fixture assets to public/fixtures
26+
run: |
27+
docker compose run --rm phpfpm cp -r fixtures/public/fixtures public/fixtures
28+
2529
- name: Build assets
2630
run: |
2731
docker compose run --rm node npm install

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Ignore custom templates folder.
22
/assets/shared/custom-templates/*
33

4+
# Ignore the public/fixtures folder.
5+
/public/fixtures
6+
47
# Ignore release json file.
58
/public/release.json
69

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ All notable changes to this project will be documented in this file.
1818
* Added update command.
1919
* Added (Client) online-check to public.
2020
* Updated developer documentation.
21+
* Removed admin/access-config.json fetch
22+
* Aligned with v. 2.5.2.
23+
* Removed themes.
2124
* Added command to migrate config.json files.
2225

2326
### NB! Prior to 3.x the project was split into separate repositories

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,13 @@ For example:
577577
booking system you can implement a "FeedSource" that fetches booking data from your source and normalizes it to match
578578
the calendar output model.
579579

580+
## Themes
581+
582+
It is possible to create themes that can apply to select templates. See `/admin/themes` in the Admin.
583+
584+
The theme css has to follow som rules. See [docs/themes/themes.md](docs/themes/themes.md) for instructions on writing
585+
custom themes.
586+
580587
## Custom Templates
581588

582589
OS2Display ships with some standard templates. These are located in `assets/shared/templates`.

Taskfile.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ tasks:
3030
- task compose-up
3131
- task composer-install
3232
- task db:migrate --yes
33+
- task fixtures:copy-assets
3334
- task site-open
3435
silent: true
3536

@@ -44,6 +45,7 @@ tasks:
4445
- task composer-install
4546
- task db:migrate --yes
4647
- task fixtures:load --yes
48+
- task fixtures:copy-assets
4749
- task site-open
4850
silent: true
4951

@@ -221,3 +223,8 @@ tasks:
221223
desc: "Migrate to latest database schema and update installed templates"
222224
cmds:
223225
- task compose -- exec phpfpm bin/console app:update --no-interaction
226+
227+
fixtures:copy-assets:
228+
desc: "Copy the folder from fixtures/public/fixtures to public/fixtures. Rerun if fixtures are changed."
229+
cmds:
230+
- task compose -- exec phpfpm cp -r fixtures/public/fixtures public/fixtures

assets/admin/app.jsx

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ function App() {
5555
const [authenticated, setAuthenticated] = useState();
5656
const [config, setConfig] = useState();
5757
const [selectedTenant, setSelectedTenant] = useState();
58-
const [accessConfig, setAccessConfig] = useState();
5958
const [tenants, setTenants] = useState();
6059
const [userName, setUserName] = useState("");
6160
const [userType, setUserType] = useState("");
@@ -66,6 +65,26 @@ function App() {
6665
const [isPublished, setIsPublished] = useState("all");
6766
const [exists, setExists] = useState(null);
6867
const [screenUserLatestRequest, setScreenUserLatestRequest] = useState(null);
68+
const [accessConfig, setAccessConfig] = useState({
69+
campaign: {
70+
roles: ["ROLE_ADMIN"],
71+
},
72+
screen: {
73+
roles: ["ROLE_ADMIN"],
74+
},
75+
settings: {
76+
roles: ["ROLE_ADMIN"],
77+
},
78+
groups: {
79+
roles: ["ROLE_ADMIN"],
80+
},
81+
shared: {
82+
roles: ["ROLE_ADMIN"],
83+
},
84+
users: {
85+
roles: ["ROLE_ADMIN", "ROLE_EXTERNAL_USER_ADMIN"],
86+
},
87+
});
6988

7089
const userStore = {
7190
authenticated: { get: authenticated, set: setAuthenticated },
@@ -150,36 +169,6 @@ function App() {
150169
};
151170
}, []);
152171

153-
useEffect(() => {
154-
fetch("/admin/access-config.json")
155-
.then((response) => response.json())
156-
.then((jsonData) => {
157-
setAccessConfig(jsonData);
158-
})
159-
.catch(() => {
160-
setAccessConfig({
161-
campaign: {
162-
roles: ["ROLE_ADMIN"],
163-
},
164-
screen: {
165-
roles: ["ROLE_ADMIN"],
166-
},
167-
settings: {
168-
roles: ["ROLE_ADMIN"],
169-
},
170-
groups: {
171-
roles: ["ROLE_ADMIN"],
172-
},
173-
shared: {
174-
roles: ["ROLE_ADMIN"],
175-
},
176-
users: {
177-
roles: ["ROLE_ADMIN", "ROLE_EXTERNAL_USER_ADMIN"],
178-
},
179-
});
180-
});
181-
}, []);
182-
183172
useEffect(() => {
184173
i18next.init({
185174
interpolation: { escapeValue: false }, // React already does escaping

assets/admin/components/screen/util/grid-generation-and-select.jsx

Lines changed: 52 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { useState, useEffect } from "react";
22
import { Tabs, Tab, Alert } from "react-bootstrap";
3-
import {
4-
createGridArea,
5-
createGrid,
6-
} from "../../../../shared/grid-generator/grid-generator";
3+
import Grid from "./grid";
74
import { useTranslation } from "react-i18next";
85
import { useDispatch } from "react-redux";
96
import idFromUrl from "../../util/helpers/id-from-url";
@@ -31,15 +28,10 @@ function GridGenerationAndSelect({
3128
}) {
3229
const { t } = useTranslation("common");
3330
const dispatch = useDispatch();
34-
const [key, setKey] = useState(regions.length > 0 ? regions[0]["@id"] : "");
31+
const [selectedRegion, setSelectedRegion] = useState(
32+
regions.length > 0 ? regions[0]["@id"] : "",
33+
);
3534
const [selectedPlaylists, setSelectedPlaylists] = useState([]);
36-
const gridClasses = `grid ${vertical ? "vertical" : "horizontal"}`;
37-
// Rows and columns in grid defaults to 1.
38-
const configColumns = grid?.columns || 1;
39-
const configRows = grid?.rows || 1;
40-
const gridTemplateAreas = {
41-
gridTemplateAreas: createGrid(configColumns, configRows),
42-
};
4335

4436
/**
4537
* @param {object} props The props
@@ -149,87 +141,67 @@ function GridGenerationAndSelect({
149141
setSelectedPlaylists(playlists);
150142
};
151143

152-
/** @param {string} id - The id of the selected tab */
153-
const handleSelect = (id) => {
154-
setKey(id);
155-
};
156-
157144
/**
158-
* Removes playlist from list of playlists, and closes modal.
145+
* Removes playlist from list of playlists.
159146
*
160-
* @param {object} inputPlaylist - InputPlaylist to remove
161-
* @param {object} inputRegion - InputRegion to remove from
147+
* @param {object} inputPlaylistId - InputPlaylistId to remove
148+
* @param {object} inputRegionId - InputRegionId to remove from
162149
*/
163-
const removeFromList = (inputPlaylist, inputRegion) => {
164-
const indexOfItemToRemove = selectedPlaylists.findIndex(
165-
({ "@id": id, region }) => {
166-
return region === inputRegion && id === inputPlaylist;
167-
},
150+
const removeFromList = (inputPlaylistId, inputRegionId) => {
151+
setSelectedPlaylists((prev) =>
152+
prev.filter(
153+
({ "@id": id, region: regionId }) =>
154+
!(regionId === inputRegionId && id === inputPlaylistId),
155+
),
168156
);
169-
const selectedPlaylistsCopy = [...selectedPlaylists];
170-
selectedPlaylistsCopy.splice(indexOfItemToRemove, 1);
171-
setSelectedPlaylists(selectedPlaylistsCopy);
172157
};
173158

159+
if (regions?.length === 0) return null;
160+
174161
return (
175162
<>
176163
<div className="col-md-4 my-3 my-md-0">
177164
<div className="bg-light border rounded p-1">
178-
<div className={gridClasses} style={gridTemplateAreas}>
179-
{regions &&
180-
regions.map((data) => (
181-
<div
182-
key={data["@id"]}
183-
className={
184-
key === data["@id"] ? "grid-item selected" : "grid-item "
185-
}
186-
style={{ gridArea: createGridArea(data.gridArea) }}
187-
>
188-
{data.title}
189-
</div>
190-
))}
191-
</div>
165+
<Grid
166+
grid={grid}
167+
vertical={vertical}
168+
regions={regions}
169+
selected={selectedRegion}
170+
/>
192171
</div>
193172
</div>
194173
<div className="col-md-12">
195-
{regions.length > 0 && (
196-
<>
197-
<h3 className="h5">{t("screen-form.screen-region-playlists")}</h3>
198-
<Tabs
199-
defaultActiveKey={regions[0]["@id"]}
200-
id="tabs"
201-
onSelect={handleSelect}
202-
className="mb-3"
203-
>
204-
{regions &&
205-
regions.map((data) => (
206-
<Tab
207-
eventKey={data["@id"]}
208-
key={data["@id"]}
209-
title={data.title}
210-
>
211-
<PlaylistDragAndDrop
212-
id="playlist_drag_and_drop"
213-
handleChange={handleChange}
214-
removeFromList={removeFromList}
215-
name={data["@id"]}
216-
regionIdForInitializeCallback={data["@id"]}
217-
screenId={screenId}
218-
regionId={idFromUrl(data["@id"])}
219-
selectedPlaylists={selectedPlaylists.filter(
220-
({ region }) => region === idFromUrl(data["@id"]),
221-
)}
222-
/>
223-
{data?.type === "touch-buttons" && (
224-
<Alert key="screen-form-touch-buttons" variant="info">
225-
{t("screen-form.touch-region-helptext")}
226-
</Alert>
227-
)}
228-
</Tab>
229-
))}
230-
</Tabs>
231-
</>
232-
)}
174+
<>
175+
<h3 className="h5">{t("screen-form.screen-region-playlists")}</h3>
176+
<Tabs
177+
defaultActiveKey={regions[0]["@id"]}
178+
id="tabs"
179+
onSelect={setSelectedRegion}
180+
className="mb-3"
181+
>
182+
{regions.map(({ title, "@id": id, type }) => (
183+
<Tab eventKey={id} key={id} title={title}>
184+
<PlaylistDragAndDrop
185+
id="playlist_drag_and_drop"
186+
handleChange={handleChange}
187+
removeFromList={removeFromList}
188+
name={id}
189+
regionIdForInitializeCallback={id}
190+
screenId={screenId}
191+
regionId={idFromUrl(id)}
192+
selectedPlaylists={selectedPlaylists.filter(
193+
({ region }) => region === idFromUrl(id),
194+
)}
195+
/>
196+
{type === "touch-buttons" && (
197+
<Alert key="screen-form-touch-buttons" variant="info">
198+
{t("screen-form.touch-region-helptext")}
199+
</Alert>
200+
)}
201+
</Tab>
202+
))}
203+
</Tabs>
204+
</>
233205
</div>
234206
</>
235207
);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {
2+
createGridArea,
3+
createGrid,
4+
} from "../../../../shared/grid-generator/grid-generator";
5+
6+
// Rows and columns in grid defaults to 1.
7+
const Grid = ({
8+
vertical,
9+
regions,
10+
selected,
11+
grid: { columns = 1, rows = 1 },
12+
}) => {
13+
const gridClasses = `grid ${vertical ? "vertical" : "horizontal"}`;
14+
const gridTemplateAreas = {
15+
gridTemplateAreas: createGrid(columns, rows),
16+
};
17+
18+
return (
19+
<div className={gridClasses} style={gridTemplateAreas}>
20+
{regions.map((region) => (
21+
<div
22+
key={region["@id"]}
23+
className={
24+
selected === region["@id"] ? "grid-item selected" : "grid-item "
25+
}
26+
style={{ gridArea: createGridArea(region.gridArea) }}
27+
>
28+
{region.title}
29+
</div>
30+
))}
31+
</div>
32+
);
33+
};
34+
35+
export default Grid;

0 commit comments

Comments
 (0)