Added spinner for notebook delete (#458)

* initial UI for delete published nb spinner

* added notebook delete spinner

* addressed PR comments
This commit is contained in:
Srinath Narayanan 2021-03-02 13:59:10 -08:00 committed by GitHub
parent 4127d0f522
commit b8e9903287
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 89 deletions

View File

@ -13,6 +13,8 @@ import {
LinkBase, LinkBase,
Separator, Separator,
TooltipHost, TooltipHost,
Spinner,
SpinnerSize,
} from "office-ui-fabric-react"; } from "office-ui-fabric-react";
import * as React from "react"; import * as React from "react";
import { IGalleryItem } from "../../../../Juno/JunoClient"; import { IGalleryItem } from "../../../../Juno/JunoClient";
@ -29,10 +31,14 @@ export interface GalleryCardComponentProps {
onFavoriteClick: () => void; onFavoriteClick: () => void;
onUnfavoriteClick: () => void; onUnfavoriteClick: () => void;
onDownloadClick: () => void; onDownloadClick: () => void;
onDeleteClick: () => void; onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
} }
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps> { interface GalleryCardComponentState {
isDeletingPublishedNotebook: boolean;
}
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps, GalleryCardComponentState> {
public static readonly CARD_WIDTH = 256; public static readonly CARD_WIDTH = 256;
private static readonly cardImageHeight = 144; private static readonly cardImageHeight = 144;
public static readonly cardHeightToWidthRatio = public static readonly cardHeightToWidthRatio =
@ -40,6 +46,14 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
private static readonly cardDescriptionMaxChars = 80; private static readonly cardDescriptionMaxChars = 80;
private static readonly cardItemGapBig = 10; private static readonly cardItemGapBig = 10;
private static readonly cardItemGapSmall = 8; private static readonly cardItemGapSmall = 8;
private static readonly cardDeleteSpinnerHeight = 360;
constructor(props: GalleryCardComponentProps) {
super(props);
this.state = {
isDeletingPublishedNotebook: false,
};
}
public render(): JSX.Element { public render(): JSX.Element {
const cardButtonsVisible = this.props.isFavorite !== undefined || this.props.showDownload || this.props.showDelete; const cardButtonsVisible = this.props.isFavorite !== undefined || this.props.showDownload || this.props.showDelete;
@ -59,6 +73,17 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
tokens={{ width: GalleryCardComponent.CARD_WIDTH, childrenGap: 0 }} tokens={{ width: GalleryCardComponent.CARD_WIDTH, childrenGap: 0 }}
onClick={(event) => this.onClick(event, this.props.onClick)} onClick={(event) => this.onClick(event, this.props.onClick)}
> >
{this.state.isDeletingPublishedNotebook && (
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
<Spinner
size={SpinnerSize.large}
label={`Deleting '${cardTitle}'`}
styles={{ root: { height: GalleryCardComponent.cardDeleteSpinnerHeight } }}
/>
</Card.Item>
)}
{!this.state.isDeletingPublishedNotebook && (
<>
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}> <Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
<Persona <Persona
imageUrl={this.props.data.isSample && CosmosDBLogo} imageUrl={this.props.data.isSample && CosmosDBLogo}
@ -109,7 +134,8 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
</Text> </Text>
<span> <span>
{this.props.data.views !== undefined && this.generateIconText("RedEye", this.props.data.views.toString())} {this.props.data.views !== undefined &&
this.generateIconText("RedEye", this.props.data.views.toString())}
{this.props.data.downloads !== undefined && {this.props.data.downloads !== undefined &&
this.generateIconText("Download", this.props.data.downloads.toString())} this.generateIconText("Download", this.props.data.downloads.toString())}
{this.props.data.favorites !== undefined && {this.props.data.favorites !== undefined &&
@ -141,10 +167,17 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
this.generateIconButtonWithTooltip("Download", "Download", "left", this.props.onDownloadClick)} this.generateIconButtonWithTooltip("Download", "Download", "left", this.props.onDownloadClick)}
{this.props.showDelete && {this.props.showDelete &&
this.generateIconButtonWithTooltip("Delete", "Remove", "right", this.props.onDeleteClick)} this.generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
this.props.onDeleteClick(
() => this.setState({ isDeletingPublishedNotebook: true }),
() => this.setState({ isDeletingPublishedNotebook: false })
)
)}
</span> </span>
</Card.Section> </Card.Section>
)} )}
</>
)}
</Card> </Card>
); );
} }

View File

@ -666,7 +666,8 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
onFavoriteClick: () => this.favoriteItem(data), onFavoriteClick: () => this.favoriteItem(data),
onUnfavoriteClick: () => this.unfavoriteItem(data), onUnfavoriteClick: () => this.unfavoriteItem(data),
onDownloadClick: () => this.downloadItem(data), onDownloadClick: () => this.downloadItem(data),
onDeleteClick: () => this.deleteItem(data), onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) =>
this.deleteItem(data, beforeDelete, afterDelete),
}; };
return ( return (
@ -710,11 +711,18 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
); );
}; };
private deleteItem = async (data: IGalleryItem): Promise<void> => { private deleteItem = async (data: IGalleryItem, beforeDelete: () => void, afterDelete: () => void): Promise<void> => {
GalleryUtils.deleteItem(this.props.container, this.props.junoClient, data, (item) => { GalleryUtils.deleteItem(
this.props.container,
this.props.junoClient,
data,
(item) => {
this.publishedNotebooks = this.publishedNotebooks?.filter((notebook) => item.id !== notebook.id); this.publishedNotebooks = this.publishedNotebooks?.filter((notebook) => item.id !== notebook.id);
this.refreshSelectedTab(item); this.refreshSelectedTab(item);
}); },
beforeDelete,
afterDelete
);
}; };
private onPivotChange = (item: PivotItem): void => { private onPivotChange = (item: PivotItem): void => {

View File

@ -373,7 +373,9 @@ export function deleteItem(
container: Explorer, container: Explorer,
junoClient: JunoClient, junoClient: JunoClient,
data: IGalleryItem, data: IGalleryItem,
onComplete: (item: IGalleryItem) => void onComplete: (item: IGalleryItem) => void,
beforeDelete?: () => void,
afterDelete?: () => void
): void { ): void {
if (container) { if (container) {
trace(Action.NotebooksGalleryClickDelete, ActionModifiers.Mark, { notebookId: data.id }); trace(Action.NotebooksGalleryClickDelete, ActionModifiers.Mark, { notebookId: data.id });
@ -383,6 +385,9 @@ export function deleteItem(
`Would you like to remove ${data.name} from the gallery?`, `Would you like to remove ${data.name} from the gallery?`,
"Remove", "Remove",
async () => { async () => {
if (beforeDelete) {
beforeDelete();
}
const name = data.name; const name = data.name;
const notificationId = NotificationConsoleUtils.logConsoleMessage( const notificationId = NotificationConsoleUtils.logConsoleMessage(
ConsoleDataType.InProgress, ConsoleDataType.InProgress,
@ -409,6 +414,10 @@ export function deleteItem(
); );
handleError(error, "GalleryUtils/deleteItem", `Failed to remove ${name} from gallery`); handleError(error, "GalleryUtils/deleteItem", `Failed to remove ${name} from gallery`);
} finally {
if (afterDelete) {
afterDelete();
}
} }
NotificationConsoleUtils.clearInProgressMessageWithId(notificationId); NotificationConsoleUtils.clearInProgressMessageWithId(notificationId);