2022-11-10 18:21:32 +11:00
|
|
|
import { useEffect, useState } from "react";
|
2022-05-24 20:34:28 +10:00
|
|
|
import { useDebouncedCallback } from "use-debounce";
|
|
|
|
|
import { get } from "lodash-es";
|
|
|
|
|
import { useAtom } from "jotai";
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
Button,
|
|
|
|
|
Checkbox,
|
|
|
|
|
Grid,
|
|
|
|
|
InputAdornment,
|
|
|
|
|
List,
|
|
|
|
|
ListItemIcon,
|
|
|
|
|
ListItemText,
|
|
|
|
|
MenuItem,
|
|
|
|
|
TextField,
|
|
|
|
|
Typography,
|
|
|
|
|
Radio,
|
|
|
|
|
} from "@mui/material";
|
|
|
|
|
import SearchIcon from "@mui/icons-material/Search";
|
|
|
|
|
|
|
|
|
|
import { IConnectorSelectProps } from ".";
|
|
|
|
|
import Loading from "@src/components/Loading";
|
|
|
|
|
import { getLabel } from "@src/components/fields/Connector/utils";
|
|
|
|
|
import { useSnackbar } from "notistack";
|
2022-07-18 14:40:46 +10:00
|
|
|
import { projectScope, rowyRunAtom } from "@src/atoms/projectScope";
|
2022-05-24 20:34:28 +10:00
|
|
|
import { tableScope, tableSettingsAtom } from "@src/atoms/tableScope";
|
2022-06-02 00:50:18 +10:00
|
|
|
import { getTableSchemaPath } from "@src/utils/table";
|
2022-05-24 20:34:28 +10:00
|
|
|
|
|
|
|
|
export interface IPopupContentsProps
|
|
|
|
|
extends Omit<IConnectorSelectProps, "className" | "TextFieldProps"> {}
|
|
|
|
|
|
|
|
|
|
// TODO: Implement infinite scroll here
|
|
|
|
|
export default function PopupContents({
|
|
|
|
|
value = [],
|
|
|
|
|
onChange,
|
|
|
|
|
column,
|
2022-11-10 18:21:32 +11:00
|
|
|
_rowy_ref,
|
2022-05-24 20:34:28 +10:00
|
|
|
}: IPopupContentsProps) {
|
2022-07-18 14:40:46 +10:00
|
|
|
const [rowyRun] = useAtom(rowyRunAtom, projectScope);
|
2022-05-24 20:34:28 +10:00
|
|
|
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
|
|
|
|
|
|
|
|
|
|
const { enqueueSnackbar } = useSnackbar();
|
|
|
|
|
// const url = config.url ;
|
|
|
|
|
const { config } = column;
|
|
|
|
|
const elementId = config.elementId;
|
|
|
|
|
const multiple = Boolean(config.multiple);
|
|
|
|
|
|
|
|
|
|
// Webservice search query
|
|
|
|
|
const [query, setQuery] = useState("");
|
|
|
|
|
// Webservice response
|
|
|
|
|
const [response, setResponse] = useState<any | null>(null);
|
|
|
|
|
const [hits, setHits] = useState<any[]>([]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
console.log(response);
|
|
|
|
|
if (response?.success === false) {
|
|
|
|
|
enqueueSnackbar(response.message, { variant: "error" });
|
|
|
|
|
} else if (Array.isArray(response?.hits)) {
|
|
|
|
|
setHits(response.hits);
|
|
|
|
|
} else {
|
|
|
|
|
setHits([]);
|
|
|
|
|
//enqueueSnackbar("response is not any array", { variant: "error" });
|
|
|
|
|
}
|
|
|
|
|
}, [response]);
|
|
|
|
|
const search = useDebouncedCallback(
|
|
|
|
|
async (query: string) => {
|
|
|
|
|
const resp = await rowyRun!({
|
|
|
|
|
route: { method: "POST", path: "/connector" },
|
|
|
|
|
body: {
|
|
|
|
|
columnKey: column.key,
|
|
|
|
|
query: query,
|
2022-06-02 00:50:18 +10:00
|
|
|
schemaDocPath: getTableSchemaPath(tableSettings),
|
2022-11-10 18:21:32 +11:00
|
|
|
rowDocPath: _rowy_ref.path,
|
2022-05-24 20:34:28 +10:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
setResponse(resp);
|
|
|
|
|
},
|
|
|
|
|
1000,
|
|
|
|
|
{ leading: true }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
search(query);
|
|
|
|
|
}, [query]);
|
|
|
|
|
|
|
|
|
|
if (!response) return <Loading />;
|
|
|
|
|
|
|
|
|
|
const select = (hit: any) => () => {
|
|
|
|
|
if (multiple) onChange([...value, hit]);
|
|
|
|
|
else onChange([hit]);
|
|
|
|
|
};
|
|
|
|
|
const deselect = (hit: any) => () => {
|
|
|
|
|
if (multiple)
|
|
|
|
|
onChange(value.filter((v) => v[elementId] !== hit[elementId]));
|
|
|
|
|
else onChange([]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const selectedValues = value?.map((item) => get(item, elementId));
|
|
|
|
|
|
|
|
|
|
const clearSelection = () => onChange([]);
|
|
|
|
|
|
|
|
|
|
return (
|
2022-11-10 18:21:32 +11:00
|
|
|
<Grid container direction="column" sx={{ p: 1, height: "100%" }}>
|
|
|
|
|
<Grid item>
|
2022-05-24 20:34:28 +10:00
|
|
|
<TextField
|
|
|
|
|
value={query}
|
2022-11-10 18:21:32 +11:00
|
|
|
type="search"
|
2022-05-24 20:34:28 +10:00
|
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
|
|
|
fullWidth
|
|
|
|
|
variant="filled"
|
|
|
|
|
label="Search items"
|
2022-11-10 18:21:32 +11:00
|
|
|
hiddenLabel
|
|
|
|
|
placeholder="Search items"
|
2022-05-24 20:34:28 +10:00
|
|
|
InputProps={{
|
2022-11-10 18:21:32 +11:00
|
|
|
startAdornment: (
|
|
|
|
|
<InputAdornment position="start">
|
2022-05-24 20:34:28 +10:00
|
|
|
<SearchIcon />
|
|
|
|
|
</InputAdornment>
|
|
|
|
|
),
|
|
|
|
|
}}
|
2022-11-10 18:21:32 +11:00
|
|
|
InputLabelProps={{ className: "visually-hidden" }}
|
2022-05-24 20:34:28 +10:00
|
|
|
onClick={(e) => e.stopPropagation()}
|
|
|
|
|
onKeyDown={(e) => e.stopPropagation()}
|
|
|
|
|
/>
|
|
|
|
|
</Grid>
|
|
|
|
|
|
2022-11-10 18:21:32 +11:00
|
|
|
<Grid item xs>
|
|
|
|
|
<List sx={{ overflowY: "auto" }}>
|
2022-05-24 20:34:28 +10:00
|
|
|
{hits.map((hit) => {
|
|
|
|
|
const isSelected = selectedValues.some((v) => v === hit[elementId]);
|
|
|
|
|
return (
|
2022-11-10 18:21:32 +11:00
|
|
|
<MenuItem
|
|
|
|
|
key={get(hit, elementId)}
|
|
|
|
|
onClick={isSelected ? deselect(hit) : select(hit)}
|
|
|
|
|
disabled={!isSelected && multiple && value.length >= config.max}
|
|
|
|
|
disableGutters
|
|
|
|
|
style={{ margin: 0, width: "100%" }}
|
|
|
|
|
>
|
|
|
|
|
<ListItemIcon>
|
|
|
|
|
{multiple ? (
|
|
|
|
|
<Checkbox
|
|
|
|
|
edge="start"
|
|
|
|
|
checked={isSelected}
|
|
|
|
|
tabIndex={-1}
|
|
|
|
|
color="secondary"
|
|
|
|
|
disableRipple
|
|
|
|
|
inputProps={{
|
|
|
|
|
"aria-labelledby": `label-${get(hit, elementId)}`,
|
|
|
|
|
}}
|
|
|
|
|
sx={{ py: 0 }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<Radio
|
|
|
|
|
edge="start"
|
|
|
|
|
checked={isSelected}
|
|
|
|
|
tabIndex={-1}
|
|
|
|
|
color="secondary"
|
|
|
|
|
disableRipple
|
|
|
|
|
inputProps={{
|
|
|
|
|
"aria-labelledby": `label-${get(hit, elementId)}`,
|
|
|
|
|
}}
|
|
|
|
|
sx={{ py: 0 }}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</ListItemIcon>
|
|
|
|
|
<ListItemText
|
|
|
|
|
id={`label-${get(hit, elementId)}`}
|
|
|
|
|
primary={getLabel(config, hit)}
|
|
|
|
|
/>
|
|
|
|
|
</MenuItem>
|
2022-05-24 20:34:28 +10:00
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</List>
|
|
|
|
|
</Grid>
|
|
|
|
|
|
|
|
|
|
{multiple && (
|
2022-11-10 18:21:32 +11:00
|
|
|
<Grid item>
|
2022-05-24 20:34:28 +10:00
|
|
|
<Grid
|
|
|
|
|
container
|
|
|
|
|
direction="row"
|
|
|
|
|
justifyContent="space-between"
|
|
|
|
|
alignItems="center"
|
|
|
|
|
>
|
2022-11-10 18:21:32 +11:00
|
|
|
<Typography variant="button" color="textSecondary" sx={{ ml: 1 }}>
|
2022-05-24 20:34:28 +10:00
|
|
|
{value?.length} of {hits?.length}
|
|
|
|
|
</Typography>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
disabled={!value || value.length === 0}
|
|
|
|
|
onClick={clearSelection}
|
|
|
|
|
color="primary"
|
2022-11-10 18:21:32 +11:00
|
|
|
variant="text"
|
2022-05-24 20:34:28 +10:00
|
|
|
>
|
2022-11-10 18:21:32 +11:00
|
|
|
Clear
|
2022-05-24 20:34:28 +10:00
|
|
|
</Button>
|
|
|
|
|
</Grid>
|
|
|
|
|
</Grid>
|
|
|
|
|
)}
|
|
|
|
|
</Grid>
|
|
|
|
|
);
|
|
|
|
|
}
|