@atlaspack/inspector-frontend 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.atlaspackrc +4 -0
- package/.eslintrc.json +19 -0
- package/CHANGELOG.md +12 -0
- package/dist/atlassian-dark-brand-refresh.91b786da.js +2 -0
- package/dist/atlassian-dark-brand-refresh.91b786da.js.map +1 -0
- package/dist/atlassian-dark-future.59ebadca.js +2 -0
- package/dist/atlassian-dark-future.59ebadca.js.map +1 -0
- package/dist/atlassian-dark-increased-contrast.ff6775f2.js +2 -0
- package/dist/atlassian-dark-increased-contrast.ff6775f2.js.map +1 -0
- package/dist/atlassian-dark.ad679134.js +2 -0
- package/dist/atlassian-dark.ad679134.js.map +1 -0
- package/dist/atlassian-legacy-dark.8aa27f7f.js +2 -0
- package/dist/atlassian-legacy-dark.8aa27f7f.js.map +1 -0
- package/dist/atlassian-legacy-light.2eb372ce.js +2 -0
- package/dist/atlassian-legacy-light.2eb372ce.js.map +1 -0
- package/dist/atlassian-light-brand-refresh.fadcab0a.js +2 -0
- package/dist/atlassian-light-brand-refresh.fadcab0a.js.map +1 -0
- package/dist/atlassian-light-future.612afe8a.js +2 -0
- package/dist/atlassian-light-future.612afe8a.js.map +1 -0
- package/dist/atlassian-light-increased-contrast.7161cd79.js +2 -0
- package/dist/atlassian-light-increased-contrast.7161cd79.js.map +1 -0
- package/dist/atlassian-light.bc343d4c.js +2 -0
- package/dist/atlassian-light.bc343d4c.js.map +1 -0
- package/dist/atlassian-shape.b92d69c0.js +2 -0
- package/dist/atlassian-shape.b92d69c0.js.map +1 -0
- package/dist/atlassian-spacing.60ddd8e7.js +2 -0
- package/dist/atlassian-spacing.60ddd8e7.js.map +1 -0
- package/dist/atlassian-typography-adg3.f88947f6.js +2 -0
- package/dist/atlassian-typography-adg3.f88947f6.js.map +1 -0
- package/dist/atlassian-typography-modernized.42016c51.js +2 -0
- package/dist/atlassian-typography-modernized.42016c51.js.map +1 -0
- package/dist/atlassian-typography-refreshed.ec0d111b.js +2 -0
- package/dist/atlassian-typography-refreshed.ec0d111b.js.map +1 -0
- package/dist/atlassian-typography.66d7e8f4.js +2 -0
- package/dist/atlassian-typography.66d7e8f4.js.map +1 -0
- package/dist/badge-light.7e55986a.png +0 -0
- package/dist/custom-theme.4680282a.js +2 -0
- package/dist/custom-theme.4680282a.js.map +1 -0
- package/dist/drag-handle.136830d3.js +2 -0
- package/dist/drag-handle.136830d3.js.map +1 -0
- package/dist/drag-handle.63bdb345.css +2 -0
- package/dist/drag-handle.63bdb345.css.map +1 -0
- package/dist/index.13289f53.js +28 -0
- package/dist/index.13289f53.js.map +1 -0
- package/dist/index.a41fafce.css +2 -0
- package/dist/index.a41fafce.css.map +1 -0
- package/dist/index.html +1 -0
- package/dist/index.runtime.3c39d71d.js +2 -0
- package/dist/index.runtime.3c39d71d.js.map +1 -0
- package/dist/refractor.2c1fd9a1.js +2 -0
- package/dist/refractor.2c1fd9a1.js.map +1 -0
- package/index.html +11 -0
- package/jest.config.js +16 -0
- package/package.json +64 -0
- package/src/APIError.test.ts +72 -0
- package/src/APIError.tsx +29 -0
- package/src/AppRoutes.tsx +56 -0
- package/src/hack-feature-flags.ts +6 -0
- package/src/main.tsx +50 -0
- package/src/test/stubCssModule.js +1 -0
- package/src/ui/App.module.css +122 -0
- package/src/ui/App.module.css.d.ts +8 -0
- package/src/ui/AppLayout/AppLayout.tsx +26 -0
- package/src/ui/AppLayout/SidebarNavigation/LinkItem.tsx +26 -0
- package/src/ui/AppLayout/SidebarNavigation/SidebarNavigation.tsx +45 -0
- package/src/ui/AppLayout/TopNavigation/Logo.module.css +12 -0
- package/src/ui/AppLayout/TopNavigation/Logo.module.css.d.ts +4 -0
- package/src/ui/AppLayout/TopNavigation/Logo.tsx +11 -0
- package/src/ui/AppLayout/TopNavigation/TopNavigation.module.css +14 -0
- package/src/ui/AppLayout/TopNavigation/TopNavigation.module.css.d.ts +3 -0
- package/src/ui/AppLayout/TopNavigation/TopNavigation.tsx +45 -0
- package/src/ui/AppLayout/TopNavigation/badge-light.png +0 -0
- package/src/ui/AppLayout/TopNavigation/logo-light.png +0 -0
- package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css +9 -0
- package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css.d.ts +3 -0
- package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.test.tsx +15 -0
- package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.tsx +14 -0
- package/src/ui/app/StatsPage.tsx +77 -0
- package/src/ui/app/cache/CacheKeysIndexPage.tsx +13 -0
- package/src/ui/app/cache/CacheKeysPage.module.css +11 -0
- package/src/ui/app/cache/CacheKeysPage.module.css.d.ts +4 -0
- package/src/ui/app/cache/CacheKeysPage.tsx +23 -0
- package/src/ui/app/cache/[key]/CacheValuePage.tsx +40 -0
- package/src/ui/app/cache/ui/CacheKeyList.module.css +40 -0
- package/src/ui/app/cache/ui/CacheKeyList.module.css.d.ts +7 -0
- package/src/ui/app/cache/ui/CacheKeyList.tsx +187 -0
- package/src/ui/app/cache-invalidation/CacheInvalidationPage.tsx +22 -0
- package/src/ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage.tsx +22 -0
- package/src/ui/app/cache-invalidation/ui/CacheFileList.module.css +40 -0
- package/src/ui/app/cache-invalidation/ui/CacheFileList.module.css.d.ts +7 -0
- package/src/ui/app/cache-invalidation/ui/CacheFileList.tsx +185 -0
- package/src/ui/app/treemap/BottomPanelResizeState.test.ts +25 -0
- package/src/ui/app/treemap/BottomPanelResizeState.tsx +48 -0
- package/src/ui/app/treemap/FoamTreemapPage.module.css +24 -0
- package/src/ui/app/treemap/FoamTreemapPage.module.css.d.ts +6 -0
- package/src/ui/app/treemap/FoamTreemapPage.tsx +47 -0
- package/src/ui/app/treemap/controllers/RelatedBundlesController.tsx +41 -0
- package/src/ui/app/treemap/controllers/UrlFocusController.tsx +33 -0
- package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css +24 -0
- package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css.d.ts +5 -0
- package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.tsx +24 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css +13 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css.d.ts +5 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.tsx +53 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/AssetTable.tsx +135 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css +7 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css.d.ts +3 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.tsx +123 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableModel.tsx +18 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css +20 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css.d.ts +6 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.tsx +79 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.test.ts +19 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.ts +24 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css +20 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css.d.ts +5 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.tsx +42 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css +29 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css.d.ts +6 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.tsx +107 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css +7 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css.d.ts +3 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.tsx +20 -0
- package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/SourceCodeURL.tsx +5 -0
- package/src/ui/app/treemap/ui/BundleGraphRenderer.module.css +13 -0
- package/src/ui/app/treemap/ui/BundleGraphRenderer.module.css.d.ts +4 -0
- package/src/ui/app/treemap/ui/BundleGraphRenderer.tsx +95 -0
- package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css +6 -0
- package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css.d.ts +3 -0
- package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.tsx +49 -0
- package/src/ui/app/treemap/ui/SigmaGraph.module.css +5 -0
- package/src/ui/app/treemap/ui/SigmaGraph.module.css.d.ts +3 -0
- package/src/ui/app/treemap/ui/SigmaGraph.tsx +80 -0
- package/src/ui/app/treemap/ui/Treemap.tsx +14 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css +32 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css.d.ts +5 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.tsx +24 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css +14 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css.d.ts +4 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.tsx +271 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css +15 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css.d.ts +4 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.tsx +111 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.test.ts +27 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.ts +21 -0
- package/src/ui/app/treemap/ui/TreemapRenderer/useMouseMoveController.ts +20 -0
- package/src/ui/globals.css +26 -0
- package/src/ui/globals.css.d.ts +1 -0
- package/src/ui/globals.d.ts +9 -0
- package/src/ui/model/ViewModel.test.ts +31 -0
- package/src/ui/model/ViewModel.ts +62 -0
- package/src/ui/not-found/NotFoundPage.module.css +7 -0
- package/src/ui/not-found/NotFoundPage.module.css.d.ts +3 -0
- package/src/ui/not-found/NotFoundPage.tsx +9 -0
- package/src/ui/types/Graph.tsx +12 -0
- package/src/ui/util/ErrorBoundary.module.css +3 -0
- package/src/ui/util/ErrorBoundary.module.css.d.ts +3 -0
- package/src/ui/util/ErrorBoundary.test.tsx +65 -0
- package/src/ui/util/ErrorBoundary.tsx +75 -0
- package/src/ui/util/colorPalette.tsx +122 -0
- package/src/ui/util/formatBytes.test.ts +13 -0
- package/src/ui/util/formatBytes.tsx +9 -0
- package/src/ui/util/getRandomDarkerColor.tsx +31 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Spinner from '@atlaskit/spinner';
|
|
2
|
+
import * as styles from './DefaultLoadingIndicator.module.css';
|
|
3
|
+
|
|
4
|
+
export function DefaultLoadingIndicator({message}: {message?: string}) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
className={styles.defaultLoadingIndicator}
|
|
8
|
+
data-testid="atlaspack-inspector-loading-indicator"
|
|
9
|
+
>
|
|
10
|
+
<Spinner size="xlarge" />
|
|
11
|
+
<h2>{message ?? 'Loading cache stats...'}</h2>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {useSuspenseQuery} from '@tanstack/react-query';
|
|
2
|
+
import {Box, Stack} from '@atlaskit/primitives';
|
|
3
|
+
|
|
4
|
+
import {formatBytes} from '../util/formatBytes';
|
|
5
|
+
|
|
6
|
+
export function StatsPage() {
|
|
7
|
+
const {data} = useSuspenseQuery<{
|
|
8
|
+
size: number;
|
|
9
|
+
keySize: number;
|
|
10
|
+
count: number;
|
|
11
|
+
assetContentCount: number;
|
|
12
|
+
assetContentSize: number;
|
|
13
|
+
assetMapCount: number;
|
|
14
|
+
assetMapSize: number;
|
|
15
|
+
}>({
|
|
16
|
+
queryKey: ['/api/stats'],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Box padding="space.100">
|
|
21
|
+
<Stack space="space.100">
|
|
22
|
+
<Box>
|
|
23
|
+
<h1>Atlaspack cache stats</h1>
|
|
24
|
+
</Box>
|
|
25
|
+
|
|
26
|
+
<table>
|
|
27
|
+
<tbody>
|
|
28
|
+
<tr>
|
|
29
|
+
<td>
|
|
30
|
+
<strong>Cache size</strong>
|
|
31
|
+
</td>
|
|
32
|
+
<td>{formatBytes(data.size)}</td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td>
|
|
36
|
+
<strong>Total size of all keys</strong>
|
|
37
|
+
</td>
|
|
38
|
+
<td>{formatBytes(data.keySize)}</td>
|
|
39
|
+
</tr>
|
|
40
|
+
<tr>
|
|
41
|
+
<td>
|
|
42
|
+
<strong>Number of cache entries</strong>
|
|
43
|
+
</td>
|
|
44
|
+
<td>{data.count}</td>
|
|
45
|
+
</tr>
|
|
46
|
+
|
|
47
|
+
<tr>
|
|
48
|
+
<td>
|
|
49
|
+
<strong>Number of asset content entries</strong>
|
|
50
|
+
</td>
|
|
51
|
+
<td>{data.assetContentCount}</td>
|
|
52
|
+
</tr>
|
|
53
|
+
<tr>
|
|
54
|
+
<td>
|
|
55
|
+
<strong>Total size of all asset content entries</strong>
|
|
56
|
+
</td>
|
|
57
|
+
<td>{formatBytes(data.assetContentSize)}</td>
|
|
58
|
+
</tr>
|
|
59
|
+
|
|
60
|
+
<tr>
|
|
61
|
+
<td>
|
|
62
|
+
<strong>Number of asset map entries</strong>
|
|
63
|
+
</td>
|
|
64
|
+
<td>{data.assetMapCount}</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td>
|
|
68
|
+
<strong>Total size of all asset map entries</strong>
|
|
69
|
+
</td>
|
|
70
|
+
<td>{formatBytes(data.assetMapSize)}</td>
|
|
71
|
+
</tr>
|
|
72
|
+
</tbody>
|
|
73
|
+
</table>
|
|
74
|
+
</Stack>
|
|
75
|
+
</Box>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function CacheKeysIndexPage() {
|
|
2
|
+
return (
|
|
3
|
+
<>
|
|
4
|
+
<p>
|
|
5
|
+
<strong>Click a cache key to view its contents</strong>
|
|
6
|
+
</p>
|
|
7
|
+
<p>
|
|
8
|
+
You can see all keys in the cache on your left. Click sorting button to
|
|
9
|
+
switch the sorting key.
|
|
10
|
+
</p>
|
|
11
|
+
</>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {Outlet} from 'react-router';
|
|
2
|
+
import {Box} from '@atlaskit/primitives';
|
|
3
|
+
import {Suspense} from 'react';
|
|
4
|
+
|
|
5
|
+
import {CacheKeyList} from './ui/CacheKeyList';
|
|
6
|
+
import {DefaultLoadingIndicator} from '../../DefaultLoadingIndicator/DefaultLoadingIndicator';
|
|
7
|
+
import * as styles from './CacheKeysPage.module.css';
|
|
8
|
+
|
|
9
|
+
export function CacheKeysPage() {
|
|
10
|
+
return (
|
|
11
|
+
<div className={styles.cacheKeysPage}>
|
|
12
|
+
<CacheKeyList />
|
|
13
|
+
|
|
14
|
+
<div className={styles.cacheKeysPageChild}>
|
|
15
|
+
<Box padding="space.200">
|
|
16
|
+
<Suspense fallback={<DefaultLoadingIndicator />}>
|
|
17
|
+
<Outlet />
|
|
18
|
+
</Suspense>
|
|
19
|
+
</Box>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {useParams} from 'react-router';
|
|
2
|
+
import {useSuspenseQuery} from '@tanstack/react-query';
|
|
3
|
+
import {Code, CodeBlock} from '@atlaskit/code';
|
|
4
|
+
import {Box, Inline, Stack} from '@atlaskit/primitives';
|
|
5
|
+
|
|
6
|
+
import {formatBytes} from '../../../util/formatBytes';
|
|
7
|
+
|
|
8
|
+
interface CacheValueResponse {
|
|
9
|
+
size: number;
|
|
10
|
+
value: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function CacheValuePage() {
|
|
14
|
+
const key = useParams().key;
|
|
15
|
+
if (!key) {
|
|
16
|
+
throw new Error('No key');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {data: cacheValue} = useSuspenseQuery<CacheValueResponse>({
|
|
20
|
+
queryKey: [`/api/cache-value/${encodeURIComponent(key)}`],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Stack space="space.100">
|
|
25
|
+
<Box>
|
|
26
|
+
<strong>Cache entry</strong>
|
|
27
|
+
</Box>
|
|
28
|
+
<Box>
|
|
29
|
+
<Code>{key}</Code>
|
|
30
|
+
</Box>
|
|
31
|
+
|
|
32
|
+
<Inline space="space.100">
|
|
33
|
+
<Box>Cache entry size</Box>
|
|
34
|
+
<Code>{formatBytes(cacheValue.size)}</Code>
|
|
35
|
+
</Inline>
|
|
36
|
+
|
|
37
|
+
<CodeBlock text={cacheValue.value} />
|
|
38
|
+
</Stack>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.cacheKeyList {
|
|
2
|
+
padding: 8px;
|
|
3
|
+
height: 100%;
|
|
4
|
+
gap: 8px;
|
|
5
|
+
display: flex;
|
|
6
|
+
background-color: var(--ds-surface-sunken);
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
border: 1px solid var(--ds-border);
|
|
9
|
+
width: 300px;
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cacheKeyListInner {
|
|
14
|
+
background-color: var(--ds-background-input);
|
|
15
|
+
padding: 4px;
|
|
16
|
+
border: 1px solid var(--ds-border);
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
flex: 1;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
gap: 4px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.cacheKeyPlaceholderContainer {
|
|
24
|
+
flex: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.cacheKeyListItemsContainer {
|
|
31
|
+
flex: 1;
|
|
32
|
+
height: 100%;
|
|
33
|
+
width: 100%;
|
|
34
|
+
overflow-y: auto;
|
|
35
|
+
position: relative;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cacheKeyListItemsContainerInner {
|
|
39
|
+
width: 100%;
|
|
40
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const __esModule: true;
|
|
2
|
+
export const cacheKeyList: string;
|
|
3
|
+
export const cacheKeyListInner: string;
|
|
4
|
+
export const cacheKeyListItemsContainer: string;
|
|
5
|
+
export const cacheKeyListItemsContainerInner: string;
|
|
6
|
+
export const cacheKeyPlaceholderContainer: string;
|
|
7
|
+
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {useNavigate, useSearchParams} from 'react-router';
|
|
2
|
+
import {useVirtualizer} from '@tanstack/react-virtual';
|
|
3
|
+
import {useEffect, useMemo, useRef} from 'react';
|
|
4
|
+
import {useInfiniteQuery} from '@tanstack/react-query';
|
|
5
|
+
import qs from 'qs';
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import Button, {LinkButton} from '@atlaskit/button/new';
|
|
8
|
+
import {Box} from '@atlaskit/primitives';
|
|
9
|
+
|
|
10
|
+
import * as styles from './CacheKeyList.module.css';
|
|
11
|
+
import * as appStyles from '../../../App.module.css';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The list of cache keys is an infinite paginated, virtualized list.
|
|
15
|
+
*
|
|
16
|
+
* That is because there might be a very large amount of keys to render.
|
|
17
|
+
*/
|
|
18
|
+
export function CacheKeyList() {
|
|
19
|
+
// sort by in querystring URL
|
|
20
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
21
|
+
const sortBy = searchParams.get('sortBy') || 'order';
|
|
22
|
+
const setSortBy = (value: string) => {
|
|
23
|
+
searchParams.set('sortBy', value);
|
|
24
|
+
setSearchParams(searchParams);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
data: cacheKeys,
|
|
29
|
+
isLoading,
|
|
30
|
+
error,
|
|
31
|
+
fetchNextPage,
|
|
32
|
+
isFetchingNextPage,
|
|
33
|
+
hasNextPage,
|
|
34
|
+
} = useInfiniteQuery<{
|
|
35
|
+
keys: string[];
|
|
36
|
+
count: number;
|
|
37
|
+
hasNextPage: boolean;
|
|
38
|
+
nextPageCursor: string | null;
|
|
39
|
+
}>({
|
|
40
|
+
queryFn: async ({pageParam}) => {
|
|
41
|
+
const backendUrl = process.env.ATLASPACK_INSPECTOR_BACKEND_URL;
|
|
42
|
+
const {data} = await axios.get(
|
|
43
|
+
`${backendUrl}/api/cache-keys/?` +
|
|
44
|
+
qs.stringify({sortBy, cursor: pageParam}),
|
|
45
|
+
);
|
|
46
|
+
return data;
|
|
47
|
+
},
|
|
48
|
+
queryKey: ['/api/cache-keys/?' + qs.stringify({sortBy})],
|
|
49
|
+
initialPageParam: null,
|
|
50
|
+
getNextPageParam: (lastPage) => lastPage.nextPageCursor,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const allKeys = useMemo(
|
|
54
|
+
() => cacheKeys?.pages.flatMap((page) => page.keys) ?? [],
|
|
55
|
+
[cacheKeys?.pages],
|
|
56
|
+
);
|
|
57
|
+
const lastPage = cacheKeys?.pages[cacheKeys.pages.length - 1];
|
|
58
|
+
const parentRef = useRef<HTMLDivElement>(null);
|
|
59
|
+
const rowVirtualizer = useVirtualizer({
|
|
60
|
+
count: lastPage?.hasNextPage ? allKeys.length + 1 : allKeys.length,
|
|
61
|
+
getScrollElement: () => parentRef.current,
|
|
62
|
+
estimateSize: () => 35,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const lastVirtualItem = virtualItems[virtualItems.length - 1];
|
|
68
|
+
const loaderRowIsShown =
|
|
69
|
+
allKeys[lastVirtualItem?.index] == null && lastPage?.hasNextPage;
|
|
70
|
+
|
|
71
|
+
if (hasNextPage && loaderRowIsShown && !isFetchingNextPage) {
|
|
72
|
+
fetchNextPage();
|
|
73
|
+
}
|
|
74
|
+
}, [
|
|
75
|
+
allKeys,
|
|
76
|
+
allKeys.length,
|
|
77
|
+
fetchNextPage,
|
|
78
|
+
hasNextPage,
|
|
79
|
+
isFetchingNextPage,
|
|
80
|
+
lastPage,
|
|
81
|
+
lastPage?.hasNextPage,
|
|
82
|
+
virtualItems,
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const navigate = useNavigate();
|
|
86
|
+
|
|
87
|
+
const renderItems = () => {
|
|
88
|
+
if (isLoading) {
|
|
89
|
+
return (
|
|
90
|
+
<div className={styles.cacheKeyPlaceholderContainer}>Loading...</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (error) {
|
|
95
|
+
return (
|
|
96
|
+
<div className={styles.cacheKeyPlaceholderContainer}>
|
|
97
|
+
Error: {error.message}
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!allKeys.length) {
|
|
103
|
+
return (
|
|
104
|
+
<div className={styles.cacheKeyPlaceholderContainer}>No cache keys</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className={styles.cacheKeyListItemsContainer} ref={parentRef}>
|
|
110
|
+
<div
|
|
111
|
+
className={styles.cacheKeyListItemsContainerInner}
|
|
112
|
+
style={{
|
|
113
|
+
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
{rowVirtualizer.getVirtualItems().map((virtualItem) => {
|
|
117
|
+
const key = allKeys[virtualItem.index];
|
|
118
|
+
const isLoaderRow = key == null && lastPage?.hasNextPage;
|
|
119
|
+
const rowStyle = {
|
|
120
|
+
position: 'absolute',
|
|
121
|
+
top: 0,
|
|
122
|
+
left: 0,
|
|
123
|
+
width: '100%',
|
|
124
|
+
height: `${virtualItem.size}px`,
|
|
125
|
+
transform: `translateY(${virtualItem.start}px)`,
|
|
126
|
+
} as const;
|
|
127
|
+
|
|
128
|
+
if (isLoaderRow) {
|
|
129
|
+
return (
|
|
130
|
+
<div
|
|
131
|
+
key="loader"
|
|
132
|
+
className={appStyles.sidebarItem}
|
|
133
|
+
style={rowStyle}
|
|
134
|
+
>
|
|
135
|
+
Loading...
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const href = `/app/cache/${encodeURIComponent(
|
|
140
|
+
key,
|
|
141
|
+
)}?${searchParams.toString()}`;
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<div
|
|
145
|
+
key={virtualItem.index}
|
|
146
|
+
className={appStyles.sidebarItem}
|
|
147
|
+
style={rowStyle}
|
|
148
|
+
>
|
|
149
|
+
<LinkButton
|
|
150
|
+
appearance="subtle"
|
|
151
|
+
href={href}
|
|
152
|
+
onClick={(e) => {
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
navigate(href);
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
{key}
|
|
158
|
+
</LinkButton>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
})}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<div className={styles.cacheKeyList}>
|
|
169
|
+
<Box>
|
|
170
|
+
<Button
|
|
171
|
+
appearance="subtle"
|
|
172
|
+
onClick={() => {
|
|
173
|
+
if (sortBy === 'order') {
|
|
174
|
+
setSortBy('size');
|
|
175
|
+
} else {
|
|
176
|
+
setSortBy('order');
|
|
177
|
+
}
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
Sorting by {sortBy}
|
|
181
|
+
</Button>
|
|
182
|
+
</Box>
|
|
183
|
+
|
|
184
|
+
<div className={styles.cacheKeyListInner}>{renderItems()}</div>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {CacheFileList} from './ui/CacheFileList';
|
|
2
|
+
import * as styles from '../cache/CacheKeysPage.module.css';
|
|
3
|
+
import {Box} from '@atlaskit/primitives';
|
|
4
|
+
import {DefaultLoadingIndicator} from '../../DefaultLoadingIndicator/DefaultLoadingIndicator';
|
|
5
|
+
import {Suspense} from 'react';
|
|
6
|
+
import {Outlet} from 'react-router';
|
|
7
|
+
|
|
8
|
+
export function CacheInvalidationPage() {
|
|
9
|
+
return (
|
|
10
|
+
<div className={styles.cacheKeysPage}>
|
|
11
|
+
<CacheFileList />
|
|
12
|
+
|
|
13
|
+
<div className={styles.cacheKeysPageChild}>
|
|
14
|
+
<Box padding="space.200">
|
|
15
|
+
<Suspense fallback={<DefaultLoadingIndicator />}>
|
|
16
|
+
<Outlet />
|
|
17
|
+
</Suspense>
|
|
18
|
+
</Box>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {useSuspenseQuery} from '@tanstack/react-query';
|
|
2
|
+
import {useParams} from 'react-router';
|
|
3
|
+
|
|
4
|
+
export function CacheInvalidationFilePage() {
|
|
5
|
+
const {fileId} = useParams();
|
|
6
|
+
|
|
7
|
+
if (!fileId) {
|
|
8
|
+
throw new Error('Invalid request, missing file ID');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const {data} = useSuspenseQuery({
|
|
12
|
+
queryKey: [`/api/cache-invalidation-files/${encodeURIComponent(fileId)}`],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div>
|
|
17
|
+
<h1>Cache invalidation file {fileId}</h1>
|
|
18
|
+
|
|
19
|
+
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.cacheFileList {
|
|
2
|
+
padding: 8px;
|
|
3
|
+
height: 100%;
|
|
4
|
+
gap: 8px;
|
|
5
|
+
display: flex;
|
|
6
|
+
background-color: var(--ds-surface-sunken);
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
border: 1px solid var(--ds-border);
|
|
9
|
+
width: 300px;
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cacheFileListInner {
|
|
14
|
+
background-color: var(--ds-background-input);
|
|
15
|
+
padding: 4px;
|
|
16
|
+
border: 1px solid var(--ds-border);
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
flex: 1;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
gap: 4px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.cacheFilePlaceholderContainer {
|
|
24
|
+
flex: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.cacheFileListItemsContainer {
|
|
31
|
+
flex: 1;
|
|
32
|
+
height: 100%;
|
|
33
|
+
width: 100%;
|
|
34
|
+
overflow-y: auto;
|
|
35
|
+
position: relative;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cacheFileListItemsContainerInner {
|
|
39
|
+
width: 100%;
|
|
40
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const __esModule: true;
|
|
2
|
+
export const cacheFileList: string;
|
|
3
|
+
export const cacheFileListInner: string;
|
|
4
|
+
export const cacheFileListItemsContainer: string;
|
|
5
|
+
export const cacheFileListItemsContainerInner: string;
|
|
6
|
+
export const cacheFilePlaceholderContainer: string;
|
|
7
|
+
|