feat(Map): Rework design of checkboxes in Signatures settings dialog. Rework design of checkboxes in Routes settings dialog. Now signature will deleteing by Delete hotkey was Backspace. Fixed size of group column in signatures list. Instead Updated column will be Added, updated may be turn on in settings. (#76)

Co-authored-by: achichenkov <aleksei.chichenkov@telleqt.ai>
This commit is contained in:
Aleksei Chichenkov
2024-11-26 22:02:30 +03:00
committed by GitHub
parent c1ecd3690e
commit ef6b45d7a1
7 changed files with 81 additions and 84 deletions

View File

@@ -1,12 +1,11 @@
import { Dialog } from 'primereact/dialog'; import { Dialog } from 'primereact/dialog';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { WdCheckbox } from '@/hooks/Mapper/components/ui-kit';
import { import {
RoutesType, RoutesType,
useRouteProvider, useRouteProvider,
} from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx'; } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
import { CheckboxChangeEvent } from 'primereact/checkbox'; import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
interface RoutesSettingsDialog { interface RoutesSettingsDialog {
visible: boolean; visible: boolean;
@@ -38,8 +37,8 @@ export const RoutesSettingsDialog = ({ visible, setVisible }: RoutesSettingsDial
currentData.current = data; currentData.current = data;
const handleChangeEvent = useCallback( const handleChangeEvent = useCallback(
(propName: keyof RoutesType) => (event: CheckboxChangeEvent) => { (propName: keyof RoutesType) => (event: boolean) => {
optionsRef.current = { ...optionsRef.current, [propName]: event.checked }; optionsRef.current = { ...optionsRef.current, [propName]: event };
updateKey(x => x + 1); updateKey(x => x + 1);
}, },
[], [],
@@ -71,14 +70,14 @@ export const RoutesSettingsDialog = ({ visible, setVisible }: RoutesSettingsDial
setVisible(false); setVisible(false);
}} }}
> >
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3 p-2.5">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2 mb-2">
{checkboxes.map(({ label, propName }) => ( {checkboxes.map(({ label, propName }) => (
<WdCheckbox <PrettySwitchbox
key={propName} key={propName}
label={label} label={label}
value={optionsRef.current[propName]} checked={optionsRef.current[propName]}
onChange={handleChangeEvent(propName)} setChecked={handleChangeEvent(propName)}
/> />
))} ))}
</div> </div>

View File

@@ -1,9 +1,9 @@
import { Dialog } from 'primereact/dialog'; import { Dialog } from 'primereact/dialog';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { Checkbox } from 'primereact/checkbox';
import { TabPanel, TabView } from 'primereact/tabview'; import { TabPanel, TabView } from 'primereact/tabview';
import styles from './SystemSignatureSettingsDialog.module.scss'; import styles from './SystemSignatureSettingsDialog.module.scss';
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
export type Setting = { key: string; name: string; value: boolean; isFilter?: boolean }; export type Setting = { key: string; name: string; value: boolean; isFilter?: boolean };
@@ -41,8 +41,8 @@ export const SystemSignatureSettingsDialog = ({
}, [onSave, settings]); }, [onSave, settings]);
return ( return (
<Dialog header="System Signatures Settings" visible={true} onHide={onCancel} className="w-full max-w-lg"> <Dialog header="System Signatures Settings" visible={true} onHide={onCancel} className="w-full max-w-lg h-[500px]">
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3 justify-between h-full">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className={styles.verticalTabsContainer}> <div className={styles.verticalTabsContainer}>
<TabView <TabView
@@ -54,16 +54,12 @@ export const SystemSignatureSettingsDialog = ({
<div className="w-full h-full flex flex-col gap-1"> <div className="w-full h-full flex flex-col gap-1">
{filterSettings.map(setting => { {filterSettings.map(setting => {
return ( return (
<div key={setting.key} className="flex items-center"> <PrettySwitchbox
<Checkbox key={setting.key}
inputId={setting.key} label={setting.name}
checked={setting.value} checked={setting.value}
onChange={() => handleSettingsChange(setting.key)} setChecked={() => handleSettingsChange(setting.key)}
/> />
<label htmlFor={setting.key} className="ml-2">
{setting.name}
</label>
</div>
); );
})} })}
</div> </div>
@@ -72,16 +68,12 @@ export const SystemSignatureSettingsDialog = ({
<div className="w-full h-full flex flex-col gap-1"> <div className="w-full h-full flex flex-col gap-1">
{userSettings.map(setting => { {userSettings.map(setting => {
return ( return (
<div key={setting.key} className="flex items-center"> <PrettySwitchbox
<Checkbox key={setting.key}
inputId={setting.key} label={setting.name}
checked={setting.value} checked={setting.value}
onChange={() => handleSettingsChange(setting.key)} setChecked={() => handleSettingsChange(setting.key)}
/> />
<label htmlFor={setting.key} className="ml-2">
{setting.name}
</label>
</div>
); );
})} })}
</div> </div>

View File

@@ -22,10 +22,10 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v4_1'; const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v4_1';
export const SHOW_DESCRIPTION_COLUMN_SETTING = 'show_description_column_setting'; export const SHOW_DESCRIPTION_COLUMN_SETTING = 'show_description_column_setting';
export const SHOW_INSERTED_COLUMN_SETTING = 'show_inserted_column_setting'; export const SHOW_UPDATED_COLUMN_SETTING = 'SHOW_UPDATED_COLUMN_SETTING';
const settings: Setting[] = [ const settings: Setting[] = [
{ key: SHOW_INSERTED_COLUMN_SETTING, name: 'Show Inserted Column', value: false, isFilter: false }, { key: SHOW_UPDATED_COLUMN_SETTING, name: 'Show Updated Column', value: false, isFilter: false },
{ key: SHOW_DESCRIPTION_COLUMN_SETTING, name: 'Show Description Column', value: false, isFilter: false }, { key: SHOW_DESCRIPTION_COLUMN_SETTING, name: 'Show Description Column', value: false, isFilter: false },
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true, isFilter: true }, { key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true, isFilter: true },
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true, isFilter: true }, { key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true, isFilter: true },

View File

@@ -1,5 +1,4 @@
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useClipboard } from '@/hooks/Mapper/hooks/useClipboard';
import { parseSignatures } from '@/hooks/Mapper/helpers'; import { parseSignatures } from '@/hooks/Mapper/helpers';
import { Commands, OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts'; import { Commands, OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
import { WdTooltip, WdTooltipHandlers } from '@/hooks/Mapper/components/ui-kit'; import { WdTooltip, WdTooltipHandlers } from '@/hooks/Mapper/components/ui-kit';
@@ -22,10 +21,10 @@ import {
getRowColorByTimeLeft, getRowColorByTimeLeft,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers'; } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers';
import { import {
renderAddedTimeLeft,
renderDescription, renderDescription,
renderIcon, renderIcon,
renderInfoColumn, renderInfoColumn,
renderInsertedTimeLeft,
renderUpdatedTimeLeft, renderUpdatedTimeLeft,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders'; } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
import useLocalStorageState from 'use-local-storage-state'; import useLocalStorageState from 'use-local-storage-state';
@@ -36,7 +35,7 @@ import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrap
import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog'; import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
import { import {
SHOW_DESCRIPTION_COLUMN_SETTING, SHOW_DESCRIPTION_COLUMN_SETTING,
SHOW_INSERTED_COLUMN_SETTING, SHOW_UPDATED_COLUMN_SETTING,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures'; } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures';
type SystemSignaturesSortSettings = { type SystemSignaturesSortSettings = {
sortField: string; sortField: string;
@@ -44,7 +43,7 @@ type SystemSignaturesSortSettings = {
}; };
const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = { const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = {
sortField: 'updated_at', sortField: 'inserted_at',
sortOrder: -1, sortOrder: -1,
}; };
@@ -80,11 +79,11 @@ export const SystemSignaturesContent = ({
const tableRef = useRef<HTMLDivElement>(null); const tableRef = useRef<HTMLDivElement>(null);
const compact = useMaxWidth(tableRef, 260); const compact = useMaxWidth(tableRef, 260);
const medium = useMaxWidth(tableRef, 380); const medium = useMaxWidth(tableRef, 380);
const refData = useRef({ selectable });
refData.current = { selectable };
const tooltipRef = useRef<WdTooltipHandlers>(null); const tooltipRef = useRef<WdTooltipHandlers>(null);
const { clipboardContent } = useClipboard();
const handleResize = useCallback(() => { const handleResize = useCallback(() => {
if (tableRef.current) { if (tableRef.current) {
const tableWidth = tableRef.current.offsetWidth; const tableWidth = tableRef.current.offsetWidth;
@@ -100,10 +99,7 @@ export const SystemSignaturesContent = ({
[settings], [settings],
); );
const showInsertedColumn = useMemo( const showUpdatedColumn = useMemo(() => settings.find(s => s.key === SHOW_UPDATED_COLUMN_SETTING)?.value, [settings]);
() => settings.find(s => s.key === SHOW_INSERTED_COLUMN_SETTING)?.value,
[settings],
);
const filteredSignatures = useMemo(() => { const filteredSignatures = useMemo(() => {
return signatures return signatures
@@ -160,19 +156,26 @@ export const SystemSignaturesContent = ({
[outCommand, systemId], [outCommand, systemId],
); );
const handleDeleteSelected = useCallback(async () => { const handleDeleteSelected = useCallback(
async (e: KeyboardEvent) => {
if (selectable) { if (selectable) {
return; return;
} }
if (selectedSignatures.length === 0) { if (selectedSignatures.length === 0) {
return; return;
} }
e.preventDefault();
e.stopPropagation();
const selectedSignaturesEveIds = selectedSignatures.map(x => x.eve_id); const selectedSignaturesEveIds = selectedSignatures.map(x => x.eve_id);
await handleUpdateSignatures( await handleUpdateSignatures(
signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)), signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)),
false, false,
); );
}, [handleUpdateSignatures, selectable, signatures, selectedSignatures]); },
[handleUpdateSignatures, selectable, signatures, selectedSignatures],
);
const handleSelectAll = useCallback(() => { const handleSelectAll = useCallback(() => {
setSelectedSignatures(signatures); setSelectedSignatures(signatures);
@@ -201,12 +204,9 @@ export const SystemSignaturesContent = ({
[onSelect, selectable], [onSelect, selectable],
); );
useHotkey(true, ['a'], handleSelectAll); const handlePaste = async () => {
const clipboardContent = await navigator.clipboard.readText();
useHotkey(false, ['Backspace'], handleDeleteSelected); if (refData.current.selectable) {
useEffect(() => {
if (selectable) {
return; return;
} }
@@ -227,7 +227,12 @@ export const SystemSignaturesContent = ({
setParsedSignatures(newSignatures); setParsedSignatures(newSignatures);
setAskUser(true); setAskUser(true);
} }
}, [clipboardContent, selectable]); };
useHotkey(true, ['a'], handleSelectAll);
useHotkey(true, ['v'], handlePaste);
useHotkey(false, ['Delete'], handleDeleteSelected);
useEffect(() => { useEffect(() => {
if (!systemId) { if (!systemId) {
@@ -330,7 +335,7 @@ export const SystemSignaturesContent = ({
return clsx(classes.TableRowCompact, 'bg-amber-500/50 hover:bg-amber-500/70 transition duration-200'); return clsx(classes.TableRowCompact, 'bg-amber-500/50 hover:bg-amber-500/70 transition duration-200');
} }
const dateClass = getRowColorByTimeLeft(row.updated_at ? new Date(row.updated_at) : undefined); const dateClass = getRowColorByTimeLeft(row.inserted_at ? new Date(row.inserted_at) : undefined);
if (!dateClass) { if (!dateClass) {
return clsx(classes.TableRowCompact, 'hover:bg-purple-400/20 transition duration-200'); return clsx(classes.TableRowCompact, 'hover:bg-purple-400/20 transition duration-200');
} }
@@ -357,6 +362,7 @@ export const SystemSignaturesContent = ({
header="Group" header="Group"
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap" bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
hidden={compact} hidden={compact}
style={{ maxWidth: 110, minWidth: 110, width: 110 }}
sortable sortable
></Column> ></Column>
<Column <Column
@@ -378,17 +384,16 @@ export const SystemSignaturesContent = ({
></Column> ></Column>
)} )}
{showInsertedColumn && (
<Column <Column
field="inserted_at" field="inserted_at"
header="Inserted" header="Added"
dataType="date" dataType="date"
bodyClassName="w-[70px] text-ellipsis overflow-hidden whitespace-nowrap" bodyClassName="w-[70px] text-ellipsis overflow-hidden whitespace-nowrap"
body={renderInsertedTimeLeft} body={renderAddedTimeLeft}
sortable sortable
></Column> ></Column>
)}
{showUpdatedColumn && (
<Column <Column
field="updated_at" field="updated_at"
header="Updated" header="Updated"
@@ -397,6 +402,7 @@ export const SystemSignaturesContent = ({
body={renderUpdatedTimeLeft} body={renderUpdatedTimeLeft}
sortable sortable
></Column> ></Column>
)}
{!selectable && ( {!selectable && (
<Column <Column

View File

@@ -1,7 +1,7 @@
export * from './renderIcon'; export * from './renderIcon';
export * from './renderDescription'; export * from './renderDescription';
export * from './renderName'; export * from './renderName';
export * from './renderInsertedTimeLeft'; export * from './renderAddedTimeLeft';
export * from './renderUpdatedTimeLeft'; export * from './renderUpdatedTimeLeft';
export * from './renderLinkedSystem'; export * from './renderLinkedSystem';
export * from './renderInfoColumn'; export * from './renderInfoColumn';

View File

@@ -1,7 +1,7 @@
import { SystemSignature } from '@/hooks/Mapper/types'; import { SystemSignature } from '@/hooks/Mapper/types';
import { TimeLeft } from '@/hooks/Mapper/components/ui-kit'; import { TimeLeft } from '@/hooks/Mapper/components/ui-kit';
export const renderInsertedTimeLeft = (row: SystemSignature) => { export const renderAddedTimeLeft = (row: SystemSignature) => {
return ( return (
<div className="flex w-full items-center"> <div className="flex w-full items-center">
<TimeLeft cDate={row.inserted_at ? new Date(row.inserted_at) : undefined} /> <TimeLeft cDate={row.inserted_at ? new Date(row.inserted_at) : undefined} />

View File

@@ -1,6 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
export const useHotkey = (isMetaKey: boolean, hotkeys: string[], callback: () => void) => { export const useHotkey = (isMetaKey: boolean, hotkeys: string[], callback: (e: KeyboardEvent) => void) => {
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
if ((!isMetaKey || event.ctrlKey || event.metaKey) && hotkeys.includes(event.key)) { if ((!isMetaKey || event.ctrlKey || event.metaKey) && hotkeys.includes(event.key)) {
@@ -8,14 +8,14 @@ export const useHotkey = (isMetaKey: boolean, hotkeys: string[], callback: () =>
return; return;
} }
event.preventDefault(); event.preventDefault();
callback(); callback(event);
} }
}; };
window.addEventListener('keydown', handleKeyDown); window.addEventListener('keydown', handleKeyDown, { capture: true });
return () => { return () => {
window.removeEventListener('keydown', handleKeyDown); window.removeEventListener('keydown', handleKeyDown, { capture: true });
}; };
}, [isMetaKey, hotkeys, callback]); }, [isMetaKey, hotkeys, callback]);
}; };