bazarr/frontend/src/Settings/Languages/table.tsx

218 lines
5.2 KiB
TypeScript
Raw Normal View History

2021-03-25 14:22:43 +00:00
import { faTrash, faWrench } from "@fortawesome/free-solid-svg-icons";
import { cloneDeep } from "lodash";
2021-03-25 14:22:43 +00:00
import React, {
FunctionComponent,
useCallback,
useMemo,
useState,
} from "react";
import { Badge, Button, ButtonGroup } from "react-bootstrap";
import { Column, TableUpdater } from "react-table";
import { useEnabledLanguagesContext, useProfilesContext } from ".";
2021-03-25 14:22:43 +00:00
import { ActionButton, SimpleTable, useShowModal } from "../../components";
import { useSingleUpdate } from "../components";
import { languageProfileKey } from "../keys";
import Modal from "./modal";
import { anyCutoff } from "./options";
const Table: FunctionComponent = () => {
const originalProfiles = useProfilesContext();
2021-03-25 14:22:43 +00:00
const languages = useEnabledLanguagesContext();
const [profiles, setProfiles] = useState(() => cloneDeep(originalProfiles));
2021-03-25 14:22:43 +00:00
const nextProfileId = useMemo(
() =>
1 +
profiles.reduce<number>((val, prof) => Math.max(prof.profileId, val), 0),
[profiles]
);
const update = useSingleUpdate();
const showModal = useShowModal();
const submitProfiles = useCallback(
(list: Language.Profile[]) => {
2021-03-25 14:22:43 +00:00
update(list, languageProfileKey);
setProfiles(list);
},
[update]
);
const updateProfile = useCallback(
(profile: Language.Profile) => {
2021-03-25 14:22:43 +00:00
const list = [...profiles];
const idx = list.findIndex((v) => v.profileId === profile.profileId);
if (idx !== -1) {
list[idx] = profile;
} else {
list.push(profile);
}
submitProfiles(list);
},
[profiles, submitProfiles]
);
const updateRow = useCallback<TableUpdater<Language.Profile>>(
(row, item?: Language.Profile) => {
2021-03-25 14:22:43 +00:00
if (item) {
showModal("profile", cloneDeep(item));
2021-03-25 14:22:43 +00:00
} else {
const list = [...profiles];
list.splice(row.index, 1);
submitProfiles(list);
}
},
[submitProfiles, showModal, profiles]
);
const columns = useMemo<Column<Language.Profile>[]>(
2021-03-25 14:22:43 +00:00
() => [
{
Header: "Name",
accessor: "name",
},
{
Header: "Languages",
accessor: "items",
Cell: (row) => {
const items = row.value;
const cutoff = row.row.original.cutoff;
return items.map((v) => {
const isCutoff = v.id === cutoff || cutoff === anyCutoff;
return (
<ItemBadge
key={v.id}
cutoff={isCutoff}
className="mx-1"
item={v}
></ItemBadge>
);
});
},
},
{
Header: "Must contain",
accessor: "mustContain",
Cell: (row) => {
const items = row.value;
if (!items) {
return false;
}
return items.map((v) => {
return (
<Badge className={"mx-1"} variant={"secondary"}>
{v}
</Badge>
);
});
},
},
{
Header: "Must not contain",
accessor: "mustNotContain",
Cell: (row) => {
const items = row.value;
if (!items) {
return false;
}
return items.map((v) => {
return (
<Badge className={"mx-1"} variant={"secondary"}>
{v}
</Badge>
);
});
},
},
2021-03-25 14:22:43 +00:00
{
accessor: "profileId",
Cell: ({ row, update }) => {
2021-03-25 14:22:43 +00:00
const profile = row.original;
return (
<ButtonGroup>
<ActionButton
icon={faWrench}
onClick={() => {
update && update(row, profile);
2021-03-25 14:22:43 +00:00
}}
></ActionButton>
<ActionButton
icon={faTrash}
onClick={() => update && update(row)}
2021-03-25 14:22:43 +00:00
></ActionButton>
</ButtonGroup>
);
},
},
],
[]
);
const canAdd = languages.length !== 0;
2021-03-25 14:22:43 +00:00
return (
<React.Fragment>
<SimpleTable
columns={columns}
data={profiles}
update={updateRow}
2021-03-25 14:22:43 +00:00
></SimpleTable>
<Button
block
disabled={!canAdd}
2021-03-25 14:22:43 +00:00
variant="light"
onClick={() => {
const profile = {
profileId: nextProfileId,
name: "",
items: [],
cutoff: null,
};
showModal("profile", profile);
}}
>
{canAdd ? "Add New Profile" : "No Enabled Languages"}
2021-03-25 14:22:43 +00:00
</Button>
<Modal update={updateProfile} modalKey="profile"></Modal>
</React.Fragment>
);
};
interface ItemProps {
className?: string;
item: Language.ProfileItem;
2021-03-25 14:22:43 +00:00
cutoff: boolean;
}
const ItemBadge: FunctionComponent<ItemProps> = ({
cutoff,
item,
className,
}) => {
const text = useMemo(() => {
let result = item.language;
if (item.hi === "True") {
result += ":HI";
} else if (item.forced === "True") {
result += ":Forced";
}
return result;
}, [item.hi, item.forced, item.language]);
return (
<Badge
className={className}
title={cutoff ? "Ignore others if this one is available" : undefined}
variant={cutoff ? "primary" : "secondary"}
>
{text}
</Badge>
);
};
export default Table;