Skip to content

Commit

Permalink
feat(spinner): add spinner to recording table actions
Browse files Browse the repository at this point in the history
  • Loading branch information
tthvo committed Nov 17, 2022
1 parent 59514c6 commit 39d4406
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 15 deletions.
122 changes: 111 additions & 11 deletions src/app/Recordings/ActiveRecordingsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import {
import { TargetRecordingFilters, UpdateFilterOptions } from '@app/Shared/Redux/RecordingFilterReducer';
import { RootState, StateDispatch } from '@app/Shared/Redux/ReduxStore';
import { authFailMessage } from '@app/ErrorView/ErrorView';
import { LoadingPropsType } from '@app/Shared/ProgressIndicator';

export enum PanelContent {
LABELS,
Expand All @@ -108,6 +109,11 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
const [panelContent, setPanelContent] = React.useState(PanelContent.LABELS);
const [isLoading, setIsLoading] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState('');
const [actionLoadings, setActionLoadings] = React.useState<Record<ActiveActions, boolean>>({
ARCHIVE: false,
DELETE: false,
STOP: false,
});

const targetRecordingFilters = useSelector((state: RootState) => {
const filters = state.recordingFilters.list.filter(
Expand Down Expand Up @@ -313,18 +319,44 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
return () => window.clearInterval(id);
}, [refreshRecordingList, context, context.settings]);

const handlePostActions = React.useCallback(
(action: ActiveActions) => {
setActionLoadings((old) => {
const newActionLoadings = { ...old };
newActionLoadings[action] = false;
return newActionLoadings;
});
},
[setActionLoadings]
);

const handleArchiveRecordings = React.useCallback(() => {
setActionLoadings((old) => ({ ...old, ARCHIVE: true }));
const tasks: Observable<boolean>[] = [];
filteredRecordings.forEach((r: ActiveRecording) => {
if (checkedIndices.includes(r.id)) {
handleRowCheck(false, r.id);
tasks.push(context.api.archiveRecording(r.name).pipe(first()));
}
});
addSubscription(forkJoin(tasks).subscribe(() => {} /* do nothing */, window.console.error));
}, [filteredRecordings, checkedIndices, handleRowCheck, context.api, addSubscription]);
addSubscription(
forkJoin(tasks).subscribe({
next: () => handlePostActions('ARCHIVE'),
error: () => handlePostActions('ARCHIVE'),
})
);
}, [
filteredRecordings,
checkedIndices,
handleRowCheck,
context.api,
addSubscription,
setActionLoadings,
handlePostActions,
]);

const handleStopRecordings = React.useCallback(() => {
setActionLoadings((old) => ({ ...old, STOP: true }));
const tasks: Observable<boolean>[] = [];
filteredRecordings.forEach((r: ActiveRecording) => {
if (checkedIndices.includes(r.id)) {
Expand All @@ -334,19 +366,46 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
}
}
});
addSubscription(forkJoin(tasks).subscribe(() => {} /* do nothing */, window.console.error));
}, [filteredRecordings, checkedIndices, handleRowCheck, context.api, addSubscription]);
addSubscription(
forkJoin(tasks).subscribe({
next: () => handlePostActions('STOP'),
error: () => handlePostActions('STOP'),
})
);
}, [
filteredRecordings,
checkedIndices,
handleRowCheck,
context.api,
addSubscription,
setActionLoadings,
handlePostActions,
]);

const handleDeleteRecordings = React.useCallback(() => {
setActionLoadings((old) => ({ ...old, DELETE: true }));
const tasks: Observable<{}>[] = [];
filteredRecordings.forEach((r: ActiveRecording) => {
if (checkedIndices.includes(r.id)) {
context.reports.delete(r);
tasks.push(context.api.deleteRecording(r.name).pipe(first()));
}
});
addSubscription(forkJoin(tasks).subscribe(() => {} /* do nothing */, window.console.error));
}, [filteredRecordings, checkedIndices, context.reports, context.api, addSubscription]);
addSubscription(
forkJoin(tasks).subscribe({
next: () => handlePostActions('DELETE'),
error: () => handlePostActions('DELETE'),
})
);
}, [
filteredRecordings,
checkedIndices,
context.reports,
context.api,
addSubscription,
setActionLoadings,
handlePostActions,
]);

