2021-03-25 14:22:43 +00:00
|
|
|
import { capitalize, isArray, isBoolean } from "lodash";
|
|
|
|
import React, {
|
|
|
|
FunctionComponent,
|
|
|
|
useCallback,
|
2021-11-13 03:38:37 +00:00
|
|
|
useEffect,
|
2021-03-25 14:22:43 +00:00
|
|
|
useMemo,
|
|
|
|
useState,
|
|
|
|
} from "react";
|
|
|
|
import { Button, Col, Container, Row } from "react-bootstrap";
|
2021-04-21 15:07:51 +00:00
|
|
|
import { components } from "react-select";
|
2021-11-03 02:33:24 +00:00
|
|
|
import { SelectComponents } from "react-select/dist/declarations/src/components";
|
2021-03-25 14:22:43 +00:00
|
|
|
import {
|
|
|
|
BaseModal,
|
|
|
|
Selector,
|
2021-08-16 18:28:18 +00:00
|
|
|
useModalInformation,
|
2021-03-25 14:22:43 +00:00
|
|
|
useOnModalShow,
|
|
|
|
useShowModal,
|
|
|
|
} from "../../components";
|
2021-08-24 01:31:47 +00:00
|
|
|
import { BuildKey, isReactText } from "../../utilities";
|
2021-03-25 14:22:43 +00:00
|
|
|
import {
|
|
|
|
Check,
|
|
|
|
ColCard,
|
|
|
|
Message,
|
|
|
|
StagedChangesContext,
|
|
|
|
Text,
|
|
|
|
useLatest,
|
|
|
|
useMultiUpdate,
|
|
|
|
} from "../components";
|
|
|
|
import { ProviderInfo, ProviderList } from "./list";
|
|
|
|
|
|
|
|
const ModalKey = "provider-modal";
|
|
|
|
const ProviderKey = "settings-general-enabled_providers";
|
|
|
|
|
|
|
|
export const ProviderView: FunctionComponent = () => {
|
|
|
|
const providers = useLatest<string[]>(ProviderKey, isArray);
|
|
|
|
|
|
|
|
const showModal = useShowModal();
|
|
|
|
|
|
|
|
const select = useCallback(
|
|
|
|
(v?: ProviderInfo) => {
|
|
|
|
showModal(ModalKey, v ?? null);
|
|
|
|
},
|
|
|
|
[showModal]
|
|
|
|
);
|
|
|
|
|
|
|
|
const cards = useMemo(() => {
|
|
|
|
if (providers) {
|
|
|
|
return providers
|
|
|
|
.flatMap((v) => {
|
|
|
|
const item = ProviderList.find((inn) => inn.key === v);
|
|
|
|
if (item) {
|
|
|
|
return item;
|
|
|
|
} else {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map((v, idx) => (
|
|
|
|
<ColCard
|
|
|
|
key={BuildKey(idx, v.name)}
|
|
|
|
header={v.name ?? capitalize(v.key)}
|
|
|
|
subheader={v.description}
|
|
|
|
onClick={() => select(v)}
|
|
|
|
></ColCard>
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}, [providers, select]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Container fluid>
|
|
|
|
<Row>
|
|
|
|
{cards}
|
|
|
|
<ColCard key="add-card" plus onClick={select}></ColCard>
|
|
|
|
</Row>
|
|
|
|
</Container>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const ProviderModal: FunctionComponent = () => {
|
2021-08-16 18:28:18 +00:00
|
|
|
const { payload, closeModal } = useModalInformation<ProviderInfo>(ModalKey);
|
2021-03-25 14:22:43 +00:00
|
|
|
|
|
|
|
const [staged, setChange] = useState<LooseObject>({});
|
|
|
|
|
2021-11-13 03:38:37 +00:00
|
|
|
useEffect(() => {
|
|
|
|
setInfo(payload);
|
|
|
|
}, [payload]);
|
|
|
|
|
2021-08-16 18:28:18 +00:00
|
|
|
const [info, setInfo] = useState<Nullable<ProviderInfo>>(payload);
|
2021-03-25 14:22:43 +00:00
|
|
|
|
2021-08-16 18:28:18 +00:00
|
|
|
useOnModalShow<ProviderInfo>((p) => setInfo(p), ModalKey);
|
2021-03-25 14:22:43 +00:00
|
|
|
|
|
|
|
const providers = useLatest<string[]>(ProviderKey, isArray);
|
|
|
|
|
|
|
|
const updateGlobal = useMultiUpdate();
|
|
|
|
|
|
|
|
const deletePayload = useCallback(() => {
|
|
|
|
if (payload && providers) {
|
|
|
|
const idx = providers.findIndex((v) => v === payload.key);
|
|
|
|
if (idx !== -1) {
|
|
|
|
const newProviders = [...providers];
|
|
|
|
newProviders.splice(idx, 1);
|
|
|
|
updateGlobal({ [ProviderKey]: newProviders });
|
|
|
|
closeModal();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [payload, providers, updateGlobal, closeModal]);
|
|
|
|
|
|
|
|
const addProvider = useCallback(() => {
|
|
|
|
if (info && providers) {
|
|
|
|
const changes = { ...staged };
|
|
|
|
|
|
|
|
// Add this provider if not exist
|
|
|
|
if (providers.find((v) => v === info.key) === undefined) {
|
|
|
|
const newProviders = [...providers, info.key];
|
|
|
|
changes[ProviderKey] = newProviders;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateGlobal(changes);
|
|
|
|
closeModal();
|
|
|
|
}
|
|
|
|
}, [info, providers, staged, closeModal, updateGlobal]);
|
|
|
|
|
|
|
|
const canSave = info !== null;
|
|
|
|
|
|
|
|
const footer = useMemo(
|
|
|
|
() => (
|
|
|
|
<React.Fragment>
|
|
|
|
<Button hidden={!payload} variant="danger" onClick={deletePayload}>
|
|
|
|
Delete
|
|
|
|
</Button>
|
|
|
|
<Button disabled={!canSave} onClick={addProvider}>
|
|
|
|
Save
|
|
|
|
</Button>
|
|
|
|
</React.Fragment>
|
|
|
|
),
|
|
|
|
[canSave, payload, deletePayload, addProvider]
|
|
|
|
);
|
|
|
|
|
|
|
|
const onSelect = useCallback((item: Nullable<ProviderInfo>) => {
|
|
|
|
if (item) {
|
|
|
|
setInfo(item);
|
|
|
|
} else {
|
|
|
|
setInfo({
|
|
|
|
key: "",
|
|
|
|
description: "Unknown Provider",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const options = useMemo<SelectorOption<ProviderInfo>[]>(
|
|
|
|
() =>
|
|
|
|
ProviderList.filter(
|
|
|
|
(v) => providers?.find((p) => p === v.key) === undefined
|
|
|
|
).map((v) => ({
|
|
|
|
label: v.name ?? capitalize(v.key),
|
|
|
|
value: v,
|
|
|
|
})),
|
|
|
|
[providers]
|
|
|
|
);
|
|
|
|
|
|
|
|
const modification = useMemo(() => {
|
|
|
|
if (info === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const defaultKey = info.defaultKey;
|
|
|
|
const override = info.keyNameOverride ?? {};
|
|
|
|
if (defaultKey === undefined) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const itemKey = info.key;
|
|
|
|
|
|
|
|
const elements: JSX.Element[] = [];
|
|
|
|
const checks: JSX.Element[] = [];
|
|
|
|
|
|
|
|
for (const key in defaultKey) {
|
|
|
|
const value = defaultKey[key];
|
|
|
|
let visibleKey = key;
|
|
|
|
|
|
|
|
if (visibleKey in override) {
|
|
|
|
visibleKey = override[visibleKey];
|
|
|
|
} else {
|
|
|
|
visibleKey = capitalize(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isReactText(value)) {
|
|
|
|
elements.push(
|
|
|
|
<Col key={key} xs={12} className="mt-2">
|
|
|
|
<Text
|
|
|
|
password={key === "password"}
|
|
|
|
placeholder={visibleKey}
|
|
|
|
settingKey={`settings-${itemKey}-${key}`}
|
|
|
|
></Text>
|
|
|
|
</Col>
|
|
|
|
);
|
|
|
|
} else if (isBoolean(value)) {
|
|
|
|
checks.push(
|
|
|
|
<Check
|
|
|
|
key={key}
|
|
|
|
inline
|
|
|
|
label={visibleKey}
|
|
|
|
settingKey={`settings-${itemKey}-${key}`}
|
|
|
|
></Check>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Row>
|
|
|
|
{elements}
|
|
|
|
<Col hidden={checks.length === 0} className="mt-2">
|
|
|
|
{checks}
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
);
|
|
|
|
}, [info]);
|
|
|
|
|
2021-04-21 15:07:51 +00:00
|
|
|
const selectorComponents = useMemo<
|
2021-11-03 02:33:24 +00:00
|
|
|
Partial<SelectComponents<ProviderInfo, false, any>>
|
2021-04-21 15:07:51 +00:00
|
|
|
>(
|
|
|
|
() => ({
|
|
|
|
Option: ({ data, ...other }) => {
|
2021-11-03 02:33:24 +00:00
|
|
|
const { label, value } =
|
|
|
|
data as unknown as SelectorOption<ProviderInfo>;
|
2021-04-21 15:07:51 +00:00
|
|
|
return (
|
|
|
|
<components.Option data={data} {...other}>
|
|
|
|
{label}
|
|
|
|
<p className="small m-0 text-muted">{value.description}</p>
|
|
|
|
</components.Option>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
|
2021-04-21 15:14:54 +00:00
|
|
|
const getLabel = useCallback(
|
|
|
|
(v: ProviderInfo) => v.name ?? capitalize(v.key),
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
|
2021-03-25 14:22:43 +00:00
|
|
|
return (
|
|
|
|
<BaseModal title="Provider" footer={footer} modalKey={ModalKey}>
|
|
|
|
<StagedChangesContext.Provider value={[staged, setChange]}>
|
|
|
|
<Container>
|
|
|
|
<Row>
|
|
|
|
<Col>
|
|
|
|
<Selector
|
2021-04-21 15:07:51 +00:00
|
|
|
components={selectorComponents}
|
2021-03-25 14:22:43 +00:00
|
|
|
disabled={payload !== null}
|
|
|
|
options={options}
|
|
|
|
value={info}
|
2021-04-21 15:14:54 +00:00
|
|
|
label={getLabel}
|
2021-03-25 14:22:43 +00:00
|
|
|
onChange={onSelect}
|
|
|
|
></Selector>
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
<Row>
|
|
|
|
<Col className="mb-2">
|
|
|
|
<Message>{info?.description}</Message>
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
{modification}
|
|
|
|
<Row hidden={info?.message === undefined}>
|
|
|
|
<Col>
|
|
|
|
<Message>{info?.message}</Message>
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
</Container>
|
|
|
|
</StagedChangesContext.Provider>
|
|
|
|
</BaseModal>
|
|
|
|
);
|
|
|
|
};
|