Implement delete multiple docs

This commit is contained in:
Laurent Nguyen 2024-03-27 18:23:17 +01:00
parent b686501df8
commit 2f85c4f84a
1 changed files with 109 additions and 80 deletions

View File

@ -113,7 +113,6 @@ const DocumentsTabComponent: React.FunctionComponent<{
const [documentIds, setDocumentIds] = useState<DocumentId[]>([]); const [documentIds, setDocumentIds] = useState<DocumentId[]>([]);
const [isExecuting, setIsExecuting] = useState<boolean>(false); // TODO isExecuting is a member of TabsBase. We may need to update this field. const [isExecuting, setIsExecuting] = useState<boolean>(false); // TODO isExecuting is a member of TabsBase. We may need to update this field.
const [dataContentsGridScrollHeight, setDataContentsGridScrollHeight] = useState<string>(undefined); const [dataContentsGridScrollHeight, setDataContentsGridScrollHeight] = useState<string>(undefined);
const [shouldShowEditor, setShouldShowEditor] = useState<boolean>(false);
// Query // Query
const [documentsIterator, setDocumentsIterator] = useState<{ const [documentsIterator, setDocumentsIterator] = useState<{
@ -133,6 +132,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
const [selectedDocumentContentBaseline, setSelectedDocumentContentBaseline] = useState<string>(undefined); const [selectedDocumentContentBaseline, setSelectedDocumentContentBaseline] = useState<string>(undefined);
const [selectedDocumentId, setSelectedDocumentId] = useState<DocumentId>(undefined); const [selectedDocumentId, setSelectedDocumentId] = useState<DocumentId>(undefined);
const [multiSelectedDocumentIds, setMultiSelectedDocumentIds] = useState<DocumentId[]>([]);
// Command buttons // Command buttons
const [editorState, setEditorState] = useState<ViewModels.DocumentExplorerState>( const [editorState, setEditorState] = useState<ViewModels.DocumentExplorerState>(
@ -328,7 +328,11 @@ const DocumentsTabComponent: React.FunctionComponent<{
}, []); }, []);
// If editor state changes, update the nav // If editor state changes, update the nav
useEffect(() => updateNavbarWithTabsButtons(), [editorState, selectedDocumentContent, initialDocumentContent]); // TODO Put whatever the buttons callback use in the dependency array
useEffect(
() => updateNavbarWithTabsButtons(),
[editorState, selectedDocumentContent, initialDocumentContent, multiSelectedDocumentIds, documentIds],
);
useEffect(() => { useEffect(() => {
if (documentsIterator) { if (documentsIterator) {
@ -336,10 +340,6 @@ const DocumentsTabComponent: React.FunctionComponent<{
} }
}, [documentsIterator]); }, [documentsIterator]);
useEffect(() => {
setShouldShowEditor(!!selectedDocumentContent);
}, [selectedDocumentContent]);
const onNewDocumentClick = useCallback((): void => { const onNewDocumentClick = useCallback((): void => {
if (isEditorDirty()) { if (isEditorDirty()) {
useDialog useDialog
@ -491,49 +491,66 @@ const DocumentsTabComponent: React.FunctionComponent<{
// setEditorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); // setEditorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits);
}; };
const onDeleteExisitingDocumentClick = async (): Promise<void> => { const onDeleteExisitingDocumentsClick = async (): Promise<void> => {
// const selectedDocumentId = this.selectedDocumentId(); // const selectedDocumentId = this.selectedDocumentId();
const msg = !isPreferredApiMongoDB
? "Are you sure you want to delete the selected item ?"
: "Are you sure you want to delete the selected document ?";
useDialog // TODO: Rework this for localization
.getState() const isPlural = multiSelectedDocumentIds.length > 1;
.showOkCancelModalDialog( const documentName = !isPreferredApiMongoDB
? isPlural
? `the selected ${multiSelectedDocumentIds.length} items`
: "the selected item"
: isPlural
? `the selected ${multiSelectedDocumentIds.length} documents`
: "the selected document";
const msg = `Are you sure you want to delete ${documentName}?`;
useDialog.getState().showOkCancelModalDialog(
"Confirm delete", "Confirm delete",
msg, msg,
"Delete", "Delete",
async () => await _deleteDocument(selectedDocumentId), // async () => await _deleteDocuments(selectedDocumentId),
() => deleteDocuments(multiSelectedDocumentIds),
"Cancel", "Cancel",
undefined, undefined,
); );
}; };
const __deleteDocument = (documentId: DocumentId): Promise<void> => { const deleteDocuments = (toDeleteDocumentIds: DocumentId[]): void => {
return deleteDocument(props.collection, documentId); setIsExecutionError(false);
setIsExecuting(true);
const promises = toDeleteDocumentIds.map((documentId) => _deleteDocuments(documentId));
Promise.all(promises)
.then((deletedDocumentIds: DocumentId[]) => {
const newDocumentIds = [...documentIds];
deletedDocumentIds.forEach((deletedDocumentId) => {
if (deletedDocumentId !== undefined) {
// documentIds.remove((documentId: DocumentId) => documentId.rid === selectedDocumentId.rid);
const index = toDeleteDocumentIds.findIndex((documentId) => documentId.rid === deletedDocumentId.rid);
if (index !== -1) {
newDocumentIds.splice(index, 1);
}
}
});
setDocumentIds(newDocumentIds);
setSelectedDocumentContent(undefined);
setSelectedDocumentId(undefined);
setMultiSelectedDocumentIds([]);
setEditorState(ViewModels.DocumentExplorerState.noDocumentSelected);
})
.finally(() => setIsExecuting(false));
}; };
const _deleteDocument = (selectedDocumentId: DocumentId): Promise<void> => { const _deleteDocuments = (documentId: DocumentId): Promise<DocumentId> => {
setIsExecutionError(false); // setIsExecutionError(false);
const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, { const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, {
dataExplorerArea: Constants.Areas.Tab, dataExplorerArea: Constants.Areas.Tab,
tabTitle: props.tabTitle, tabTitle: props.tabTitle,
}); });
setIsExecuting(true); // setIsExecuting(true);
return __deleteDocument(selectedDocumentId) return deleteDocument(props.collection, documentId).then(
.then(
() => { () => {
// documentIds.remove((documentId: DocumentId) => documentId.rid === selectedDocumentId.rid);
const index = documentIds.findIndex((documentId) => documentId.rid === selectedDocumentId.rid);
if (index !== -1) {
const newDocumentIds = [...documentIds];
newDocumentIds.splice(index, 1);
setDocumentIds(newDocumentIds);
}
setSelectedDocumentContent("");
setSelectedDocumentId(null);
setEditorState(ViewModels.DocumentExplorerState.noDocumentSelected);
TelemetryProcessor.traceSuccess( TelemetryProcessor.traceSuccess(
Action.DeleteDocument, Action.DeleteDocument,
{ {
@ -542,6 +559,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
}, },
startKey, startKey,
); );
return documentId;
}, },
(error) => { (error) => {
setIsExecutionError(true); setIsExecutionError(true);
@ -556,9 +574,10 @@ const DocumentsTabComponent: React.FunctionComponent<{
}, },
startKey, startKey,
); );
return undefined;
}, },
) );
.finally(() => setIsExecuting(false)); // .finally(() => setIsExecuting(false));
}; };
const onShowFilterClick = () => { const onShowFilterClick = () => {
@ -910,7 +929,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
buttons.push({ buttons.push({
iconSrc: DeleteDocumentIcon, iconSrc: DeleteDocumentIcon,
iconAlt: label, iconAlt: label,
onCommandClick: onDeleteExisitingDocumentClick, onCommandClick: onDeleteExisitingDocumentsClick,
commandButtonLabel: label, commandButtonLabel: label,
ariaLabel: label, ariaLabel: label,
hasPopup: false, hasPopup: false,
@ -993,9 +1012,16 @@ const DocumentsTabComponent: React.FunctionComponent<{
} }
}; };
const onDocumentsSelectionChange = (selectedItemsIndices: Set<number>) => { const onDocumentsSelectionChange = useCallback(
// TODO: Update some state? (selectedItemsIndices: Set<number>) => {
}; if (documentIds.length === 0) {
return;
}
setMultiSelectedDocumentIds(Array.from(selectedItemsIndices).map((index) => documentIds[index]));
},
[documentIds],
);
const loadDocument = (documentId: DocumentId) => const loadDocument = (documentId: DocumentId) =>
(_isQueryCopilotSampleContainer ? readSampleDocument(documentId) : readDocument(props.collection, documentId)).then( (_isQueryCopilotSampleContainer ? readSampleDocument(documentId) : readDocument(props.collection, documentId)).then(
@ -1167,7 +1193,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
value={filterContent} value={filterContent}
onChange={(e) => setFilterContent(e.target.value)} onChange={(e) => setFilterContent(e.target.value)}
/* /*
data-bind=" data-bind="
W attr:{ W attr:{
placeholder:isPreferredApiMongoDB?'Type a query predicate (e.g., {´a´:´foo´}), or choose one from the drop down list, or leave empty to query all documents.':'Type a query predicate (e.g., WHERE c.id=´1´), or choose one from the drop down list, or leave empty to query all documents.' placeholder:isPreferredApiMongoDB?'Type a query predicate (e.g., {´a´:´foo´}), or choose one from the drop down list, or leave empty to query all documents.':'Type a query predicate (e.g., WHERE c.id=´1´), or choose one from the drop down list, or leave empty to query all documents.'
}, },
@ -1250,7 +1276,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
</a> </a>
</div> </div>
<div style={{ minWidth: "20%", width: "100%" }}> <div style={{ minWidth: "20%", width: "100%" }}>
{shouldShowEditor && ( {selectedDocumentContent && multiSelectedDocumentIds.length === 1 && (
<EditorReact <EditorReact
language={"json"} language={"json"}
content={selectedDocumentContent} content={selectedDocumentContent}
@ -1261,6 +1287,9 @@ const DocumentsTabComponent: React.FunctionComponent<{
onContentChanged={_onEditorContentChange} onContentChanged={_onEditorContentChange}
/> />
)} )}
{multiSelectedDocumentIds.length > 1 && (
<span style={{ margin: 10 }}>Number of selected documents: {multiSelectedDocumentIds.length}</span>
)}
</div> </div>
</Split> </Split>
</div> </div>