mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: problem_main: support copy ids
This commit is contained in:
2 files changed
+18
-21
No files matched your search
@@ -38,17 +38,13 @@ export interface AutoCompleteProps<Item> {
|
|||||||
export interface AutoCompleteHandle<Item> {
|
export interface AutoCompleteHandle<Item> {
|
||||||
getSelectedItems: () => Item[];
|
getSelectedItems: () => Item[];
|
||||||
getSelectedItemKeys: () => string[];
|
getSelectedItemKeys: () => string[];
|
||||||
getSelectedItemsAsString: () => string;
|
|
||||||
setSelectedItems: (items: Item[]) => void;
|
setSelectedItems: (items: Item[]) => void;
|
||||||
getQuery: () => string;
|
getQuery: () => string;
|
||||||
setQuery: (query: string) => void;
|
setQuery: (query: string) => void;
|
||||||
setSelectedKeys: (keys: string[]) => void;
|
setSelectedKeys: (keys: string[]) => void;
|
||||||
triggerQuery: () => any;
|
triggerQuery: () => any;
|
||||||
closeList: () => void;
|
closeList: () => void;
|
||||||
/** returns comma seperated value text */
|
|
||||||
getValue: () => string;
|
getValue: () => string;
|
||||||
/** return value detail */
|
|
||||||
getValueArray: () => Item[];
|
|
||||||
clear: () => void;
|
clear: () => void;
|
||||||
focus: () => void;
|
focus: () => void;
|
||||||
}
|
}
|
||||||
@@ -94,7 +90,6 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
const freeSoloConverter = freeSolo ? props.freeSoloConverter ?? ((i) => i) : ((i) => i);
|
const freeSoloConverter = freeSolo ? props.freeSoloConverter ?? ((i) => i) : ((i) => i);
|
||||||
|
|
||||||
const [focused, setFocused] = useState(false); // is focused
|
const [focused, setFocused] = useState(false); // is focused
|
||||||
const [selected, setSelected] = useState([]); // selected items
|
|
||||||
const [selectedKeys, setSelectedKeys] = useState(props.selectedKeys || []); // keys of selected items
|
const [selectedKeys, setSelectedKeys] = useState(props.selectedKeys || []); // keys of selected items
|
||||||
const [itemList, setItemList] = useState([]); // items list
|
const [itemList, setItemList] = useState([]); // items list
|
||||||
const [currentItem, setCurrentItem] = useState(null); // index of current item (in item list)
|
const [currentItem, setCurrentItem] = useState(null); // index of current item (in item list)
|
||||||
@@ -152,24 +147,17 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
if (multi) {
|
if (multi) {
|
||||||
const idx = selectedKeys.indexOf(key);
|
const idx = selectedKeys.indexOf(key);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
setSelected((s) => {
|
|
||||||
const newSelected = [...s];
|
|
||||||
newSelected.splice(idx, 1);
|
|
||||||
return newSelected;
|
|
||||||
});
|
|
||||||
setSelectedKeys((s) => {
|
setSelectedKeys((s) => {
|
||||||
const newSelectedKeys = [...s];
|
const newSelectedKeys = [...s];
|
||||||
newSelectedKeys.splice(idx, 1);
|
newSelectedKeys.splice(idx, 1);
|
||||||
return newSelectedKeys;
|
return newSelectedKeys;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setSelected((s) => [...s, item]);
|
|
||||||
setSelectedKeys((s) => [...s, key]);
|
setSelectedKeys((s) => [...s, key]);
|
||||||
}
|
}
|
||||||
if (!preserve) inputRef.current.value = '';
|
if (!preserve) inputRef.current.value = '';
|
||||||
inputRef.current.focus();
|
inputRef.current.focus();
|
||||||
} else {
|
} else {
|
||||||
setSelected([item]);
|
|
||||||
setSelectedKeys([key]);
|
setSelectedKeys([key]);
|
||||||
inputRef.current.value = key;
|
inputRef.current.value = key;
|
||||||
}
|
}
|
||||||
@@ -201,7 +189,6 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
if (key === 'Backspace') {
|
if (key === 'Backspace') {
|
||||||
if (target.value.length) return;
|
if (target.value.length) return;
|
||||||
if (selectedKeys.length) {
|
if (selectedKeys.length) {
|
||||||
setSelected((s) => s.slice(0, -1));
|
|
||||||
setSelectedKeys((s) => s.slice(0, -1));
|
setSelectedKeys((s) => s.slice(0, -1));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -229,28 +216,24 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
};
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
getSelectedItems: () => selected,
|
getSelectedItems: () => selectedKeys.map((key) => valueCache[key]),
|
||||||
getSelectedItemKeys: () => [...selectedKeys, inputRef.current?.value].filter((v) => v?.trim().length),
|
getSelectedItemKeys: () => [...selectedKeys, inputRef.current?.value].filter((v) => v?.trim().length),
|
||||||
getSelectedItemsAsString: () => [...selectedKeys, inputRef.current?.value].filter((v) => v?.trim().length).join(','),
|
|
||||||
setSelectedItems: (items) => {
|
setSelectedItems: (items) => {
|
||||||
setSelected(items);
|
|
||||||
setSelectedKeys(items.map((i) => itemKey(i)));
|
setSelectedKeys(items.map((i) => itemKey(i)));
|
||||||
if (!multi && inputRef.current) inputRef.current.value = items.map((i) => itemKey(i)).join(',');
|
if (!multi && inputRef.current) inputRef.current.value = items.map((i) => itemKey(i)).join(',');
|
||||||
},
|
},
|
||||||
|
setSelectedKeys,
|
||||||
getQuery: () => inputRef.current?.value,
|
getQuery: () => inputRef.current?.value,
|
||||||
setQuery: (query) => {
|
setQuery: (query) => {
|
||||||
if (inputRef.current) inputRef.current.value = query;
|
if (inputRef.current) inputRef.current.value = query;
|
||||||
},
|
},
|
||||||
setSelectedKeys: (keys) => setSelectedKeys(keys),
|
|
||||||
triggerQuery: () => queryList(inputRef.current?.value),
|
triggerQuery: () => queryList(inputRef.current?.value),
|
||||||
closeList: () => {
|
closeList: () => {
|
||||||
setItemList([]);
|
setItemList([]);
|
||||||
setCurrentItem(null);
|
setCurrentItem(null);
|
||||||
},
|
},
|
||||||
getValue: () => (multi ? selectedKeys.join(',') : (inputRef.current.value ?? '')),
|
getValue: () => (multi ? selectedKeys.join(',') : (inputRef.current.value ?? '')),
|
||||||
getValueArray: () => (multi ? selected : [inputRef.current?.value].filter((i) => !!i)),
|
|
||||||
clear: () => {
|
clear: () => {
|
||||||
setSelected([]);
|
|
||||||
setSelectedKeys([]);
|
setSelectedKeys([]);
|
||||||
if (inputRef.current) inputRef.current.value = '';
|
if (inputRef.current) inputRef.current.value = '';
|
||||||
},
|
},
|
||||||
@@ -258,7 +241,7 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
setFocused(true);
|
setFocused(true);
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
},
|
},
|
||||||
}), [selected, selectedKeys, inputRef, multi]);
|
}), [selectedKeys, inputRef, multi]);
|
||||||
|
|
||||||
const move = (dragId: string, hoverId: string) => {
|
const move = (dragId: string, hoverId: string) => {
|
||||||
if (dragId === hoverId || !draggable) return;
|
if (dragId === hoverId || !draggable) return;
|
||||||
@@ -309,7 +292,6 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
if (!ids.length) return;
|
if (!ids.length) return;
|
||||||
const fetched = await props.fetchItems(ids);
|
const fetched = await props.fetchItems(ids);
|
||||||
for (const item of fetched) valueCache[itemKey(item)] = item;
|
for (const item of fetched) valueCache[itemKey(item)] = item;
|
||||||
setSelected([...selected, ...fetched]);
|
|
||||||
setSelectedKeys([...selectedKeys, ...fetched.map((val) => itemKey(val))]);
|
setSelectedKeys([...selectedKeys, ...fetched.map((val) => itemKey(val))]);
|
||||||
}}
|
}}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
|
|||||||
@@ -320,6 +320,18 @@ function ProblemSelectionDisplay(props) { // eslint-disable-line
|
|||||||
(window as any).__setPids = (newIds: string[]) => setPids(newIds);
|
(window as any).__setPids = (newIds: string[]) => setPids(newIds);
|
||||||
}, [pids]);
|
}, [pids]);
|
||||||
|
|
||||||
|
const problemSelectAutoCompleteRef = React.useRef(null);
|
||||||
|
const copyIds = React.useCallback(async () => {
|
||||||
|
await navigator.clipboard.writeText(pids.join(','));
|
||||||
|
Notification.success(i18n('Problem ids copied to clipboard!'));
|
||||||
|
problemSelectAutoCompleteRef.current.getSelectedItems();
|
||||||
|
}, [pids]);
|
||||||
|
const copyPids = React.useCallback(async () => {
|
||||||
|
const items = problemSelectAutoCompleteRef.current.getSelectedItems();
|
||||||
|
await navigator.clipboard.writeText(items.map((i) => i.pid || i.docId).join(','));
|
||||||
|
Notification.success(i18n('Problem ids copied to clipboard!'));
|
||||||
|
}, [pids]);
|
||||||
|
|
||||||
const updateCheckboxSelection = React.useCallback(() => {
|
const updateCheckboxSelection = React.useCallback(() => {
|
||||||
for (const i of $('[data-checkbox-group="problem"]:checked')) {
|
for (const i of $('[data-checkbox-group="problem"]:checked')) {
|
||||||
if (!pids.includes(i.closest('tr').dataset.pid)) {
|
if (!pids.includes(i.closest('tr').dataset.pid)) {
|
||||||
@@ -357,6 +369,7 @@ function ProblemSelectionDisplay(props) { // eslint-disable-line
|
|||||||
<div className="columns">
|
<div className="columns">
|
||||||
<ProblemSelectAutoComplete
|
<ProblemSelectAutoComplete
|
||||||
multi
|
multi
|
||||||
|
ref={problemSelectAutoCompleteRef}
|
||||||
onChange={(v) => setPids(v.split(',').filter((i) => i.trim()))}
|
onChange={(v) => setPids(v.split(',').filter((i) => i.trim()))}
|
||||||
selectedKeys={pids}
|
selectedKeys={pids}
|
||||||
/>
|
/>
|
||||||
@@ -367,6 +380,8 @@ function ProblemSelectionDisplay(props) { // eslint-disable-line
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="columns clearfix">
|
<div className="columns clearfix">
|
||||||
<div className="float-right dialog__action">
|
<div className="float-right dialog__action">
|
||||||
|
<button className="rounded button" onClick={copyIds}>{i18n('Copy IDs')}</button>{' '}
|
||||||
|
<button className="rounded button" onClick={copyPids}>{i18n('Copy pids')}</button>{' '}
|
||||||
<button className="rounded button" onClick={() => setPids([])}>{i18n('Clear')}</button>{' '}
|
<button className="rounded button" onClick={() => setPids([])}>{i18n('Clear')}</button>{' '}
|
||||||
<button className="primary rounded button" onClick={() => setDialogOpen(false)}>{i18n('Ok')}</button>
|
<button className="primary rounded button" onClick={() => setDialogOpen(false)}>{i18n('Ok')}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user