Skip to content

Commit

Permalink
#847: Add 'Select All' option for duplicate check UI
Browse files Browse the repository at this point in the history
  • Loading branch information
aschonfeld committed Apr 30, 2024
1 parent 93872aa commit 20d9c1c
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
1 change: 1 addition & 0 deletions dtale/duplicate_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ def __init__(self, data_id, cfg):

def check(self, df):
subset, keep = (self.cfg.get(p) for p in ["subset", "keep"])
subset = None if not len(subset or []) else subset
dupe_args = {"keep": False if keep == "none" else keep}
duplicates = df.duplicated(subset, **dupe_args)
removed = int(duplicates.sum())
Expand Down
9 changes: 8 additions & 1 deletion dtale/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -7893,9 +7893,16 @@ a.text-dark:focus, a.text-dark:hover {
border-collapse: separate;
height: calc(1.91562rem + 2px);
outline: none;
overflow: hidden;
position: relative;
width: 100%;
overflow-y: hidden;
overflow-x: hidden;
}

.input-group.select-all .Select__control,
.input-group.select-all .Select-control {
overflow-y: auto;
overflow-x: hidden;
}

.Select__control:hover,
Expand Down
42 changes: 28 additions & 14 deletions frontend/static/popups/create/ColumnSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ interface ColumnSelectInputProps {
updateState: (state: Record<string, BaseOption<string> | Array<BaseOption<string>> | undefined>) => void;
dtypes?: string[];
includeAllOption?: boolean;
selectAll?: boolean;
}

export const BaseColumnSelectInput: React.FC<ColumnSelectInputProps & WithTranslation> = ({
Expand All @@ -69,6 +70,7 @@ export const BaseColumnSelectInput: React.FC<ColumnSelectInputProps & WithTransl
prop,
updateState,
includeAllOption,
selectAll,
t,
}) => {
const [dtypesStr, columnOptions] = React.useMemo(() => {
Expand All @@ -83,19 +85,31 @@ export const BaseColumnSelectInput: React.FC<ColumnSelectInputProps & WithTransl
}, [dtypes, columns, parent, otherProps, includeAllOption]);

return (
<Select
isMulti={isMulti ?? false}
className="Select is-clearable is-searchable Select--single"
classNamePrefix="Select"
options={columnOptions}
getOptionLabel={(o) => o.label ?? o.value}
getOptionValue={(o) => o.value}
value={parent[prop] ?? null}
onChange={(selected?: BaseOption<string> | Array<BaseOption<string>>) => updateState({ [prop]: selected })}
isClearable={true}
filterOption={createFilter({ ignoreAccents: false })} // required for performance reasons!
noOptionsMessage={() => `${t('No columns available')}${dtypesStr}!`}
/>
<>
<Select
isMulti={isMulti ?? false}
className="Select is-clearable is-searchable Select--single"
classNamePrefix="Select"
options={columnOptions}
getOptionLabel={(o) => o.label ?? o.value}
getOptionValue={(o) => o.value}
value={parent[prop] ?? null}
onChange={(selected?: BaseOption<string> | Array<BaseOption<string>>) => updateState({ [prop]: selected })}
isClearable={true}
filterOption={createFilter({ ignoreAccents: false })} // required for performance reasons!
noOptionsMessage={() => `${t('No columns available')}${dtypesStr}!`}
/>
{isMulti && selectAll && columnOptions.length > (parent[prop] ?? []).length && (
<button
className="col-auto btn btn-secondary ml-5"
onClick={() => updateState({ [prop]: columnOptions })}
data-testid="view-duplicates"
title="Select All"
>
<i className="fa-solid fa-check-double" />
</button>
)}
</>
);
};

Expand All @@ -115,7 +129,7 @@ const ColumnSelect: React.FC<React.PropsWithChildren<ColumnSelectProps & WithTra
<div className="form-group row">
<label className="col-md-3 col-form-label text-right">{label || inputProps.prop}</label>
<div className="col-md-8">
<div className="input-group">
<div className={`input-group${inputProps.selectAll ? ' select-all' : ''}`}>
<ColumnSelectInput {...inputProps} />
</div>
{children}
Expand Down
9 changes: 6 additions & 3 deletions frontend/static/popups/duplicates/Rows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,19 @@ const Rows: React.FC<RowsProps & WithTranslation> = ({ columns, selectedCol, set
let result: React.ReactNode = `${t('No duplicate rows exist for the column(s)')}: ${
cfg.subset?.join(', ') ?? ''
}`;
if (response?.results && Object.keys(response.results).length) {
if (!cfg.subset?.length) {
result = t('No duplicate rows exist');
}
if (response?.results && response.results.removed) {
result = (
<React.Fragment>
<span className="pr-3">{t('From')}</span>
<b>{response.results.total}</b>
<span className="pl-3">{` ${t('rows')}:`}</span>
<span className="pl-2">{` ${t('rows')}:`}</span>
<ul>
<li>
<b>{response.results.removed}</b>
{t(' duplicate rows will be removed')}
{t(` ${cfg.subset ? `(${cfg.subset?.join(', ')}) ` : ''}duplicate rows will be removed`)}
</li>
<li>
<b>{response.results.remaining}</b>
Expand Down
10 changes: 6 additions & 4 deletions frontend/static/popups/duplicates/ShowDuplicates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface ShowDuplicatesProps extends BaseDuplicatesComponentProps {
}

/** Response type definition for testing ShowDuplicates config */
type TestType = DuplicatesRepository.DuplicatesResponse<ShowDuplicatesResult>;
type TestType = DuplicatesRepository.DuplicatesResponse<ShowDuplicatesResult> & { cfg: ShowDuplicatesConfig };

const ShowDuplicates: React.FC<ShowDuplicatesProps & WithTranslation> = ({ columns, setCfg, t }) => {
const dataId = useAppSelector(selectDataId);
Expand All @@ -47,13 +47,14 @@ const ShowDuplicates: React.FC<ShowDuplicatesProps & WithTranslation> = ({ colum

const test = (): void => {
setLoadingTest(true);
const cfg = buildCfg();
DuplicatesRepository.run<TestType>(dataId, {
type: DuplicatesConfigType.SHOW,
cfg: buildCfg(),
cfg,
action: DuplicatesActionType.TEST,
}).then((response) => {
setLoadingTest(false);
setTestOutput(response);
setTestOutput({ ...response, cfg } as TestType);
setFilter(undefined);
});
};
Expand All @@ -69,7 +70,7 @@ const ShowDuplicates: React.FC<ShowDuplicatesProps & WithTranslation> = ({ colum
if (Object.keys(testOutput.results).length) {
return (
<React.Fragment>
<span>{`${t('Duplicates exist for the following')} (${cfg.group?.join(', ')}) ${t('groups')}:`}</span>
<span>{`${t('Duplicates exist for the following')} (${testOutput.cfg.group?.join(', ')}) ${t('groups')}:`}</span>
<br />
<b>Total Duplicates</b>
{`: ${Object.values(testOutput.results).reduce((res, { count }) => res + count, 0)}`}
Expand Down Expand Up @@ -107,6 +108,7 @@ const ShowDuplicates: React.FC<ShowDuplicatesProps & WithTranslation> = ({ colum
}}
columns={columns}
isMulti={true}
selectAll={true}
/>
<div className="form-group row">
<div className="col-md-3" />
Expand Down

0 comments on commit 20d9c1c

Please # to comment.