You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bazarr/frontend/src/pages/Settings/components/pathMapper.tsx

168 lines
4.0 KiB

import { faArrowCircleRight, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ActionButton, FileBrowser, SimpleTable } from "components";
import { capitalize, isArray, isBoolean } from "lodash";
import React, { FunctionComponent, useCallback, useMemo } from "react";
import { Button } from "react-bootstrap";
import { Column, TableUpdater } from "react-table";
import {
moviesEnabledKey,
pathMappingsKey,
pathMappingsMovieKey,
seriesEnabledKey,
} from "../keys";
import { Message } from "./forms";
import { useExtract, useLatest, useSingleUpdate } from "./hooks";
type SupportType = "sonarr" | "radarr";
function getSupportKey(type: SupportType) {
if (type === "sonarr") {
return pathMappingsKey;
} else {
return pathMappingsMovieKey;
}
}
function getEnabledKey(type: SupportType) {
if (type === "sonarr") {
return seriesEnabledKey;
} else {
return moviesEnabledKey;
}
}
interface PathMappingItem {
from: string;
to: string;
}
interface TableProps {
type: SupportType;
}
export const PathMappingTable: FunctionComponent<TableProps> = ({ type }) => {
const key = getSupportKey(type);
const items = useLatest<[string, string][]>(key, isArray);
const enabledKey = getEnabledKey(type);
const enabled = useExtract<boolean>(enabledKey, isBoolean);
const update = useSingleUpdate();
const updateRow = useCallback(
(newItems: PathMappingItem[]) => {
update(
newItems.map((v) => [v.from, v.to]),
key
);
},
[key, update]
);
const addRow = useCallback(() => {
if (items) {
const newItems = [...items, ["", ""]];
update(newItems, key);
}
}, [items, key, update]);
const data = useMemo<PathMappingItem[]>(
() => items?.map((v) => ({ from: v[0], to: v[1] })) ?? [],
[items]
);
const updateCell = useCallback<TableUpdater<PathMappingItem>>(
(row, item?: PathMappingItem) => {
const newItems = [...data];
if (item) {
newItems[row.index] = item;
} else {
newItems.splice(row.index, 1);
}
updateRow(newItems);
},
[data, updateRow]
);
const columns = useMemo<Column<PathMappingItem>[]>(
() => [
{
Header: capitalize(type),
accessor: "from",
Cell: ({ value, row, update }) => (
<FileBrowser
drop="up"
type={type}
defaultValue={value}
onChange={(path) => {
const newItem = { ...row.original };
newItem.from = path;
update && update(row, newItem);
}}
></FileBrowser>
),
},
{
id: "arrow",
className: "text-center",
Cell: () => (
<FontAwesomeIcon icon={faArrowCircleRight}></FontAwesomeIcon>
),
},
{
Header: "Bazarr",
accessor: "to",
Cell: ({ value, row, update }) => (
<FileBrowser
drop="up"
defaultValue={value}
type="bazarr"
onChange={(path) => {
const newItem = { ...row.original };
newItem.to = path;
update && update(row, newItem);
}}
></FileBrowser>
),
},
{
id: "action",
accessor: "to",
Cell: ({ row, update }) => (
<ActionButton
icon={faTrash}
onClick={() => {
update && update(row);
}}
></ActionButton>
),
},
],
[type]
);
if (enabled) {
return (
<React.Fragment>
<SimpleTable
emptyText="No Mapping"
responsive={false}
columns={columns}
data={data}
update={updateCell}
></SimpleTable>
<Button block variant="light" onClick={addRow}>
Add
</Button>
</React.Fragment>
);
} else {
return (
<Message>
Path Mappings will be available after staged changes are saved
</Message>
);
}
};