const handleClearFilters = React.useCallback(() => {
dispatch(deleteAllFiltersIntent(targetConnectURL, false));
Expand Down Expand Up @@ -542,6 +601,7 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
handleEditLabels={handleEditLabels}
handleStopRecordings={handleStopRecordings}
handleDeleteRecordings={handleDeleteRecordings}
actionLoadings={actionLoadings}
/>
),
[
Expand All @@ -558,6 +618,7 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
handleEditLabels,
handleStopRecordings,
handleDeleteRecordings,
actionLoadings,
]
);

Expand Down Expand Up @@ -606,6 +667,8 @@ export const ActiveRecordingsTable: React.FunctionComponent<ActiveRecordingsTabl
);
};

export type ActiveActions = 'ARCHIVE' | 'STOP' | 'DELETE';

export interface ActiveRecordingsToolbarProps {
target: string;
checkedIndices: number[];
Expand All @@ -620,6 +683,7 @@ export interface ActiveRecordingsToolbarProps {
handleEditLabels: () => void;
handleStopRecordings: () => void;
handleDeleteRecordings: () => void;
actionLoadings: Record<ActiveActions, boolean>;
}

const ActiveRecordingsToolbar: React.FunctionComponent<ActiveRecordingsToolbarProps> = (props) => {
Expand Down Expand Up @@ -652,6 +716,27 @@ const ActiveRecordingsToolbar: React.FunctionComponent<ActiveRecordingsToolbarPr
return !anyRunning;
}, [props.checkedIndices, props.filteredRecordings]);

const actionLoadingProps = React.useMemo<Record<ActiveActions, LoadingPropsType>>(
() => ({
ARCHIVE: {
spinnerAriaValueText: 'Archiving',
spinnerAriaLabel: 'archive-active-recording',
isLoading: props.actionLoadings['ARCHIVE'],
},
STOP: {
spinnerAriaValueText: 'Stopping',
spinnerAriaLabel: 'stop-active-recording',
isLoading: props.actionLoadings['STOP'],
},
DELETE: {
spinnerAriaValueText: 'Deleting',
spinnerAriaLabel: 'deleting-active-recording',
isLoading: props.actionLoadings['DELETE'],
},
}),
[props.actionLoadings]
);

const buttons = React.useMemo(() => {
let arr = [
<Button key="create" variant="primary" onClick={props.handleCreateRecording}>
Expand All @@ -665,8 +750,9 @@ const ActiveRecordingsToolbar: React.FunctionComponent<ActiveRecordingsToolbarPr
variant="secondary"
onClick={props.handleArchiveRecordings}
isDisabled={!props.checkedIndices.length}
{...actionLoadingProps['ARCHIVE']}
>
Archive
{props.actionLoadings['ARCHIVE'] ? 'Archiving' : 'Archive'}
</Button>
);
}
Expand All @@ -680,11 +766,23 @@ const ActiveRecordingsToolbar: React.FunctionComponent<ActiveRecordingsToolbarPr
>
Edit Labels
</Button>,
<Button key="stop" variant="tertiary" onClick={props.handleStopRecordings} isDisabled={isStopDisabled}>
Stop
<Button
key="stop"
variant="tertiary"
onClick={props.handleStopRecordings}
isDisabled={isStopDisabled}
{...actionLoadingProps['STOP']}
>
{props.actionLoadings['STOP'] ? 'Stopping' : 'Stop'}
</Button>,
<Button key="delete" variant="danger" onClick={handleDeleteButton} isDisabled={!props.checkedIndices.length}>
Delete
<Button
key="delete"
variant="danger"
onClick={handleDeleteButton}
isDisabled={!props.checkedIndices.length}
{...actionLoadingProps['DELETE']}
>
{props.actionLoadings['DELETE'] ? 'Deleting' : 'Delete'}
</Button>,
];
return (
Expand All @@ -700,7 +798,9 @@ const ActiveRecordingsToolbar: React.FunctionComponent<ActiveRecordingsToolbarPr
props.handleArchiveRecordings,
props.handleEditLabels,
props.handleStopRecordings,
props.actionLoadings,
handleDeleteButton,
actionLoadingProps,
]);

