@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.
Files changed (164) hide show
  1. package/.atlaspackrc +4 -0
  2. package/.eslintrc.json +19 -0
  3. package/CHANGELOG.md +12 -0
  4. package/dist/atlassian-dark-brand-refresh.91b786da.js +2 -0
  5. package/dist/atlassian-dark-brand-refresh.91b786da.js.map +1 -0
  6. package/dist/atlassian-dark-future.59ebadca.js +2 -0
  7. package/dist/atlassian-dark-future.59ebadca.js.map +1 -0
  8. package/dist/atlassian-dark-increased-contrast.ff6775f2.js +2 -0
  9. package/dist/atlassian-dark-increased-contrast.ff6775f2.js.map +1 -0
  10. package/dist/atlassian-dark.ad679134.js +2 -0
  11. package/dist/atlassian-dark.ad679134.js.map +1 -0
  12. package/dist/atlassian-legacy-dark.8aa27f7f.js +2 -0
  13. package/dist/atlassian-legacy-dark.8aa27f7f.js.map +1 -0
  14. package/dist/atlassian-legacy-light.2eb372ce.js +2 -0
  15. package/dist/atlassian-legacy-light.2eb372ce.js.map +1 -0
  16. package/dist/atlassian-light-brand-refresh.fadcab0a.js +2 -0
  17. package/dist/atlassian-light-brand-refresh.fadcab0a.js.map +1 -0
  18. package/dist/atlassian-light-future.612afe8a.js +2 -0
  19. package/dist/atlassian-light-future.612afe8a.js.map +1 -0
  20. package/dist/atlassian-light-increased-contrast.7161cd79.js +2 -0
  21. package/dist/atlassian-light-increased-contrast.7161cd79.js.map +1 -0
  22. package/dist/atlassian-light.bc343d4c.js +2 -0
  23. package/dist/atlassian-light.bc343d4c.js.map +1 -0
  24. package/dist/atlassian-shape.b92d69c0.js +2 -0
  25. package/dist/atlassian-shape.b92d69c0.js.map +1 -0
  26. package/dist/atlassian-spacing.60ddd8e7.js +2 -0
  27. package/dist/atlassian-spacing.60ddd8e7.js.map +1 -0
  28. package/dist/atlassian-typography-adg3.f88947f6.js +2 -0
  29. package/dist/atlassian-typography-adg3.f88947f6.js.map +1 -0
  30. package/dist/atlassian-typography-modernized.42016c51.js +2 -0
  31. package/dist/atlassian-typography-modernized.42016c51.js.map +1 -0
  32. package/dist/atlassian-typography-refreshed.ec0d111b.js +2 -0
  33. package/dist/atlassian-typography-refreshed.ec0d111b.js.map +1 -0
  34. package/dist/atlassian-typography.66d7e8f4.js +2 -0
  35. package/dist/atlassian-typography.66d7e8f4.js.map +1 -0
  36. package/dist/badge-light.7e55986a.png +0 -0
  37. package/dist/custom-theme.4680282a.js +2 -0
  38. package/dist/custom-theme.4680282a.js.map +1 -0
  39. package/dist/drag-handle.136830d3.js +2 -0
  40. package/dist/drag-handle.136830d3.js.map +1 -0
  41. package/dist/drag-handle.63bdb345.css +2 -0
  42. package/dist/drag-handle.63bdb345.css.map +1 -0
  43. package/dist/index.13289f53.js +28 -0
  44. package/dist/index.13289f53.js.map +1 -0
  45. package/dist/index.a41fafce.css +2 -0
  46. package/dist/index.a41fafce.css.map +1 -0
  47. package/dist/index.html +1 -0
  48. package/dist/index.runtime.3c39d71d.js +2 -0
  49. package/dist/index.runtime.3c39d71d.js.map +1 -0
  50. package/dist/refractor.2c1fd9a1.js +2 -0
  51. package/dist/refractor.2c1fd9a1.js.map +1 -0
  52. package/index.html +11 -0
  53. package/jest.config.js +16 -0
  54. package/package.json +64 -0
  55. package/src/APIError.test.ts +72 -0
  56. package/src/APIError.tsx +29 -0
  57. package/src/AppRoutes.tsx +56 -0
  58. package/src/hack-feature-flags.ts +6 -0
  59. package/src/main.tsx +50 -0
  60. package/src/test/stubCssModule.js +1 -0
  61. package/src/ui/App.module.css +122 -0
  62. package/src/ui/App.module.css.d.ts +8 -0
  63. package/src/ui/AppLayout/AppLayout.tsx +26 -0
  64. package/src/ui/AppLayout/SidebarNavigation/LinkItem.tsx +26 -0
  65. package/src/ui/AppLayout/SidebarNavigation/SidebarNavigation.tsx +45 -0
  66. package/src/ui/AppLayout/TopNavigation/Logo.module.css +12 -0
  67. package/src/ui/AppLayout/TopNavigation/Logo.module.css.d.ts +4 -0
  68. package/src/ui/AppLayout/TopNavigation/Logo.tsx +11 -0
  69. package/src/ui/AppLayout/TopNavigation/TopNavigation.module.css +14 -0
  70. package/src/ui/AppLayout/TopNavigation/TopNavigation.module.css.d.ts +3 -0
  71. package/src/ui/AppLayout/TopNavigation/TopNavigation.tsx +45 -0
  72. package/src/ui/AppLayout/TopNavigation/badge-light.png +0 -0
  73. package/src/ui/AppLayout/TopNavigation/logo-light.png +0 -0
  74. package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css +9 -0
  75. package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css.d.ts +3 -0
  76. package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.test.tsx +15 -0
  77. package/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.tsx +14 -0
  78. package/src/ui/app/StatsPage.tsx +77 -0
  79. package/src/ui/app/cache/CacheKeysIndexPage.tsx +13 -0
  80. package/src/ui/app/cache/CacheKeysPage.module.css +11 -0
  81. package/src/ui/app/cache/CacheKeysPage.module.css.d.ts +4 -0
  82. package/src/ui/app/cache/CacheKeysPage.tsx +23 -0
  83. package/src/ui/app/cache/[key]/CacheValuePage.tsx +40 -0
  84. package/src/ui/app/cache/ui/CacheKeyList.module.css +40 -0
  85. package/src/ui/app/cache/ui/CacheKeyList.module.css.d.ts +7 -0
  86. package/src/ui/app/cache/ui/CacheKeyList.tsx +187 -0
  87. package/src/ui/app/cache-invalidation/CacheInvalidationPage.tsx +22 -0
  88. package/src/ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage.tsx +22 -0
  89. package/src/ui/app/cache-invalidation/ui/CacheFileList.module.css +40 -0
  90. package/src/ui/app/cache-invalidation/ui/CacheFileList.module.css.d.ts +7 -0
  91. package/src/ui/app/cache-invalidation/ui/CacheFileList.tsx +185 -0
  92. package/src/ui/app/treemap/BottomPanelResizeState.test.ts +25 -0
  93. package/src/ui/app/treemap/BottomPanelResizeState.tsx +48 -0
  94. package/src/ui/app/treemap/FoamTreemapPage.module.css +24 -0
  95. package/src/ui/app/treemap/FoamTreemapPage.module.css.d.ts +6 -0
  96. package/src/ui/app/treemap/FoamTreemapPage.tsx +47 -0
  97. package/src/ui/app/treemap/controllers/RelatedBundlesController.tsx +41 -0
  98. package/src/ui/app/treemap/controllers/UrlFocusController.tsx +33 -0
  99. package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css +24 -0
  100. package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css.d.ts +5 -0
  101. package/src/ui/app/treemap/ui/BottomPanel/BottomPanel.tsx +24 -0
  102. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css +13 -0
  103. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css.d.ts +5 -0
  104. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.tsx +53 -0
  105. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/AssetTable.tsx +135 -0
  106. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css +7 -0
  107. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css.d.ts +3 -0
  108. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.tsx +123 -0
  109. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableModel.tsx +18 -0
  110. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css +20 -0
  111. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css.d.ts +6 -0
  112. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.tsx +79 -0
  113. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.test.ts +19 -0
  114. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.ts +24 -0
  115. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css +20 -0
  116. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css.d.ts +5 -0
  117. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.tsx +42 -0
  118. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css +29 -0
  119. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css.d.ts +6 -0
  120. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.tsx +107 -0
  121. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css +7 -0
  122. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css.d.ts +3 -0
  123. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.tsx +20 -0
  124. package/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/SourceCodeURL.tsx +5 -0
  125. package/src/ui/app/treemap/ui/BundleGraphRenderer.module.css +13 -0
  126. package/src/ui/app/treemap/ui/BundleGraphRenderer.module.css.d.ts +4 -0
  127. package/src/ui/app/treemap/ui/BundleGraphRenderer.tsx +95 -0
  128. package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css +6 -0
  129. package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css.d.ts +3 -0
  130. package/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.tsx +49 -0
  131. package/src/ui/app/treemap/ui/SigmaGraph.module.css +5 -0
  132. package/src/ui/app/treemap/ui/SigmaGraph.module.css.d.ts +3 -0
  133. package/src/ui/app/treemap/ui/SigmaGraph.tsx +80 -0
  134. package/src/ui/app/treemap/ui/Treemap.tsx +14 -0
  135. package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css +32 -0
  136. package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css.d.ts +5 -0
  137. package/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.tsx +24 -0
  138. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css +14 -0
  139. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css.d.ts +4 -0
  140. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.tsx +271 -0
  141. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css +15 -0
  142. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css.d.ts +4 -0
  143. package/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.tsx +111 -0
  144. package/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.test.ts +27 -0
  145. package/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.ts +21 -0
  146. package/src/ui/app/treemap/ui/TreemapRenderer/useMouseMoveController.ts +20 -0
  147. package/src/ui/globals.css +26 -0
  148. package/src/ui/globals.css.d.ts +1 -0
  149. package/src/ui/globals.d.ts +9 -0
  150. package/src/ui/model/ViewModel.test.ts +31 -0
  151. package/src/ui/model/ViewModel.ts +62 -0
  152. package/src/ui/not-found/NotFoundPage.module.css +7 -0
  153. package/src/ui/not-found/NotFoundPage.module.css.d.ts +3 -0
  154. package/src/ui/not-found/NotFoundPage.tsx +9 -0
  155. package/src/ui/types/Graph.tsx +12 -0
  156. package/src/ui/util/ErrorBoundary.module.css +3 -0
  157. package/src/ui/util/ErrorBoundary.module.css.d.ts +3 -0
  158. package/src/ui/util/ErrorBoundary.test.tsx +65 -0
  159. package/src/ui/util/ErrorBoundary.tsx +75 -0
  160. package/src/ui/util/colorPalette.tsx +122 -0
  161. package/src/ui/util/formatBytes.test.ts +13 -0
  162. package/src/ui/util/formatBytes.tsx +9 -0
  163. package/src/ui/util/getRandomDarkerColor.tsx +31 -0
  164. package/tsconfig.json +12 -0
