feat(workspace): add blob and storage limit (#5535)

close TOV-343 AFF-508 TOV-461 TOV-460 TOV-419

Add `isOverCapacity ` status to detect if blob usage exceeds limits.
Add `onCapacityChange` and `onBlobSet` to monitor if the storage or blob exceeds the capacity limit.
Global modals `LocalQuotaModal` and `CloudQuotaModal` have been added, with the upload size of the blob being limited within the modal components.
The notification component has been adjusted, now you can pass in `action` click events and `actionLabel` .
This commit is contained in:
JimmFly
2024-01-24 07:34:51 +00:00
parent c566952e09
commit 25897dc404
25 changed files with 394 additions and 58 deletions

View File

@@ -11,7 +11,8 @@ export type Notification = {
progressingBar?: boolean;
multimedia?: React.ReactNode | JSX.Element;
// actions
undo?: () => Promise<void>;
action?: () => Promise<void>;
actionLabel?: string;
};
const notificationsBaseAtom = atom<Notification[]>([]);
@@ -48,19 +49,19 @@ export const pushNotificationAtom = atom<null, [Notification], void>(
set(notificationsBaseAtom, notifications =>
notifications.filter(notification => notification.key !== key)
);
const undo: (() => Promise<void>) | undefined = newNotification.undo
const action: (() => Promise<void>) | undefined = newNotification.action
? (() => {
const undo: () => Promise<void> = newNotification.undo;
return async function undoNotificationWrapper() {
const action: () => Promise<void> = newNotification.action;
return async function actionNotificationWrapper() {
removeNotification();
return undo();
return action();
};
})()
: undefined;
set(notificationsBaseAtom, notifications => [
// push to the top
{ ...newNotification, undo },
{ ...newNotification, action },
...notifications,
]);
}

View File

@@ -2,6 +2,7 @@
// License on the MIT
// https://github.com/emilkowalski/sonner/blob/5cb703edc108a23fd74979235c2f3c4005edd2a7/src/index.tsx
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon, InformationFillDuotoneIcon } from '@blocksuite/icons';
import * as Toast from '@radix-ui/react-toast';
import clsx from 'clsx';
@@ -71,6 +72,7 @@ const typeColorMap = {
};
function NotificationCard(props: NotificationCardProps): ReactNode {
const t = useAFFiNEI18N();
const removeNotification = useSetAtom(removeNotificationAtom);
const { notification, notifications, setHeights, heights, index } = props;
@@ -134,7 +136,6 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
notificationNode.style.height = 'auto';
const newHeight = notificationNode.getBoundingClientRect().height;
notificationNode.style.height = originalHeight;
setInitialHeight(newHeight);
setHeights(heights => {
@@ -190,9 +191,9 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
};
}, [duration, expand, onClickRemove]);
const onClickUndo = useCallback(() => {
if (notification.undo) {
notification.undo().catch(err => {
const onClickAction = useCallback(() => {
if (notification.action) {
notification.action().catch(err => {
console.error(err);
});
}
@@ -298,7 +299,7 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
<div className={styles.notificationTitleContactStyle}>
{notification.title}
</div>
{notification.undo && (
{notification.action && (
<div
className={clsx(styles.undoButtonStyle, {
[styles.darkColorStyle]:
@@ -306,15 +307,16 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
notification.theme !== 'default',
[styles.undoButtonWithMediaStyle]: notification.multimedia,
})}
onClick={onClickUndo}
onClick={onClickAction}
>
UNDO
{notification.actionLabel ??
t['com.affine.keyboardShortcuts.undo']()}
</div>
)}
{notification.multimedia ? null : (
<IconButton
className={clsx(styles.closeButtonStyle, {
[styles.closeButtonWithoutUndoStyle]: !notification.undo,
[styles.closeButtonWithoutUndoStyle]: !notification.action,
})}
style={{
color: