refactor(core): adjust error detail and add error component to routes (#8234)
close PD-1430 https://github.com/user-attachments/assets/9447eaa5-c8b3-4108-96f1-d67ab45f249d ![CleanShot 2024-09-13 at 13 28 52@2x](https://github.com/user-attachments/assets/8c6c3a1d-9af7-41df-9d33-b69684d54d6b)
@ -2,4 +2,14 @@ import { style } from '@vanilla-extract/css';
|
||||
export const viewport = style({
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
export const container = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
});
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { getCurrentStore } from '@toeverything/infra';
|
||||
import { Provider } from 'jotai/react';
|
||||
import type { FC } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useRouteError } from 'react-router-dom';
|
||||
|
||||
import * as styles from './affine-error-fallback.css';
|
||||
import { ErrorDetail } from './error-basic/error-detail';
|
||||
import type { FallbackProps } from './error-basic/fallback-creator';
|
||||
import { ERROR_REFLECT_KEY } from './error-basic/fallback-creator';
|
||||
import { DumpInfo } from './error-basic/info-logger';
|
||||
@ -44,3 +47,25 @@ export const AffineErrorFallback: FC<AffineErrorFallbackProps> = props => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AffineErrorComponent = () => {
|
||||
const error = useRouteError() as Error;
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
const reloadPage = useCallback(() => {
|
||||
document.location.reload();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ErrorDetail
|
||||
title={t['com.affine.error.unexpected-error.title']()}
|
||||
resetError={reloadPage}
|
||||
buttonText={t['com.affine.error.reload']()}
|
||||
description={
|
||||
'message' in (error as Error) ? (error as Error).message : `${error}`
|
||||
}
|
||||
error={error as Error}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,25 +0,0 @@
|
||||
<svg width="402" height="178" viewBox="0 0 402 178" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M93.7434 129.308H1L71.7965 15.1021V167.142" stroke="#121212" stroke-width="2" stroke-linecap="square" stroke-linejoin="bevel" />
|
||||
<ellipse cx="71.4426" cy="14.7483" rx="3.89381" ry="3.88938" fill="#121212" />
|
||||
<ellipse cx="93.3894" cy="129.308" rx="3.89381" ry="3.88938" fill="#121212" />
|
||||
<path d="M140.357 27.1235L264.717 151.342" stroke="#E3E2E4" />
|
||||
<rect x="140.392" y="27.1582" width="124.291" height="124.149" stroke="#E3E2E4" />
|
||||
<path d="M264.339 89.4652C264.895 85.8242 265.183 82.0954 265.183 78.2995C265.183 37.7024 232.235 4.79199 191.592 4.79199C150.948 4.79199 118 37.7024 118 78.2995C118 118.897 150.948 151.807 191.592 151.807C195.23 151.807 198.807 151.543 202.304 151.034" stroke="#E3E2E4" />
|
||||
<path d="M202.304 150.964C205.949 151.519 209.682 151.807 213.483 151.807C254.126 151.807 287.074 118.897 287.074 78.2995C287.074 37.7024 254.126 4.79199 213.483 4.79199C172.839 4.79199 139.892 37.7024 139.892 78.2995C139.892 82.0955 140.18 85.8242 140.735 89.4652" stroke="#E3E2E4" />
|
||||
<path d="M140.2 89.4652C139.69 92.9584 139.426 96.5312 139.426 100.166C139.426 140.763 172.374 173.673 213.017 173.673C253.66 173.673 286.608 140.763 286.608 100.166C286.608 59.5686 253.66 26.6582 213.017 26.6582C209.378 26.6582 205.801 26.922 202.304 27.4314" stroke="#E3E2E4" />
|
||||
<path d="M202.304 27.4314C198.807 26.922 195.23 26.6582 191.592 26.6582C150.948 26.6582 118 59.5686 118 100.166C118 140.763 150.948 173.673 191.592 173.673C232.235 173.673 265.183 140.763 265.183 100.166C265.183 96.5312 264.919 92.9584 264.409 89.4652" stroke="#E3E2E4" />
|
||||
<path d="M264.717 27.1235L140.357 151.342" stroke="#E3E2E4" />
|
||||
<path d="M139.892 89.4653H264.717" stroke="#E3E2E4" />
|
||||
<path d="M202.304 26.6582V151.807" stroke="#E3E2E4" />
|
||||
<ellipse cx="264.717" cy="89.4651" rx="3.72614" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="264.717" cy="27.1233" rx="3.72614" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="264.717" cy="151.807" rx="3.72614" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="140.357" cy="151.807" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="202.304" cy="89.4651" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="202.304" cy="27.1233" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="140.357" cy="89.4651" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="140.357" cy="27.1233" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<ellipse cx="202.304" cy="151.807" rx="3.72613" ry="3.7219" fill="#121212" />
|
||||
<path d="M401 127.187H308.257L379.053 12.9805V165.02" stroke="#121212" stroke-width="2" stroke-linecap="square" stroke-linejoin="bevel" />
|
||||
<ellipse cx="379.407" cy="127.187" rx="3.89381" ry="3.88938" fill="#121212" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 221 KiB |
After Width: | Height: | Size: 232 KiB |
@ -1,43 +0,0 @@
|
||||
<svg width="420" height="208" viewBox="0 0 420 208" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.744 133.603C13.7034 140.028 15.0861 145.722 17.8923 150.683C20.6984 155.645 24.5823 159.529 29.5439 162.335C34.5055 165.141 40.2195 166.544 46.6858 166.544C53.8842 166.544 60.2692 164.775 65.8409 161.237C71.4125 157.699 75.7844 152.88 78.9566 146.779C82.1288 140.679 83.7352 133.765 83.7758 126.038C83.8165 117.986 82.1084 110.97 78.6516 104.992C75.2354 98.973 70.6805 94.3164 64.9868 91.0222C59.3338 87.6874 53.1522 86.02 46.4418 86.02C41.4395 86.02 36.8643 86.8943 32.7161 88.6431C28.5678 90.3512 24.928 92.649 21.7965 95.5365H21.3084L27.6528 43.8057H79.6276" stroke="#EAEAEA" stroke-width="1.71785"/>
|
||||
<ellipse cx="80.6482" cy="43.7108" rx="3.34449" ry="3.34069" fill="#EAEAEA"/>
|
||||
<ellipse cx="13.6516" cy="133.897" rx="3.34449" ry="3.34069" fill="#EAEAEA"/>
|
||||
<ellipse cx="27.3948" cy="43.7108" rx="3.34449" ry="3.34069" fill="#EAEAEA"/>
|
||||
<ellipse cx="21.3821" cy="95.245" rx="3.34449" ry="3.34069" fill="#EAEAEA"/>
|
||||
<path d="M129.77 50.7832L236.585 157.478" stroke="#727272" stroke-width="0.858927"/>
|
||||
<rect x="129.799" y="50.8133" width="106.757" height="106.635" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M236.261 104.331C236.738 101.203 236.985 98.0005 236.985 94.7401C236.985 59.8702 208.685 31.6025 173.776 31.6025C138.866 31.6025 110.566 59.8702 110.566 94.7401C110.566 129.61 138.866 157.878 173.776 157.878C176.901 157.878 179.973 157.651 182.977 157.213" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M182.978 157.154C186.108 157.63 189.315 157.878 192.579 157.878C227.489 157.878 255.788 129.61 255.788 94.7401C255.788 59.8702 227.489 31.6025 192.579 31.6025C157.669 31.6025 129.37 59.8702 129.37 94.7401C129.37 98.0005 129.617 101.203 130.094 104.331" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M129.634 104.33C129.196 107.331 128.969 110.4 128.969 113.521C128.969 148.391 157.269 176.659 192.179 176.659C227.088 176.659 255.388 148.391 255.388 113.521C255.388 78.6514 227.088 50.3838 192.179 50.3838C189.053 50.3838 185.981 50.6103 182.977 51.0479" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M182.977 51.0479C179.973 50.6103 176.901 50.3838 173.776 50.3838C138.866 50.3838 110.566 78.6514 110.566 113.521C110.566 148.391 138.866 176.659 173.776 176.659C208.685 176.659 236.985 148.391 236.985 113.521C236.985 110.4 236.758 107.331 236.32 104.33" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M236.585 50.7832L129.77 157.478" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M129.37 104.33H236.585" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M182.978 50.3838V157.877" stroke="#727272" stroke-width="0.858927"/>
|
||||
<ellipse cx="236.585" cy="104.331" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="236.585" cy="50.7838" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="236.585" cy="157.878" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="129.77" cy="157.878" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="182.977" cy="104.331" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="182.977" cy="50.7838" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="129.77" cy="104.331" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="129.77" cy="50.7838" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="182.977" cy="157.878" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<path d="M290.381 50.7812L397.197 157.476" stroke="#727272" stroke-width="0.858927"/>
|
||||
<rect x="290.41" y="50.8113" width="106.757" height="106.635" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M396.872 104.329C397.349 101.201 397.596 97.9986 397.596 94.7381C397.596 59.8682 369.297 31.6006 334.387 31.6006C299.478 31.6006 271.178 59.8682 271.178 94.7381C271.178 129.608 299.478 157.876 334.387 157.876C337.512 157.876 340.585 157.649 343.588 157.212" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M343.589 157.152C346.72 157.629 349.926 157.876 353.19 157.876C388.1 157.876 416.4 129.608 416.4 94.7381C416.4 59.8682 388.1 31.6006 353.19 31.6006C318.281 31.6006 289.981 59.8682 289.981 94.7381C289.981 97.9986 290.228 101.201 290.705 104.329" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M290.245 104.328C289.807 107.329 289.581 110.398 289.581 113.519C289.581 148.389 317.88 176.657 352.79 176.657C387.699 176.657 415.999 148.389 415.999 113.519C415.999 78.6495 387.699 50.3818 352.79 50.3818C349.665 50.3818 346.592 50.6084 343.589 51.046" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M343.588 51.046C340.585 50.6084 337.512 50.3818 334.387 50.3818C299.478 50.3818 271.178 78.6495 271.178 113.519C271.178 148.389 299.478 176.657 334.387 176.657C369.297 176.657 397.596 148.389 397.596 113.519C397.596 110.398 397.37 107.329 396.932 104.328" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M397.197 50.7812L290.381 157.476" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M289.981 104.328H397.197" stroke="#727272" stroke-width="0.858927"/>
|
||||
<path d="M343.589 50.3818V157.875" stroke="#727272" stroke-width="0.858927"/>
|
||||
<ellipse cx="397.197" cy="104.329" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="397.197" cy="50.7818" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="397.197" cy="157.876" rx="3.20048" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="290.381" cy="157.876" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="343.589" cy="104.329" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="343.589" cy="50.7818" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="290.381" cy="104.329" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="290.381" cy="50.7818" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
<ellipse cx="343.589" cy="157.876" rx="3.20047" ry="3.19684" fill="#EAEAEA"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 5.7 KiB |
@ -1,43 +0,0 @@
|
||||
<svg width="490" height="242" viewBox="0 0 490 242" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.5098 155.545C16.4625 163.027 18.0723 169.655 21.3393 175.432C24.6064 181.208 29.1282 185.73 34.9047 188.997C40.6812 192.264 47.3337 193.898 54.8621 193.898C63.2428 193.898 70.6765 191.838 77.1632 187.719C83.65 183.599 88.7399 177.989 92.4331 170.886C96.1263 163.784 97.9965 155.735 98.0439 146.739C98.0912 137.364 96.1026 129.196 92.078 122.236C88.1007 115.228 82.7977 109.807 76.1689 105.972C69.5875 102.089 62.3905 100.148 54.578 100.148C48.7541 100.148 43.4274 101.166 38.5979 103.202C33.7683 105.19 29.5306 107.866 25.8848 111.227H25.3166L32.703 51H93.2143" stroke="black" stroke-width="2"/>
|
||||
<ellipse cx="94.4026" cy="50.8894" rx="3.89381" ry="3.88938" fill="#121212"/>
|
||||
<ellipse cx="16.4026" cy="155.889" rx="3.89381" ry="3.88938" fill="#121212"/>
|
||||
<ellipse cx="32.4026" cy="50.8894" rx="3.89381" ry="3.88938" fill="#121212"/>
|
||||
<ellipse cx="25.4026" cy="110.889" rx="3.89381" ry="3.88938" fill="#121212"/>
|
||||
<path d="M151.592 59.1235L275.951 183.342" stroke="#E3E2E4"/>
|
||||
<rect x="151.626" y="59.1582" width="124.291" height="124.149" stroke="#E3E2E4"/>
|
||||
<path d="M275.573 121.465C276.129 117.824 276.417 114.095 276.417 110.299C276.417 69.7024 243.469 36.792 202.826 36.792C162.183 36.792 129.235 69.7024 129.235 110.299C129.235 150.897 162.183 183.807 202.826 183.807C206.465 183.807 210.041 183.543 213.539 183.034" stroke="#E3E2E4"/>
|
||||
<path d="M213.539 182.964C217.184 183.519 220.917 183.807 224.717 183.807C265.36 183.807 298.308 150.897 298.308 110.299C298.308 69.7024 265.36 36.792 224.717 36.792C184.074 36.792 151.126 69.7024 151.126 110.299C151.126 114.095 151.414 117.824 151.97 121.465" stroke="#E3E2E4"/>
|
||||
<path d="M151.434 121.465C150.924 124.958 150.66 128.531 150.66 132.166C150.66 172.763 183.608 205.673 224.251 205.673C264.894 205.673 297.842 172.763 297.842 132.166C297.842 91.5686 264.894 58.6582 224.251 58.6582C220.613 58.6582 217.036 58.922 213.539 59.4314" stroke="#E3E2E4"/>
|
||||
<path d="M213.539 59.4314C210.041 58.922 206.465 58.6582 202.826 58.6582C162.183 58.6582 129.235 91.5686 129.235 132.166C129.235 172.763 162.183 205.673 202.826 205.673C243.469 205.673 276.417 172.763 276.417 132.166C276.417 128.531 276.153 124.958 275.643 121.465" stroke="#E3E2E4"/>
|
||||
<path d="M275.951 59.1235L151.592 183.342" stroke="#E3E2E4"/>
|
||||
<path d="M151.126 121.465H275.951" stroke="#E3E2E4"/>
|
||||
<path d="M213.539 58.6582V183.807" stroke="#E3E2E4"/>
|
||||
<ellipse cx="275.951" cy="121.465" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="275.951" cy="59.1233" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="275.951" cy="183.807" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="151.592" cy="183.807" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="213.539" cy="121.465" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="213.539" cy="59.1233" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="151.592" cy="121.465" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="151.592" cy="59.1233" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="213.539" cy="183.807" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<path d="M338.583 59.1235L462.943 183.342" stroke="#E3E2E4"/>
|
||||
<rect x="338.617" y="59.1582" width="124.291" height="124.149" stroke="#E3E2E4"/>
|
||||
<path d="M462.565 121.465C463.12 117.824 463.408 114.095 463.408 110.299C463.408 69.7024 430.46 36.792 389.817 36.792C349.174 36.792 316.226 69.7024 316.226 110.299C316.226 150.897 349.174 183.807 389.817 183.807C393.456 183.807 397.033 183.543 400.53 183.034" stroke="#E3E2E4"/>
|
||||
<path d="M400.53 182.964C404.175 183.519 407.908 183.807 411.708 183.807C452.351 183.807 485.299 150.897 485.299 110.299C485.299 69.7024 452.351 36.792 411.708 36.792C371.065 36.792 338.117 69.7024 338.117 110.299C338.117 114.095 338.405 117.824 338.961 121.465" stroke="#E3E2E4"/>
|
||||
<path d="M338.425 121.465C337.915 124.958 337.651 128.531 337.651 132.166C337.651 172.763 370.599 205.673 411.242 205.673C451.886 205.673 484.833 172.763 484.833 132.166C484.833 91.5686 451.886 58.6582 411.242 58.6582C407.604 58.6582 404.027 58.922 400.53 59.4314" stroke="#E3E2E4"/>
|
||||
<path d="M400.53 59.4314C397.033 58.922 393.456 58.6582 389.817 58.6582C349.174 58.6582 316.226 91.5686 316.226 132.166C316.226 172.763 349.174 205.673 389.817 205.673C430.46 205.673 463.408 172.763 463.408 132.166C463.408 128.531 463.144 124.958 462.634 121.465" stroke="#E3E2E4"/>
|
||||
<path d="M462.943 59.1235L338.583 183.342" stroke="#E3E2E4"/>
|
||||
<path d="M338.117 121.465H462.943" stroke="#E3E2E4"/>
|
||||
<path d="M400.53 58.6582V183.807" stroke="#E3E2E4"/>
|
||||
<ellipse cx="462.942" cy="121.465" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="462.942" cy="59.1233" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="462.942" cy="183.807" rx="3.72614" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="338.583" cy="183.807" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="400.53" cy="121.465" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="400.53" cy="59.1233" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="338.583" cy="121.465" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="338.583" cy="59.1233" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
<ellipse cx="400.53" cy="183.807" rx="3.72613" ry="3.7219" fill="#121212"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 5.3 KiB |
@ -1,35 +1,97 @@
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
export const errorLayout = style({
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
gap: '20px',
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
});
|
||||
export const errorDetailStyle = style({
|
||||
export const errorContainer = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
maxWidth: '420px',
|
||||
});
|
||||
export const errorTitle = style({
|
||||
fontSize: '32px',
|
||||
lineHeight: '44px',
|
||||
fontWeight: 700,
|
||||
});
|
||||
export const errorImage = style({
|
||||
height: '178px',
|
||||
maxWidth: '400px',
|
||||
flexGrow: 1,
|
||||
backgroundSize: 'cover',
|
||||
});
|
||||
export const errorDescription = style({
|
||||
marginTop: '24px',
|
||||
});
|
||||
export const errorFooter = style({
|
||||
marginTop: '24px',
|
||||
});
|
||||
export const errorDivider = style({
|
||||
width: '20px',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
gap: '8px',
|
||||
padding: '16px',
|
||||
maxWidth: '400px',
|
||||
transition: 'max-width 0.3s ease-in-out',
|
||||
selectors: {
|
||||
'&[data-show-stack="true"]': {
|
||||
maxWidth: '600px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const label = style({
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
textWrap: 'wrap',
|
||||
wordBreak: 'break-word',
|
||||
});
|
||||
|
||||
export const scrollArea = style({
|
||||
height: 'auto',
|
||||
maxHeight: 0,
|
||||
transition: 'max-height 0.3s ease-in-out',
|
||||
color: cssVarV2('text/secondary'),
|
||||
fontSize: 14,
|
||||
lineHeight: '22px',
|
||||
fontWeight: 400,
|
||||
selectors: {
|
||||
'&[data-show-stack="true"]': {
|
||||
maxHeight: '200px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const illustration = style({
|
||||
maxWidth: '100%',
|
||||
width: 300,
|
||||
alignSelf: 'center',
|
||||
});
|
||||
|
||||
export const text = style({
|
||||
fontSize: 14,
|
||||
lineHeight: '22px',
|
||||
fontWeight: 400,
|
||||
color: cssVarV2('text/primary'),
|
||||
marginBottom: 4,
|
||||
});
|
||||
|
||||
export const actionContainer = style({
|
||||
display: 'flex',
|
||||
marginTop: '16px',
|
||||
width: '100%',
|
||||
gap: '32px',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
export const actionButton = style({
|
||||
padding: '4px 8px',
|
||||
fontSize: 12,
|
||||
minWidth: '120px',
|
||||
});
|
||||
|
||||
export const actionContent = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
export const arrowIcon = style({
|
||||
transition: 'transform 0.3s ease-in-out',
|
||||
marginLeft: '8px',
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
selectors: {
|
||||
'&[data-show-stack="true"]': {
|
||||
transform: 'rotate(180deg)',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Scrollable, ThemedImg } from '@affine/component';
|
||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { ArrowDownSmallIcon } from '@blocksuite/icons/rc';
|
||||
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import imageUrlFor404 from '../error-assets/404-status.assets.svg';
|
||||
import imageUrlForDark500 from '../error-assets/dark-500-status.assets.svg';
|
||||
import imageUrlForLight500 from '../error-assets/light-500-status.assets.svg';
|
||||
import { ActionButton } from '../../empty/action-button';
|
||||
import imageUrlForDark404 from '../error-assets/404.dark.png';
|
||||
import imageUrlForLight404 from '../error-assets/404.light.png';
|
||||
import imageUrlForDark500 from '../error-assets/500.dark.png';
|
||||
import imageUrlForLight500 from '../error-assets/500.light.png';
|
||||
import * as styles from './error-detail.css';
|
||||
|
||||
export enum ErrorStatus {
|
||||
@ -17,21 +19,20 @@ export enum ErrorStatus {
|
||||
|
||||
export interface ErrorDetailProps extends PropsWithChildren {
|
||||
status?: ErrorStatus;
|
||||
direction?: 'column' | 'row';
|
||||
title: string;
|
||||
description: ReactNode | Array<ReactNode>;
|
||||
buttonText?: string;
|
||||
onButtonClick?: () => void | Promise<void>;
|
||||
resetError?: () => void;
|
||||
withoutImage?: boolean;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
const imageMap = new Map([
|
||||
[
|
||||
ErrorStatus.NotFound,
|
||||
{
|
||||
light: imageUrlFor404, // TODO(@catsjuice): Ask designer for dark/light mode image.
|
||||
dark: imageUrlFor404,
|
||||
light: imageUrlForLight404,
|
||||
dark: imageUrlForDark404,
|
||||
},
|
||||
],
|
||||
[
|
||||
@ -49,16 +50,19 @@ const imageMap = new Map([
|
||||
export const ErrorDetail: FC<ErrorDetailProps> = props => {
|
||||
const {
|
||||
status = ErrorStatus.Unexpected,
|
||||
direction = 'row',
|
||||
description,
|
||||
onButtonClick,
|
||||
resetError,
|
||||
withoutImage,
|
||||
error,
|
||||
} = props;
|
||||
const descriptions = Array.isArray(description) ? description : [description];
|
||||
const [isBtnLoading, setBtnLoading] = useState(false);
|
||||
const [showStack, setShowStack] = useState(false);
|
||||
const t = useI18n();
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const onToggleStack = useCallback(() => {
|
||||
setShowStack(!showStack);
|
||||
}, [showStack]);
|
||||
|
||||
const onBtnClick = useAsyncCallback(async () => {
|
||||
try {
|
||||
@ -70,36 +74,62 @@ export const ErrorDetail: FC<ErrorDetailProps> = props => {
|
||||
}
|
||||
}, [onButtonClick, resetError]);
|
||||
|
||||
const desc = descriptions.map((item, i) => (
|
||||
<p key={i} className={styles.text}>
|
||||
{item}
|
||||
</p>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={styles.errorLayout} style={{ flexDirection: direction }}>
|
||||
<div className={styles.errorDetailStyle}>
|
||||
<h1 className={styles.errorTitle}>{props.title}</h1>
|
||||
{descriptions.map((item, i) => (
|
||||
<p key={i} className={styles.errorDescription}>
|
||||
{item}
|
||||
</p>
|
||||
))}
|
||||
<div className={styles.errorFooter}>
|
||||
<Button
|
||||
variant="primary"
|
||||
<div className={styles.errorLayout}>
|
||||
<div className={styles.errorContainer} data-show-stack={showStack}>
|
||||
<ThemedImg
|
||||
style={{ width: '300px' }}
|
||||
draggable={false}
|
||||
className={styles.illustration}
|
||||
lightSrc={imageMap.get(status)?.light || imageUrlForLight404}
|
||||
darkSrc={imageMap.get(status)?.dark || imageUrlForDark404}
|
||||
/>
|
||||
|
||||
<div className={styles.label}>
|
||||
<div className={styles.text}>{props.title}</div>
|
||||
<div className={styles.text}>{desc}</div>
|
||||
</div>
|
||||
<Scrollable.Root
|
||||
className={styles.scrollArea}
|
||||
data-show-stack={showStack}
|
||||
>
|
||||
<Scrollable.Viewport>
|
||||
{error?.stack || 'No detailed error stack is provided.'}
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
</Scrollable.Root>
|
||||
|
||||
<div className={styles.actionContainer}>
|
||||
{error?.stack ? (
|
||||
<ActionButton
|
||||
onClick={onToggleStack}
|
||||
className={styles.actionButton}
|
||||
>
|
||||
<div className={styles.actionContent}>
|
||||
<span>{t['com.affine.error.hide-error']()}</span>
|
||||
<ArrowDownSmallIcon
|
||||
data-show-stack={showStack}
|
||||
className={styles.arrowIcon}
|
||||
/>
|
||||
</div>
|
||||
</ActionButton>
|
||||
) : null}
|
||||
<ActionButton
|
||||
onClick={onBtnClick}
|
||||
className={styles.actionButton}
|
||||
loading={isBtnLoading}
|
||||
size="extraLarge"
|
||||
variant="primary"
|
||||
>
|
||||
{props.buttonText ?? t['com.affine.error.retry']()}
|
||||
</Button>
|
||||
{props.buttonText ?? t['com.affine.error.reload']()}
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
{withoutImage ? null : (
|
||||
<div
|
||||
className={styles.errorImage}
|
||||
style={{
|
||||
backgroundImage: `url(${
|
||||
imageMap.get(status)?.[resolvedTheme as 'light' | 'dark']
|
||||
})`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -24,6 +24,7 @@ export const AnyErrorFallback: FC<FallbackProps> = props => {
|
||||
description={
|
||||
'message' in (error as Error) ? (error as Error).message : `${error}`
|
||||
}
|
||||
error={error as Error}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
useNavigate,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import { AffineErrorComponent } from '../components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { NavigateContext } from '../components/hooks/use-navigate-helper';
|
||||
import { RootWrapper } from './pages/root';
|
||||
|
||||
@ -31,6 +32,7 @@ export function RootRouter() {
|
||||
export const topLevelRoutes = [
|
||||
{
|
||||
element: <RootRouter />,
|
||||
errorElement: <AffineErrorComponent />,
|
||||
children: [
|
||||
{
|
||||
path: '/',
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||
import { AffineErrorComponent } from '@affine/core/components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { PageNotFound } from '@affine/core/desktop/pages/404';
|
||||
import { MobileWorkbenchRoot } from '@affine/core/desktop/pages/workspace/workbench-root';
|
||||
@ -59,6 +60,7 @@ const warpedRoutes = workbenchRoutes.map((originalRoute: RouteObject) => {
|
||||
Component: () => {
|
||||
return <MobileRouteContainer route={route} />;
|
||||
},
|
||||
errorElement: <AffineErrorComponent />,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ResizePanel } from '@affine/component/resize-panel';
|
||||
import { AffineErrorComponent } from '@affine/core/components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { rightSidebarWidthAtom } from '@affine/core/components/atoms';
|
||||
import { workbenchRoutes } from '@affine/core/desktop/workbench-router';
|
||||
import {
|
||||
@ -29,6 +30,7 @@ const useAdapter = BUILD_CONFIG.isElectron
|
||||
const routes: RouteObject[] = [
|
||||
{
|
||||
element: <RouteContainer />,
|
||||
errorElement: <AffineErrorComponent />,
|
||||
children: workbenchRoutes,
|
||||
},
|
||||
];
|
||||
|
@ -687,7 +687,7 @@
|
||||
"com.affine.error.no-page-root.title": "محتوى المستند مفقود",
|
||||
"com.affine.error.page-not-found.title": "تحديث",
|
||||
"com.affine.error.refetch": "إعادة جلب",
|
||||
"com.affine.error.reload": "إعادة تحميل",
|
||||
"com.affine.error.reload": "AFFiNE إعادة تحميل",
|
||||
"com.affine.error.retry": "تحديث",
|
||||
"com.affine.error.unexpected-error.title": "هناك خطأ ما...",
|
||||
"com.affine.expired.page.subtitle": "يرجى طلب رابط إعادة تعيين كلمة المرور جديد.",
|
||||
|
@ -704,7 +704,8 @@
|
||||
"com.affine.error.no-page-root.title": "Doc content is missing",
|
||||
"com.affine.error.page-not-found.title": "Refresh",
|
||||
"com.affine.error.refetch": "Refetch",
|
||||
"com.affine.error.reload": "Reload",
|
||||
"com.affine.error.reload": "Reload AFFiNE",
|
||||
"com.affine.error.hide-error": "Hide error",
|
||||
"com.affine.error.retry": "Refresh",
|
||||
"com.affine.error.unexpected-error.title": "Something is wrong...",
|
||||
"com.affine.expired.page.subtitle": "Please request a new reset password link.",
|
||||
|
@ -674,7 +674,7 @@
|
||||
"com.affine.error.no-page-root.title": "Le contenu du document est manquant.",
|
||||
"com.affine.error.page-not-found.title": "Rafraichir",
|
||||
"com.affine.error.refetch": "Récupérer",
|
||||
"com.affine.error.reload": "Récupérer",
|
||||
"com.affine.error.reload": "Récupérer AFFiNE",
|
||||
"com.affine.error.retry": "Rafraichir",
|
||||
"com.affine.error.unexpected-error.title": "Quelque chose ne va pas...",
|
||||
"com.affine.expired.page.subtitle": "Merci de demander un nouveau lien pour réinitialiser votre mot de passe",
|
||||
|
@ -651,7 +651,7 @@
|
||||
"com.affine.error.no-page-root.title": "페이지 콘텐츠가 누락됨",
|
||||
"com.affine.error.page-not-found.title": "새로고침",
|
||||
"com.affine.error.refetch": "다시 가져오기",
|
||||
"com.affine.error.reload": "다시 로드",
|
||||
"com.affine.error.reload": "다시 로드 AFFiNE",
|
||||
"com.affine.error.retry": "새로고침",
|
||||
"com.affine.error.unexpected-error.title": "뭔가 잘못되었습니다...",
|
||||
"com.affine.expired.page.subtitle": "비밀번호 재설정 링크를 요청해 주세요.",
|
||||
|
@ -518,7 +518,7 @@
|
||||
"com.affine.error.no-page-root.title": "Conteúdo da página está faltando",
|
||||
"com.affine.error.page-not-found.title": "Atualizar",
|
||||
"com.affine.error.refetch": "Recarregar",
|
||||
"com.affine.error.reload": "Recarregar",
|
||||
"com.affine.error.reload": "Recarregar AFFiNE",
|
||||
"com.affine.error.retry": "Atualizar",
|
||||
"com.affine.error.unexpected-error.title": "Algo está errado...",
|
||||
"com.affine.expired.page.subtitle": "Por favor, solicite um novo link de redefinição de senha.",
|
||||
|
@ -691,7 +691,7 @@
|
||||
"com.affine.error.no-page-root.title": "Содержимое документа отсутствует",
|
||||
"com.affine.error.page-not-found.title": "Обновить",
|
||||
"com.affine.error.refetch": "Повторно получить данные",
|
||||
"com.affine.error.reload": "Перезагрузить",
|
||||
"com.affine.error.reload": "Перезагрузить AFFiNE",
|
||||
"com.affine.error.retry": "Обновить",
|
||||
"com.affine.error.unexpected-error.title": "Что-то не так...",
|
||||
"com.affine.expired.page.subtitle": "Пожалуйста, запросите новую ссылку для восстановления пароля.",
|
||||
|
@ -692,7 +692,8 @@
|
||||
"com.affine.error.no-page-root.title": "文档内容丢失",
|
||||
"com.affine.error.page-not-found.title": "刷新",
|
||||
"com.affine.error.refetch": "重新连接",
|
||||
"com.affine.error.reload": "重新加载",
|
||||
"com.affine.error.reload": "重新加载 AFFiNE",
|
||||
"com.affine.error.hide-error": "隐藏错误详情",
|
||||
"com.affine.error.retry": "刷新",
|
||||
"com.affine.error.unexpected-error.title": "出了点问题...",
|
||||
"com.affine.expired.page.subtitle": "请重新请求重置密码链接。",
|
||||
|