const deleteActiveWarningModal = React.useMemo(() => {
Expand Down
57 changes: 53 additions & 4 deletions src/app/Recordings/ArchivedRecordingsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import {
} from '@app/Shared/Redux/RecordingFilterActions';
import { RootState, StateDispatch } from '@app/Shared/Redux/ReduxStore';
import { formatBytes, hashCode } from '@app/utils/utils';
import { LoadingPropsType } from '@app/Shared/ProgressIndicator';

export interface ArchivedRecordingsTableProps {
target: Observable<Target>;
Expand All @@ -103,6 +104,7 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
const [showDetailsPanel, setShowDetailsPanel] = React.useState(false);
const [isLoading, setIsLoading] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState('');
const [actionLoadings, setActionLoadings] = React.useState<Record<ArchiveActions, boolean>>({ DELETE: false });

const targetRecordingFilters = useSelector((state: RootState) => {
const filters = state.recordingFilters.list.filter(
Expand Down Expand Up @@ -346,7 +348,19 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
setHeaderChecked(checkedIndices.length === filteredRecordings.length);
}, [setHeaderChecked, checkedIndices]);

const handlePostActions = React.useCallback(
(action: ArchiveActions) => {
setActionLoadings((old) => {
const newActionLoadings = { ...old };
newActionLoadings[action] = false;
return newActionLoadings;
});
},
[setActionLoadings]
);

const handleDeleteRecordings = React.useCallback(() => {
setActionLoadings((old) => ({ ...old, DELETE: true }));
const tasks: Observable<any>[] = [];
if (props.directory) {
const directory = props.directory;
Expand All @@ -366,11 +380,25 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
tasks.push(context.api.deleteArchivedRecording(t.connectUrl, r.name).pipe(first()));
}
});
addSubscription(forkJoin(tasks).subscribe());
addSubscription(
forkJoin(tasks).subscribe({
next: () => handlePostActions('DELETE'),
error: () => handlePostActions('DELETE'),
})
);
})
);
}
}, [addSubscription, filteredRecordings, checkedIndices, context.reports, context.api, props.directory]);
}, [
addSubscription,
filteredRecordings,
checkedIndices,
context.reports,
context.api,
props.directory,
setActionLoadings,
handlePostActions,
]);

const toggleExpanded = React.useCallback(
(id: string) => {
Expand Down Expand Up @@ -508,6 +536,7 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
handleDeleteRecordings={handleDeleteRecordings}
handleShowUploadModal={() => setShowUploadModal(true)}
isUploadsTable={props.isUploadsTable}
actionLoadings={actionLoadings}
/>
),
[
Expand All @@ -522,6 +551,7 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
handleDeleteRecordings,
setShowUploadModal,
props.isUploadsTable,
actionLoadings,
]
);

Expand Down Expand Up @@ -605,6 +635,8 @@ export const ArchivedRecordingsTable: React.FunctionComponent<ArchivedRecordings
);
};

export type ArchiveActions = 'DELETE';

interface RecordingRowProps {
key: string;
recording: ArchivedRecording;
Expand All @@ -626,6 +658,7 @@ export interface ArchivedRecordingsToolbarProps {
handleDeleteRecordings: () => void;
handleShowUploadModal: () => void;
isUploadsTable: boolean;
actionLoadings: Record<ArchiveActions, boolean>;
}

const ArchivedRecordingsToolbar: React.FunctionComponent<ArchivedRecordingsToolbarProps> = (props) => {
Expand Down Expand Up @@ -660,6 +693,17 @@ const ArchivedRecordingsToolbar: React.FunctionComponent<ArchivedRecordingsToolb
);
}, [warningModalOpen, props.handleDeleteRecordings, handleWarningModalClose]);

const actionLoadingProps = React.useMemo<Record<ArchiveActions, LoadingPropsType>>(
() => ({
DELETE: {
spinnerAriaValueText: 'Deleting',
spinnerAriaLabel: 'deleting-archived-recording',
isLoading: props.actionLoadings['DELETE'],
} as LoadingPropsType,
}),
[props.actionLoadings]
);

return (
<Toolbar
id="archived-recordings-toolbar"
Expand All @@ -686,8 +730,13 @@ const ArchivedRecordingsToolbar: React.FunctionComponent<ArchivedRecordingsToolb
</Button>
</ToolbarItem>
<ToolbarItem>
<Button variant="danger" onClick={handleDeleteButton} isDisabled={!props.checkedIndices.length}>
Delete
<Button
variant="danger"
onClick={handleDeleteButton}
isDisabled={!props.checkedIndices.length}
{...actionLoadingProps['DELETE']}
>
{props.actionLoadings['DELETE'] ? 'Deleting' : 'Delete'}
</Button>
</ToolbarItem>
</ToolbarGroup>
Expand Down

0 comments on commit 39d4406

Please sign in to comment.