Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
"plugin:prettier/recommended"
],
"ignorePatterns": ["*.yml"],
"globals": {
"window": true,
"localStorage": true,
"document": true
},
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: |
docker network create frontend
docker compose run --rm node yarn install
docker compose run --rm node yarn check-coding-standards
docker compose run --rm node yarn check-coding-standards-actions
playwright-tests:
name: Playwright
Expand Down
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

- [#264](https://github.com/os2display/display-admin-client/pull/264)
- Added checkbox options component for use in calendar modifiers.
- Fixed multiselect when more than one feed source of the given type is installed.
- Fixed github action to fail on warnings.
- [#268](https://github.com/os2display/display-admin-client/pull/268)
- Added feed source UI.

Expand All @@ -23,8 +27,6 @@ All notable changes to this project will be documented in this file.
- Add validation checking if template is selected on slide before save
- [#260](https://github.com/os2display/display-admin-client/pull/260)
- Bug in multiselect, fixed by removing duplicates by key both `@id`and `id`
- [#265](https://github.com/os2display/display-admin-client/pull/265)
- Bug in multiselect, fixed by removing duplicates by key both `@id`and `id`
- [#259](https://github.com/os2display/display-admin-client/pull/259)
- Add saving of playlists/groups with screen (as opposed to _after_)
- Clean up `screen-manager.jsx`
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,14 @@
},
"scripts": {
"lint:js": "eslint --ext .js --ext .jsx ./src",
"lint-actions:js": "eslint --ext .js --ext .jsx ./src --max-warnings=0",
"lint:js:fix": "eslint --ext .js --ext .jsx --fix ./src",
"lint:scss": "stylelint \"./src/**/*.scss\"",
"lint-actions:scss": "stylelint \"./src/**/*.scss\" --max-warnings=0",
"lint:scss:fix": "stylelint --fix \"./src/**/*.scss\"",
"check-coding-standards": "yarn lint:js && yarn lint:scss",
"apply-coding-standards": "yarn lint:js:fix && yarn lint:scss:fix",
"check-coding-standards-actions": "yarn lint-actions:js && yarn lint-actions:scss",
"start": "vite --host 0.0.0.0",
"build": "vite build",
"preview": "vite preview"
Expand Down
54 changes: 33 additions & 21 deletions src/components/feed-sources/feed-source-form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import FormSelect from "../util/forms/select";
import ContentBody from "../util/content-body/content-body";
import ContentFooter from "../util/content-footer/content-footer";
import FormInput from "../util/forms/form-input";
import CalendarFeedType from "./templates/calendar-feed-type.jsx";
import NotifiedFeedType from "./templates/notified-feed-type.jsx";
import EventDatabaseFeedType from "./templates/event-database-feed-type.jsx";
import CalendarApiFeedType from "./templates/calendar-api-feed-type";
import NotifiedFeedType from "./templates/notified-feed-type";
import EventDatabaseApiFeedType from "./templates/event-database-feed-type";

/**
* The feed-source form component.
Expand All @@ -22,13 +22,14 @@ import EventDatabaseFeedType from "./templates/event-database-feed-type.jsx";
* @param {Function} props.handleInput Handles form input.
* @param {Function} props.handleSubmit Handles form submit.
* @param {string} props.headerText Headline text.
* @param {boolean} [props.isLoading=false] Indicator of whether the form is
* loading. Default is `false`
* @param {string} [props.loadingMessage=""] The loading message for the
* spinner. Default is `""`
* @param {object} props.feedSource The feed source object
* @param {boolean} [props.isLoading] Indicator of whether the form is loading.
* Default is `false`
* @param {string} [props.loadingMessage] The loading message for the spinner.
* Default is `""`
* @param {object} props.feedSourceTypeOptions The options for feed source types
* @param {string} props.mode The mode
* @param {Function} props.onFeedTypeChange Callback on feed type change.
* @param {Function} props.handleSecretInput Callback on secret input change.
* @returns {object} The feed-source form.
*/
function FeedSourceForm({
Expand Down Expand Up @@ -81,15 +82,28 @@ function FeedSourceForm({
options={feedSourceTypeOptions}
/>

{feedSource?.feedType === "App\\Feed\\CalendarApiFeedType" &&
(<CalendarFeedType handleInput={handleSecretInput} formStateObject={feedSource.secrets} mode={mode} />)
}
{feedSource?.feedType === "App\\Feed\\NotifiedFeedType" &&
(<NotifiedFeedType handleInput={handleSecretInput} formStateObject={feedSource.secrets} mode={mode} />)
}
{feedSource?.feedType === "App\\Feed\\EventDatabaseApiFeedType" &&
(<EventDatabaseFeedType handleInput={handleSecretInput} formStateObject={feedSource.secrets} mode={mode} />)
}
{feedSource?.feedType === "App\\Feed\\CalendarApiFeedType" && (
<CalendarApiFeedType
handleInput={handleSecretInput}
formStateObject={feedSource.secrets}
mode={mode}
feedSourceId={feedSource["@id"]}
/>
)}
{feedSource?.feedType === "App\\Feed\\EventDatabaseApiFeedType" && (
<EventDatabaseApiFeedType
handleInput={handleSecretInput}
formStateObject={feedSource.secrets}
mode={mode}
/>
)}
{feedSource?.feedType === "App\\Feed\\NotifiedFeedType" && (
<NotifiedFeedType
handleInput={handleSecretInput}
formStateObject={feedSource.secrets}
mode={mode}
/>
)}
</ContentBody>
<ContentFooter>
<Button
Expand Down Expand Up @@ -126,13 +140,11 @@ FeedSourceForm.propTypes = {
}),
handleInput: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
handleSecretInput: PropTypes.func.isRequired,
onFeedTypeChange: PropTypes.func.isRequired,
headerText: PropTypes.string.isRequired,
isLoading: PropTypes.bool,
loadingMessage: PropTypes.string,
dynamicFormElement: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element),
]),
feedSourceTypeOptions: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string.isRequired,
Expand Down
45 changes: 21 additions & 24 deletions src/components/feed-sources/feed-source-manager.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cloneElement, React, useEffect, useState } from "react";
import { React, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
Expand All @@ -11,9 +11,6 @@ import {
displayError,
displaySuccess,
} from "../util/list/toast-component/display-toast";
import EventDatabaseFeedType from "./templates/event-database-feed-type.jsx";
import NotifiedFeedType from "./templates/notified-feed-type.jsx";
import CalendarFeedType from "./templates/calendar-feed-type.jsx";

/**
* The theme manager component.
Expand Down Expand Up @@ -48,7 +45,6 @@ function FeedSourceManager({
t("loading-messages.loading-feed-source")
);

const [dynamicFormElement, setDynamicFormElement] = useState();
const [submitting, setSubmitting] = useState(false);
const [formStateObject, setFormStateObject] = useState({});

Expand All @@ -68,23 +64,23 @@ function FeedSourceManager({
title: t("dynamic-fields.event-database-api-feed-type.title"),
key: "1",
secretsDefault: {
"host": ""
host: "",
},
},
{
value: "App\\Feed\\NotifiedFeedType",
title: t("dynamic-fields.notified-feed-type.title"),
key: "2",
secretsDefault: {
"token": "",
token: "",
},
},
{
value: "App\\Feed\\CalendarApiFeedType",
title: t("dynamic-fields.calendar-api-feed-type.title"),
key: "3",
key: "0",
secretsDefault: {
"resources": []
locations: [],
},
},
{
Expand All @@ -109,26 +105,29 @@ function FeedSourceManager({

/** Set loaded data into form state. */
useEffect(() => {
setFormStateObject({ ...initialState });
}, [initialState]);
const newState = { ...initialState };

const handleSecretInput = ({target}) => {
const localFormStateObject = { ...formStateObject };
if (!localFormStateObject.secrets) {
localFormStateObject.secrets = {};
if (newState.secrets instanceof Array) {
newState.secrets = {};
}
localFormStateObject.secrets[target.id] = target.value;
setFormStateObject(localFormStateObject);

setFormStateObject(newState);
}, [initialState]);

const handleSecretInput = ({ target }) => {
const secrets = { ...formStateObject.secrets };
secrets[target.id] = target.value;
setFormStateObject({ ...formStateObject, secrets });
};

const onFeedTypeChange = ({target}) => {
const value = target.value
const onFeedTypeChange = ({ target }) => {
const { value } = target;
const option = feedSourceTypeOptions.find((opt) => opt.value === value);
const newFormStateObject = {...formStateObject};
const newFormStateObject = { ...formStateObject };
newFormStateObject.feedType = value;
newFormStateObject.secrets = {...option.secretsDefault};
newFormStateObject.secrets = { ...option.secretsDefault };
setFormStateObject(newFormStateObject);
}
};

/** Save feed source. */
function saveFeedSource() {
Expand Down Expand Up @@ -193,7 +192,6 @@ function FeedSourceManager({
onFeedTypeChange={onFeedTypeChange}
handleSecretInput={handleSecretInput}
feedSourceTypeOptions={feedSourceTypeOptions}
dynamicFormElement={dynamicFormElement}
mode={saveMethod}
/>
)}
Expand Down Expand Up @@ -222,7 +220,6 @@ FeedSourceManager.propTypes = {
status: PropTypes.number,
}),
}),
mode: PropTypes.string,
};

export default FeedSourceManager;
7 changes: 3 additions & 4 deletions src/components/feed-sources/feed-sources-columns.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { React, useContext } from "react";
import { useTranslation } from "react-i18next";
import ColumnHoc from "../util/column-hoc";
import ListButton from "../util/list/list-button.jsx";
import SelectColumnHoc from "../util/select-column-hoc.jsx";
import UserContext from "../../context/user-context.jsx";
import ListButton from "../util/list/list-button";
import SelectColumnHoc from "../util/select-column-hoc";
import UserContext from "../../context/user-context";

/**
* Retrieves the columns for feed sources data based on API call response.
Expand All @@ -12,7 +12,6 @@ import UserContext from "../../context/user-context.jsx";
* @param {Function} props.apiCall - The API call function to retrieve feed sources data.
* @param {string} props.infoModalRedirect - The redirect URL for information modal.
* @param {string} props.infoModalTitle - The title for information modal.
* @param {string} props.dataKey - The key for data retrieval.
* @returns {object} Columns - An array of objects representing the columns for
* feed sources data.
*/
Expand Down
14 changes: 7 additions & 7 deletions src/components/feed-sources/feed-sources-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import {
useDeleteV2FeedSourcesByIdMutation,
useGetV2FeedSourcesByIdSlidesQuery,
} from "../../redux/api/api.generated.ts";
import ListContext from "../../context/list-context.jsx";
import ContentBody from "../util/content-body/content-body.jsx";
import List from "../util/list/list.jsx";
import ListContext from "../../context/list-context";
import ContentBody from "../util/content-body/content-body";
import List from "../util/list/list";
import { FeedSourceColumns } from "./feed-sources-columns";
import {
displayError,
displaySuccess,
} from "../util/list/toast-component/display-toast.jsx";
import idFromUrl from "../util/helpers/id-from-url.jsx";
import UserContext from "../../context/user-context.jsx";
import useModal from "../../context/modal-context/modal-context-hook.jsx";
} from "../util/list/toast-component/display-toast";
import idFromUrl from "../util/helpers/id-from-url";
import UserContext from "../../context/user-context";
import useModal from "../../context/modal-context/modal-context-hook";

/**
* The feed sources list component.
Expand Down
55 changes: 55 additions & 0 deletions src/components/feed-sources/templates/calendar-api-feed-type.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { React, useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { Alert } from "react-bootstrap";
import MultiselectFromEndpoint from "../../slide/content/multiselect-from-endpoint";
import ConfigLoader from "../../../config-loader";

const CalendarApiFeedType = ({
feedSourceId,
handleInput,
formStateObject,
}) => {
const { t } = useTranslation("common", {
keyPrefix: "feed-source-manager.dynamic-fields.calendar-api-feed-type",
});

const [optionsEndpoint, setOptionsEndpoint] = useState(null);

useEffect(() => {
if (feedSourceId && feedSourceId !== "") {
ConfigLoader.loadConfig().then((config) => {
setOptionsEndpoint(`${config.api + feedSourceId}/config/locations`);
});
}
}, [feedSourceId]);

return (
<>
{!feedSourceId && (
<Alert className="mt-4" variant="warning">
{t("save-before-locations-can-be-set")}
</Alert>
)}
{optionsEndpoint && (
<MultiselectFromEndpoint
onChange={handleInput}
name="locations"
label={t("locations")}
value={formStateObject.locations ?? []}
optionsEndpoint={optionsEndpoint}
/>
)}
</>
);
};

CalendarApiFeedType.propTypes = {
handleInput: PropTypes.func,
formStateObject: PropTypes.shape({
locations: PropTypes.arrayOf(PropTypes.string),
}),
feedSourceId: PropTypes.string,
};

export default CalendarApiFeedType;
37 changes: 0 additions & 37 deletions src/components/feed-sources/templates/calendar-feed-type.jsx

This file was deleted.

Loading
Loading