package/index.html ADDED
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Atlaspack Inspector</title>
5
+ </head>
6
+ <body>
7
+ <div id="root"></div>
8
+
9
+ <script src="src/main.tsx" type="module"></script>
10
+ </body>
11
+ </html>
package/jest.config.js ADDED
@@ -0,0 +1,16 @@
1
+ const {createDefaultPreset} = require('ts-jest');
2
+
3
+ const tsJestTransformCfg = createDefaultPreset().transform;
4
+
5
+ /** @type {import("jest").Config} **/
6
+ module.exports = {
7
+ testEnvironment: 'jsdom',
8
+ transform: {
9
+ ...tsJestTransformCfg,
10
+ },
11
+ moduleNameMapper: {
12
+ '\\.css$': '<rootDir>/src/test/stubCssModule.js',
13
+ '\\.module\\.css$': '<rootDir>/src/test/stubCssModule.js',
14
+ },
15
+ collectCoverageFrom: ['src/**/*.tsx'],
16
+ };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@atlaspack/inspector-frontend",
3
+ "version": "0.1.1",
4
+ "license": "MIT",
5
+ "authors": [
6
+ "Pedro Tacla Yamada"
7
+ ],
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "scripts": {
12
+ "dev": "ATLASPACK_INSPECTOR_BACKEND_URL='http://localhost:3000' atlaspack serve --feature-flag cachePerformanceImprovements=true --cache-dir=.atlaspack-cache ./index.html",
13
+ "build:css-types": "rm -rf src/**/*.module.css.d.ts && tcm --namedExports ./src && prettier --write src/**/*.css.d.ts",
14
+ "lint": "oxlint",
15
+ "build": "yarn build:css-types && rm -rf .atlaspack-cache && rm -rf dist && ATLASPACK_INSPECTOR_BACKEND_URL='' atlaspack build --feature-flag cachePerformanceImprovements=false --cache-dir=.atlaspack-cache ./index.html",
16
+ "prepack": "yarn run build",
17
+ "test": "yarn test:unit",
18
+ "test:unit": "jest",
19
+ "typecheck": "tsc --noEmit"
20
+ },
21
+ "dependencies": {
22
+ "@atlaskit/app-provider": "^2.2.1",
23
+ "@atlaskit/code": "^17.2.2",
24
+ "@atlaskit/css-reset": "^7.3.2",
25
+ "@atlaskit/heading": "^5.2.1",
26
+ "@atlaskit/logo": "^19.0.1",
27
+ "@atlaskit/navigation-system": "^0.170.0",
28
+ "@atlaskit/primitives": "^14.8.4",
29
+ "@atlaskit/tabs": "^18.1.2",
30
+ "@atlaspack/cli": "2.14.13",
31
+ "@atlaspack/core": "2.25.1",
32
+ "@atlaspack/graph": "3.5.23",
33
+ "@carrotsearch/foamtree": "^3.5.2",
34
+ "@tanstack/react-query": "^5.81.5",
35
+ "@tanstack/react-virtual": "^3.13.12",
36
+ "axios": "^1.9.0",
37
+ "graphology": "^0.26.0",
38
+ "graphology-layout": "^0.6.1",
39
+ "graphology-layout-forceatlas2": "^0.10.1",
40
+ "graphology-types": "^0.24.8",
41
+ "mobx": "^6.13.7",
42
+ "mobx-react-lite": "^4.1.0",
43
+ "path-browserify": "^1.0.1",
44
+ "react": "^18.2.0",
45
+ "react-dom": "^18.2.0",
46
+ "react-router": "^7.6.0",
47
+ "sigma": "^3.0.1"
48
+ },
49
+ "browserslist": "Chrome 75",
50
+ "devDependencies": {
51
+ "@testing-library/dom": "^10.4.0",
52
+ "@testing-library/react": "^16.3.0",
53
+ "@testing-library/jest-dom": "^6.6.3",
54
+ "@types/react": "^18.2.0",
55
+ "@types/react-dom": "^18.2.0",
56
+ "eslint-config-react-app": "^7.0.1",
57
+ "jest": "^30.0.4",
58
+ "jest-environment-jsdom": "^30.0.4",
59
+ "oxlint": "^1.2.0",
60
+ "ts-jest": "^29.4.0",
61
+ "typed-css-modules": "^0.9.1"
62
+ },
63
+ "type": "commonjs"
64
+ }
@@ -0,0 +1,72 @@
1
+ import assert from 'assert';
2
+ import {AxiosError} from 'axios';
3
+
4
+ import {APIError} from './APIError';
5
+
6
+ /**
7
+ * Helper to create a minimal AxiosError-like object for testing purposes.
8
+ */
9
+ function createAxiosError(
10
+ method: string,
11
+ url: string,
12
+ status?: number,
13
+ statusText?: string,
14
+ data?: unknown,
15
+ cause?: Error,
16
+ ): AxiosError {
17
+ return {
18
+ name: 'AxiosError',
19
+ message: 'mock',
20
+ config: {method, url} as any,
21
+ response: status ? ({status, statusText, data} as any) : undefined,
22
+ cause,
23
+ isAxiosError: true,
24
+ toJSON() {
25
+ return {};
26
+ },
27
+ } as unknown as AxiosError;
28
+ }
29
+
30
+ describe('APIError', function () {
31
+ it('should create message including method, url, status, statusText and data', function () {
32
+ const axiosErr = createAxiosError(
33
+ 'get',
34
+ '/api/test',
35
+ 404,
36
+ 'Not Found',
37
+ 'Page not found',
38
+ );
39
+
40
+ const error = new APIError(axiosErr);
41
+
42
+ assert(
43
+ error.message.includes('GET /api/test 404 Not Found'),
44
+ 'Expected message to include HTTP method, url, and status',
45
+ );
46
+ assert(
47
+ error.message.includes('Page not found'),
48
+ 'Expected message to include response data',
49
+ );
50
+ assert(error instanceof Error);
51
+ assert(error instanceof APIError);
52
+ });
53
+
54
+ it('should include cause message when provided', function () {
55
+ const cause = new Error('connection closed');
56
+ const axiosErr = createAxiosError(
57
+ 'post',
58
+ '/api/submit',
59
+ 500,
60
+ 'Internal Server Error',
61
+ undefined,
62
+ cause,
63
+ );
64
+
65
+ const error = new APIError(axiosErr);
66
+
67
+ assert(
68
+ error.message.includes('connection closed'),
69
+ 'Expected error message to include cause',
70
+ );
71
+ });
72
+ });
@@ -0,0 +1,29 @@
1
+ import {AxiosError} from 'axios';
2
+
3
+ /**
4
+ * A custom error class for HTTP errors.
5
+ */
6
+ export class APIError extends Error {
7
+ constructor(err: AxiosError) {
8
+ const url = err.config?.url;
9
+ const method = err.config?.method;
10
+ const status = err.response?.status;
11
+ const statusText = err.response?.statusText;
12
+ const data = err.response?.data;
13
+ const cause = err.cause;
14
+
15
+ super(
16
+ `Failed to fetch: ${[
17
+ method?.toUpperCase(),
18
+ url,
19
+ status,
20
+ statusText,
21
+ cause?.message,
22
+ '\n',
23
+ JSON.stringify(data, null, 2),
24
+ ]
25
+ .filter(Boolean)
26
+ .join(' ')}`,
27
+ );
28
+ }
29
+ }
@@ -0,0 +1,56 @@
1
+ import {Routes, Route} from 'react-router';
2
+ import {Suspense} from 'react';
3
+
4
+ import {CacheValuePage} from './ui/app/cache/[key]/CacheValuePage';
5
+ import {CacheKeysIndexPage} from './ui/app/cache/CacheKeysIndexPage';
6
+ import {StatsPage} from './ui/app/StatsPage';
7
+ import {FoamTreemapPage} from './ui/app/treemap/FoamTreemapPage';
8
+ import {AppLayout} from './ui/AppLayout/AppLayout';
9
+ import {CacheKeysPage} from './ui/app/cache/CacheKeysPage';
10
+ import {CacheInvalidationPage} from './ui/app/cache-invalidation/CacheInvalidationPage';
11
+ import {NotFoundPage} from './ui/not-found/NotFoundPage';
12
+ import {ErrorBoundary} from './ui/util/ErrorBoundary';
13
+ import {DefaultLoadingIndicator} from './ui/DefaultLoadingIndicator/DefaultLoadingIndicator';
14
+ import {CacheInvalidationFilePage} from './ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage';
15
+
16
+ /**
17
+ * All the routes in the atlaspack-inspector app.
18
+ */
19
+ export default function AppRoutes() {
20
+ return (
21
+ <Suspense
22
+ fallback={
23
+ <DefaultLoadingIndicator message="Loading atlaspack-inspector..." />
24
+ }
25
+ >
26
+ <ErrorBoundary>
27
+ <Routes>
28
+ <Route path="/" element={<AppLayout />}>
29
+ <Route index element={<FoamTreemapPage />} />
30
+
31
+ <Route path="/app/cache-stats" element={<StatsPage />} />
32
+ <Route path="/app/cache" element={<CacheKeysPage />}>
33
+ <Route index element={<CacheKeysIndexPage />} />
34
+ <Route path="/app/cache/:key" element={<CacheValuePage />} />
35
+ </Route>
36
+
37
+ <Route
38
+ path="/app/cache-invalidation"
39
+ element={<CacheInvalidationPage />}
40
+ >
41
+ <Route index element={null} />
42
+ <Route
43
+ path="/app/cache-invalidation/:fileId"
44
+ element={<CacheInvalidationFilePage />}
45
+ />
46
+ </Route>
47
+
48
+ <Route path="/app/treemap" element={<FoamTreemapPage />} />
49
+
50
+ <Route path="*" element={<NotFoundPage />} />
51
+ </Route>
52
+ </Routes>
53
+ </ErrorBoundary>
54
+ </Suspense>
55
+ );
56
+ }
@@ -0,0 +1,6 @@
1
+ // @ts-expect-error
2
+ window.__PLATFORM_FEATURE_FLAGS__ = {
3
+ booleanResolver() {
4
+ return true;
5
+ },
6
+ };
package/src/main.tsx ADDED
@@ -0,0 +1,50 @@
1
+ import './hack-feature-flags';
2
+ import './ui/globals.css';
3
+ import {createRoot} from 'react-dom/client';
4
+ import {BrowserRouter} from 'react-router';
5
+ import {
6
+ QueryClient,
7
+ QueryClientProvider,
8
+ QueryFunction,
9
+ } from '@tanstack/react-query';
10
+ import axios, {AxiosError} from 'axios';
11
+
12
+ import AppRoutes from './AppRoutes';
13
+ import {APIError} from './APIError';
14
+
15
+ const defaultQueryFn: QueryFunction = async ({queryKey}) => {
16
+ const backendUrl = process.env.ATLASPACK_INSPECTOR_BACKEND_URL;
17
+ try {
18
+ const {data} = await axios.get(`${backendUrl}${queryKey[0]}`);
19
+ return data;
20
+ } catch (err) {
21
+ if (err instanceof AxiosError) {
22
+ throw new APIError(err);
23
+ }
24
+
25
+ throw err;
26
+ }
27
+ };
28
+
29
+ const queryClient = new QueryClient({
30
+ defaultOptions: {
31
+ queries: {
32
+ queryFn: defaultQueryFn,
33
+ },
34
+ },
35
+ });
36
+
37
+ const rootElement = document.getElementById('root');
38
+ if (!rootElement) {
39
+ throw new Error('Failed to find the root element');
40
+ }
41
+
42
+ const root = createRoot(rootElement);
43
+
44
+ root.render(
45
+ <QueryClientProvider client={queryClient}>
46
+ <BrowserRouter>
47
+ <AppRoutes />
48
+ </BrowserRouter>
49
+ </QueryClientProvider>,
50
+ );
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,122 @@
1
+ .app {
2
+ display: flex;
3
+ height: 100vh;
4
+ width: 100vw;
5
+
6
+ color: var(--color);
7
+ background-color: var(--background-color);
8
+
9
+ --background-color: rgb(255, 255, 255);
10
+ --color: rgb(0, 0, 0);
11
+ --border-color: #b8b8b8;
12
+ --base-spacing: 4px;
13
+ }
14
+
15
+ h1,
16
+ h2,
17
+ h3,
18
+ h4,
19
+ h5,
20
+ h6 {
21
+ margin: 0;
22
+ padding: 0;
23
+ }
24
+
25
+ .sidebar {
26
+ height: 100vh;
27
+ overflow-y: scroll;
28
+ /* width: 300px; */
29
+ border-right: 1px solid #434343;
30
+ display: flex;
31
+ flex-direction: column;
32
+ /* flex: 0 0 300px; */
33
+ }
34
+
35
+ .sidebar h1 {
36
+ padding: calc(var(--base-spacing) / 2) var(--base-spacing);
37
+ border-bottom: 1px solid var(--border-color);
38
+ }
39
+
40
+ .sidebar ul {
41
+ list-style: none;
42
+ padding: 0px;
43
+ margin: 0;
44
+ display: flex;
45
+ flex-direction: column;
46
+ }
47
+
48
+ .sidebar .sidebarItem {
49
+ padding: var(--base-spacing);
50
+ white-space: nowrap;
51
+ border-bottom: 1px solid var(--border-color);
52
+ text-overflow: ellipsis;
53
+ max-width: 100%;
54
+ overflow: hidden;
55
+ }
56
+
57
+ .sidebar .sidebarItem:hover {
58
+ background-color: var(--color);
59
+ color: var(--background-color);
60
+ }
61
+
62
+ .sidebar .sidebarItem a {
63
+ text-decoration: none;
64
+ color: inherit;
65
+ display: inline-block;
66
+ text-overflow: ellipsis;
67
+ height: 100%;
68
+ width: 100%;
69
+ overflow: hidden;
70
+ }
71
+
72
+ .sidebarFilter {
73
+ display: flex;
74
+ gap: calc(var(--base-spacing) * 2);
75
+ border-bottom: 1px solid var(--border-color);
76
+ padding: calc(var(--base-spacing) * 2) var(--base-spacing);
77
+ }
78
+
79
+ .sidebarFilter select {
80
+ flex: 1;
81
+ }
82
+
83
+ table {
84
+ border-collapse: collapse;
85
+ }
86
+
87
+ table td {
88
+ border: solid 1px var(--border-color);
89
+ margin: 0;
90
+ padding: calc(var(--base-spacing) / 2) var(--base-spacing);
91
+ }
92
+
93
+ .content {
94
+ flex: 1;
95
+ display: flex;
96
+ width: calc(100% - 300px);
97
+ overflow-x: scroll;
98
+ flex-direction: column;
99
+ gap: calc(var(--base-spacing) * 2);
100
+ min-height: 100%;
101
+ /* padding: calc(var(--base-spacing) / 2) var(--base-spacing); */
102
+ }
103
+
104
+ .contentInner {
105
+ min-height: 100%;
106
+ }
107
+
108
+ .treemapTable tr {
109
+ border-bottom: solid 1px var(--ds-border);
110
+ }
111
+
112
+ .treemapTable tr:focus-within {
113
+ background-color: #dbe7ff !important;
114
+ }
115
+
116
+ .treemapTable tr:nth-child(even) {
117
+ background-color: #e7e7e79b;
118
+ }
119
+
120
+ .treemapTable tr:hover {
121
+ background-color: var(--ds-background-neutral-hovered);
122
+ }
@@ -0,0 +1,8 @@
1
+ export const __esModule: true;
2
+ export const app: string;
3
+ export const content: string;
4
+ export const contentInner: string;
5
+ export const sidebar: string;
6
+ export const sidebarFilter: string;
7
+ export const sidebarItem: string;
8
+ export const treemapTable: string;
@@ -0,0 +1,26 @@
1
+ import '@atlaskit/css-reset';
2
+ import {Root as PageLayoutRoot} from '@atlaskit/navigation-system/layout/root';
3
+ import AppProvider from '@atlaskit/app-provider';
4
+ import {Main} from '@atlaskit/navigation-system';
5
+ import {Outlet} from 'react-router';
6
+ import {useState} from 'react';
7
+ import {TopNavigation} from './TopNavigation/TopNavigation';
8
+ import {SidebarNavigation} from './SidebarNavigation/SidebarNavigation';
9
+
10
+ export function AppLayout() {
11
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
12
+
13
+ return (
14
+ <AppProvider>
15
+ <PageLayoutRoot>
16
+ <TopNavigation setSidebarCollapsed={setSidebarCollapsed} />
17
+
18
+ {sidebarCollapsed ? null : <SidebarNavigation />}
19
+
20
+ <Main>
21
+ <Outlet />
22
+ </Main>
23
+ </PageLayoutRoot>
24
+ </AppProvider>
25
+ );
26
+ }
@@ -0,0 +1,26 @@
1
+ import {LinkMenuItem} from '@atlaskit/navigation-system';
2
+ import {useCallback} from 'react';
3
+ import {useNavigate} from 'react-router';
4
+
5
+ interface LinkItemProps {
6
+ href: string;
7
+ children: React.ReactNode;
8
+ elemBefore: React.ReactNode;
9
+ }
10
+
11
+ export function LinkItem({href, children, elemBefore}: LinkItemProps) {
12
+ const navigate = useNavigate();
13
+ const onClick = useCallback(
14
+ (e: React.MouseEvent<HTMLAnchorElement>) => {
15
+ e.preventDefault();
16
+ navigate(href);
17
+ },
18
+ [href, navigate],
19
+ );
20
+
21
+ return (
22
+ <LinkMenuItem href={href} onClick={onClick} elemBefore={elemBefore}>
23
+ {children}
24
+ </LinkMenuItem>
25
+ );
26
+ }
@@ -0,0 +1,45 @@
1
+ import '@atlaskit/css-reset';
2
+ import {
3
+ SideNav,
4
+ SideNavContent,
5
+ } from '@atlaskit/navigation-system/layout/side-nav';
6
+ import {PanelSplitter} from '@atlaskit/navigation-system';
7
+ import HomeIcon from '@atlaskit/icon/glyph/home';
8
+ import CacheData from '@atlaskit/icon/glyph/component';
9
+ import PageIcon from '@atlaskit/icon/glyph/page';
10
+ import {LinkItem} from './LinkItem';
11
+
12
+ export function SidebarNavigation() {
13
+ return (
14
+ <SideNav>
15
+ <SideNavContent>
16
+ <LinkItem elemBefore={<PageIcon label="Page" />} href="/">
17
+ Bundle size data
18
+ </LinkItem>
19
+
20
+ <LinkItem
21
+ elemBefore={<HomeIcon label="Home" />}
22
+ href="/app/cache-stats"
23
+ >
24
+ Cache statistics
25
+ </LinkItem>
26
+
27
+ <LinkItem
28
+ elemBefore={<CacheData label="Cache invalidation" />}
29
+ href="/app/cache-invalidation"
30
+ >
31
+ Cache invalidation
32
+ </LinkItem>
33
+
34
+ <LinkItem
35
+ elemBefore={<CacheData label="Cache data" />}
36
+ href="/app/cache"
37
+ >
38
+ Cache data
39
+ </LinkItem>
40
+ </SideNavContent>
41
+
42
+ <PanelSplitter label="Resize side nav" />
43
+ </SideNav>
44
+ );
45
+ }
@@ -0,0 +1,12 @@
1
+ .logo {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 8px;
5
+ }
6
+
7
+ .logoText {
8
+ color: var(--ds-text);
9
+ font-size: 20px;
10
+ font-weight: 600;
11
+ text-decoration: none !important;
12
+ }
@@ -0,0 +1,4 @@
1
+ export const __esModule: true;
2
+ export const logo: string;
3
+ export const logoText: string;
4
+
@@ -0,0 +1,11 @@
1
+ import atlaspackBadge from './badge-light.png';
2
+ import * as styles from './Logo.module.css';
3
+
4
+ export function Logo() {
5
+ return (
6
+ <div className={styles.logo}>
7
+ <img src={atlaspackBadge} alt="Atlaspack" />
8
+ <span className={styles.logoText}>Atlaspack</span>
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,14 @@
1
+ .logoContainer {
2
+ max-height: 48px;
3
+ display: flex;
4
+ align-items: center;
5
+ }
6
+
7
+ .logoContainer img {
8
+ height: calc(48px - 24px);
9
+ width: auto;
10
+ }
11
+
12
+ .logoContainer a {
13
+ text-decoration: none !important;
14
+ }
@@ -0,0 +1,3 @@
1
+ export const __esModule: true;
2
+ export const logoContainer: string;
3
+
@@ -0,0 +1,45 @@
1
+ import '@atlaskit/css-reset';
2
+ import {SideNavToggleButton} from '@atlaskit/navigation-system/layout/side-nav';
3
+ import {TopNav, TopNavStart} from '@atlaskit/navigation-system/layout/top-nav';
4
+ import {Link, useNavigate} from 'react-router';
5
+ import {useCallback} from 'react';
6
+ import {Logo} from './Logo';
7
+ import * as styles from './TopNavigation.module.css';
8
+
9
+ interface TopNavigationProps {
10
+ setSidebarCollapsed: (update: (collapsed: boolean) => boolean) => void;
11
+ }
12
+
13
+ export function TopNavigation({setSidebarCollapsed}: TopNavigationProps) {
14
+ const navigate = useNavigate();
15
+
16
+ const onClickLogo = useCallback(
17
+ (e: React.MouseEvent<HTMLAnchorElement>) => {
18
+ e.preventDefault();
19
+ navigate('/');
20
+ },
21
+ [navigate],
22
+ );
23
+ const onClickSideNavToggleButton = useCallback(() => {
24
+ setSidebarCollapsed((collapsed) => !collapsed);
25
+ }, [setSidebarCollapsed]);
26
+
27
+ return (
28
+ <TopNav>
29
+ <TopNavStart>
30
+ <SideNavToggleButton
31
+ defaultCollapsed={false}
32
+ expandLabel="Expand sidebar"
33
+ collapseLabel="Collapse sidebar"
34
+ onClick={onClickSideNavToggleButton}
35
+ />
36
+
37
+ <div className={styles.logoContainer}>
38
+ <Link to="/" onClick={onClickLogo}>
39
+ <Logo />
40
+ </Link>
41
+ </div>
42
+ </TopNavStart>
43
+ </TopNav>
44
+ );
45
+ }
@@ -0,0 +1,9 @@
1
+ .defaultLoadingIndicator {
2
+ display: flex;
3
+ padding-top: 100px;
4
+ flex-direction: column;
5
+ gap: 32px;
6
+ align-items: center;
7
+ height: 100%;
8
+ width: 100%;
9
+ }
@@ -0,0 +1,3 @@
1
+ export const __esModule: true;
2
+ export const defaultLoadingIndicator: string;
3
+
@@ -0,0 +1,15 @@
1
+ import '@testing-library/jest-dom';
2
+ import {render, screen} from '@testing-library/react';
3
+ import {DefaultLoadingIndicator} from './DefaultLoadingIndicator';
4
+
5
+ describe('DefaultLoadingIndicator', () => {
6
+ it('should render', () => {
7
+ render(<DefaultLoadingIndicator />);
8
+ expect(screen.getByText('Loading cache stats...')).toBeInTheDocument();
9
+ });
10
+
11
+ it('renders provided message', () => {
12
+ render(<DefaultLoadingIndicator message="Loading..." />);
13
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
14
+ });
15
+ });