openvsx-webui-test 0.20.0-dev.5 → 0.20.2-dev.0
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/lib/components/scan-admin/scan-card/scan-card-expanded-content.d.ts +2 -1
- package/lib/components/scan-admin/scan-card/scan-card-expanded-content.d.ts.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-expanded-content.js.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-header.js +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-header.js.map +1 -1
- package/lib/components/scan-admin/scan-card/utils.js +1 -1
- package/lib/components/scan-admin/scan-card/utils.js.map +1 -1
- package/lib/components/sidepanel/navigation-item.d.ts +0 -1
- package/lib/components/sidepanel/navigation-item.d.ts.map +1 -1
- package/lib/components/sidepanel/navigation-item.js +22 -8
- package/lib/components/sidepanel/navigation-item.js.map +1 -1
- package/lib/components/sidepanel/sidebar-context.d.ts +16 -0
- package/lib/components/sidepanel/sidebar-context.d.ts.map +1 -0
- package/lib/components/sidepanel/sidebar-context.js +15 -0
- package/lib/components/sidepanel/sidebar-context.js.map +1 -0
- package/lib/components/sidepanel/sidepanel.d.ts +4 -4
- package/lib/components/sidepanel/sidepanel.d.ts.map +1 -1
- package/lib/components/sidepanel/sidepanel.js +47 -10
- package/lib/components/sidepanel/sidepanel.js.map +1 -1
- package/lib/default/menu-content.d.ts +1 -1
- package/lib/default/menu-content.js +1 -1
- package/lib/default/menu-content.js.map +1 -1
- package/lib/extension-registry-service.d.ts +6 -0
- package/lib/extension-registry-service.d.ts.map +1 -1
- package/lib/extension-registry-service.js +17 -0
- package/lib/extension-registry-service.js.map +1 -1
- package/lib/hooks/use-local-storage.d.ts +23 -0
- package/lib/hooks/use-local-storage.d.ts.map +1 -0
- package/lib/hooks/use-local-storage.js +62 -0
- package/lib/hooks/use-local-storage.js.map +1 -0
- package/lib/main.d.ts.map +1 -1
- package/lib/main.js +5 -5
- package/lib/main.js.map +1 -1
- package/lib/other-pages.d.ts.map +1 -1
- package/lib/other-pages.js +7 -7
- package/lib/other-pages.js.map +1 -1
- package/lib/pages/admin-dashboard/{admin-routes.d.ts → admin-dashboard-routes.d.ts} +6 -9
- package/lib/pages/admin-dashboard/admin-dashboard-routes.d.ts.map +1 -0
- package/lib/pages/admin-dashboard/{admin-routes.js → admin-dashboard-routes.js} +6 -9
- package/lib/pages/admin-dashboard/admin-dashboard-routes.js.map +1 -0
- package/lib/pages/admin-dashboard/admin-dashboard.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/admin-dashboard.js +45 -101
- package/lib/pages/admin-dashboard/admin-dashboard.js.map +1 -1
- package/lib/pages/admin-dashboard/admin-header.d.ts +19 -0
- package/lib/pages/admin-dashboard/admin-header.d.ts.map +1 -0
- package/lib/pages/admin-dashboard/admin-header.js +16 -0
- package/lib/pages/admin-dashboard/admin-header.js.map +1 -0
- package/lib/pages/admin-dashboard/admin-sidepanel.d.ts +19 -0
- package/lib/pages/admin-dashboard/admin-sidepanel.d.ts.map +1 -0
- package/lib/pages/admin-dashboard/admin-sidepanel.js +17 -0
- package/lib/pages/admin-dashboard/admin-sidepanel.js.map +1 -0
- package/lib/pages/admin-dashboard/customers/customer-member-list.js +1 -1
- package/lib/pages/admin-dashboard/customers/customer-member-list.js.map +1 -1
- package/lib/pages/admin-dashboard/customers/customers.js +1 -1
- package/lib/pages/admin-dashboard/customers/customers.js.map +1 -1
- package/lib/pages/admin-dashboard/namespace-admin.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/namespace-admin.js +4 -1
- package/lib/pages/admin-dashboard/namespace-admin.js.map +1 -1
- package/lib/pages/admin-dashboard/namespace-change-dialog.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/namespace-change-dialog.js +6 -1
- package/lib/pages/admin-dashboard/namespace-change-dialog.js.map +1 -1
- package/lib/pages/admin-dashboard/namespace-delete-dialog.d.ts +23 -0
- package/lib/pages/admin-dashboard/namespace-delete-dialog.d.ts.map +1 -0
- package/lib/pages/admin-dashboard/namespace-delete-dialog.js +53 -0
- package/lib/pages/admin-dashboard/namespace-delete-dialog.js.map +1 -0
- package/lib/pages/admin-dashboard/nav-types.d.ts +27 -0
- package/lib/pages/admin-dashboard/nav-types.d.ts.map +1 -0
- package/lib/pages/admin-dashboard/nav-types.js +14 -0
- package/lib/pages/admin-dashboard/nav-types.js.map +1 -0
- package/lib/pages/admin-dashboard/publisher-admin.js +1 -1
- package/lib/pages/admin-dashboard/publisher-admin.js.map +1 -1
- package/lib/pages/admin-dashboard/scan-admin.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/scan-admin.js +2 -5
- package/lib/pages/admin-dashboard/scan-admin.js.map +1 -1
- package/lib/pages/admin-dashboard/usage-stats/usage-stats.js +1 -1
- package/lib/pages/admin-dashboard/usage-stats/usage-stats.js.map +1 -1
- package/lib/pages/admin-dashboard/welcome.d.ts +5 -1
- package/lib/pages/admin-dashboard/welcome.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/welcome.js +18 -16
- package/lib/pages/admin-dashboard/welcome.js.map +1 -1
- package/lib/pages/extension-detail/extension-detail-routes.d.ts +0 -1
- package/lib/pages/extension-detail/extension-detail-routes.d.ts.map +1 -1
- package/lib/pages/extension-detail/extension-detail-routes.js +2 -3
- package/lib/pages/extension-detail/extension-detail-routes.js.map +1 -1
- package/lib/pages/extension-detail/extension-detail.d.ts.map +1 -1
- package/lib/pages/extension-detail/extension-detail.js +120 -249
- package/lib/pages/extension-detail/extension-detail.js.map +1 -1
- package/lib/pages/extension-detail/use-extension-details.d.ts +23 -0
- package/lib/pages/extension-detail/use-extension-details.d.ts.map +1 -0
- package/lib/pages/extension-detail/use-extension-details.js +80 -0
- package/lib/pages/extension-detail/use-extension-details.js.map +1 -0
- package/lib/pages/user/avatar.js +1 -1
- package/lib/pages/user/avatar.js.map +1 -1
- package/lib/pages/user/user-setting-tabs.d.ts.map +1 -1
- package/lib/pages/user/user-setting-tabs.js +1 -1
- package/lib/pages/user/user-setting-tabs.js.map +1 -1
- package/lib/pages/user/user-settings-namespace-detail.d.ts +1 -0
- package/lib/pages/user/user-settings-namespace-detail.d.ts.map +1 -1
- package/lib/pages/user/user-settings-namespace-detail.js +19 -3
- package/lib/pages/user/user-settings-namespace-detail.js.map +1 -1
- package/lib/pages/user/user-settings-namespaces.js.map +1 -1
- package/package.json +3 -1
- package/src/components/scan-admin/scan-card/scan-card-expanded-content.tsx +4 -4
- package/src/components/scan-admin/scan-card/scan-card-header.tsx +1 -1
- package/src/components/scan-admin/scan-card/utils.ts +1 -1
- package/src/components/sidepanel/navigation-item.tsx +79 -23
- package/src/components/sidepanel/sidebar-context.tsx +17 -0
- package/src/components/sidepanel/sidepanel.tsx +57 -29
- package/src/default/menu-content.tsx +1 -1
- package/src/extension-registry-service.ts +18 -0
- package/src/hooks/use-local-storage.ts +67 -0
- package/src/main.tsx +11 -6
- package/src/other-pages.tsx +20 -16
- package/src/pages/admin-dashboard/{admin-routes.ts → admin-dashboard-routes.ts} +5 -8
- package/src/pages/admin-dashboard/admin-dashboard.tsx +71 -216
- package/src/pages/admin-dashboard/admin-header.tsx +59 -0
- package/src/pages/admin-dashboard/admin-sidepanel.tsx +59 -0
- package/src/pages/admin-dashboard/customers/customer-member-list.tsx +1 -1
- package/src/pages/admin-dashboard/customers/customers.tsx +1 -1
- package/src/pages/admin-dashboard/namespace-admin.tsx +5 -0
- package/src/pages/admin-dashboard/namespace-change-dialog.tsx +55 -46
- package/src/pages/admin-dashboard/namespace-delete-dialog.tsx +89 -0
- package/src/pages/admin-dashboard/nav-types.ts +31 -0
- package/src/pages/admin-dashboard/publisher-admin.tsx +1 -1
- package/src/pages/admin-dashboard/scan-admin.tsx +2 -5
- package/src/pages/admin-dashboard/usage-stats/usage-stats.tsx +1 -1
- package/src/pages/admin-dashboard/welcome.tsx +80 -48
- package/src/pages/extension-detail/extension-detail-routes.ts +2 -3
- package/src/pages/extension-detail/extension-detail.tsx +290 -409
- package/src/pages/extension-detail/use-extension-details.tsx +101 -0
- package/src/pages/user/avatar.tsx +1 -1
- package/src/pages/user/user-setting-tabs.tsx +3 -2
- package/src/pages/user/user-settings-namespace-detail.tsx +38 -5
- package/src/pages/user/user-settings-namespaces.tsx +1 -1
- package/lib/pages/admin-dashboard/admin-routes.d.ts.map +0 -1
- package/lib/pages/admin-dashboard/admin-routes.js.map +0 -1
package/src/other-pages.tsx
CHANGED
|
@@ -11,25 +11,27 @@
|
|
|
11
11
|
* SPDX-License-Identifier: EPL-2.0
|
|
12
12
|
*****************************************************************************/
|
|
13
13
|
|
|
14
|
-
import { FunctionComponent, useContext, useEffect, useState } from 'react';
|
|
14
|
+
import { FunctionComponent, useContext, useEffect, useState, lazy, Suspense } from 'react';
|
|
15
15
|
import { Routes, Route } from 'react-router-dom';
|
|
16
16
|
import { AppBar, Box, Toolbar } from '@mui/material';
|
|
17
17
|
import { styled, Theme } from '@mui/material/styles';
|
|
18
18
|
import { Banner } from './components/banner';
|
|
19
19
|
import { MainContext } from './context';
|
|
20
20
|
import { HeaderMenu } from './header-menu';
|
|
21
|
-
import {
|
|
22
|
-
import { ExtensionListRoutes } from "./pages/extension-list/extension-list-routes";
|
|
23
|
-
import { UserSettings } from './pages/user/user-settings';
|
|
21
|
+
import { ExtensionListRoutes } from './pages/extension-list/extension-list-routes';
|
|
24
22
|
import { UserSettingsRoutes } from './pages/user/user-settings-routes';
|
|
25
|
-
import { NamespaceDetail } from './pages/namespace-detail/namespace-detail';
|
|
26
23
|
import { NamespaceDetailRoutes } from './pages/namespace-detail/namespace-detail-routes';
|
|
27
|
-
import { ExtensionDetail } from './pages/extension-detail/extension-detail';
|
|
28
24
|
import { ExtensionDetailRoutes } from './pages/extension-detail/extension-detail-routes';
|
|
29
25
|
import { getCookieValueByKey, setCookie } from './utils';
|
|
30
26
|
import { UserData } from './extension-registry-types';
|
|
27
|
+
|
|
28
|
+
import { ExtensionDetail } from './pages/extension-detail/extension-detail';
|
|
29
|
+
import { ExtensionListContainer } from './pages/extension-list/extension-list-container';
|
|
30
|
+
import { NamespaceDetail } from './pages/namespace-detail/namespace-detail';
|
|
31
31
|
import { NotFound } from './not-found';
|
|
32
32
|
|
|
33
|
+
const UserSettings = lazy(() => import('./pages/user/user-settings').then(m => ({ default: m.UserSettings })));
|
|
34
|
+
|
|
33
35
|
const ToolbarItem = styled(Box)({
|
|
34
36
|
display: 'flex',
|
|
35
37
|
alignItems: 'center'
|
|
@@ -122,16 +124,18 @@ export const OtherPages: FunctionComponent<OtherPagesProps> = (props) => {
|
|
|
122
124
|
: null
|
|
123
125
|
}
|
|
124
126
|
<Box pb={`${getContentPadding()}px`}>
|
|
125
|
-
<
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
127
|
+
<Suspense fallback={null}>
|
|
128
|
+
<Routes>
|
|
129
|
+
<Route path={ExtensionListRoutes.MAIN} element={ <ExtensionListContainer /> } />
|
|
130
|
+
<Route path={UserSettingsRoutes.MAIN} element={<UserSettings userLoading={props.userLoading} />} />
|
|
131
|
+
<Route path={UserSettingsRoutes.DELETE_EXTENSION} element={<UserSettings userLoading={props.userLoading} />} />
|
|
132
|
+
<Route path={NamespaceDetailRoutes.MAIN} element={ <NamespaceDetail /> } />
|
|
133
|
+
<Route path={ExtensionDetailRoutes.MAIN} element={<ExtensionDetail />} />
|
|
134
|
+
<Route path={ExtensionDetailRoutes.MAIN_TARGET} element={<ExtensionDetail />} />
|
|
135
|
+
{AdditionalRoutes ?? null}
|
|
136
|
+
<Route path='*' element={<NotFound />} />
|
|
137
|
+
</Routes>
|
|
138
|
+
</Suspense>
|
|
135
139
|
</Box>
|
|
136
140
|
{
|
|
137
141
|
FooterComponent ?
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (c)
|
|
3
|
-
*
|
|
4
|
-
* See the NOTICE file(s) distributed with this work for additional
|
|
5
|
-
* information regarding copyright ownership.
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2020 TypeFox and others
|
|
6
3
|
*
|
|
7
4
|
* This program and the accompanying materials are made available under the
|
|
8
|
-
* terms of the Eclipse Public License 2.0 which is available at
|
|
9
|
-
*
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
10
7
|
*
|
|
11
8
|
* SPDX-License-Identifier: EPL-2.0
|
|
12
|
-
|
|
9
|
+
********************************************************************************/
|
|
13
10
|
|
|
14
11
|
import { createRoute } from '../../utils';
|
|
15
12
|
|
|
@@ -8,95 +8,62 @@
|
|
|
8
8
|
* SPDX-License-Identifier: EPL-2.0
|
|
9
9
|
********************************************************************************/
|
|
10
10
|
|
|
11
|
-
import { FunctionComponent, ReactNode, useContext,
|
|
11
|
+
import { FunctionComponent, ReactNode, useContext, lazy, Suspense } from 'react';
|
|
12
12
|
import {
|
|
13
13
|
Box,
|
|
14
14
|
Container,
|
|
15
15
|
CssBaseline,
|
|
16
16
|
Typography,
|
|
17
17
|
IconButton,
|
|
18
|
-
Breadcrumbs,
|
|
19
|
-
LinkProps,
|
|
20
|
-
Link,
|
|
21
|
-
Toolbar
|
|
22
18
|
} from '@mui/material';
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
25
|
-
import { Link as RouterLink, Route, Routes, useNavigate, useLocation } from 'react-router-dom';
|
|
19
|
+
import { styled } from '@mui/material/styles';
|
|
20
|
+
import { Route, Routes, useNavigate } from 'react-router-dom';
|
|
26
21
|
import AccountBoxIcon from '@mui/icons-material/AccountBox';
|
|
27
22
|
import AssignmentIndIcon from '@mui/icons-material/AssignmentInd';
|
|
28
23
|
import BarChartIcon from '@mui/icons-material/BarChart';
|
|
29
24
|
import ExtensionSharpIcon from '@mui/icons-material/ExtensionSharp';
|
|
30
|
-
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
|
|
31
25
|
import HistoryIcon from '@mui/icons-material/History';
|
|
32
|
-
import MenuIcon from '@mui/icons-material/Menu';
|
|
33
26
|
import PeopleIcon from '@mui/icons-material/People';
|
|
34
27
|
import PersonIcon from '@mui/icons-material/Person';
|
|
35
28
|
import SecurityIcon from '@mui/icons-material/Security';
|
|
36
29
|
import SpeedIcon from '@mui/icons-material/Speed';
|
|
37
30
|
import StarIcon from '@mui/icons-material/Star';
|
|
38
|
-
import { CustomerDetails } from './customers/customer-details';
|
|
39
|
-
import { Customers } from './customers/customers';
|
|
40
|
-
import { DrawerHeader } from '../../components/sidepanel/drawer-header';
|
|
41
|
-
import { Sidepanel } from "../../components/sidepanel/sidepanel";
|
|
42
|
-
import { ExtensionAdmin } from './extension-admin';
|
|
43
31
|
import { LoginComponent } from "../../default/login";
|
|
44
|
-
import { Logs } from './logs/logs';
|
|
45
32
|
import { MainContext } from '../../context';
|
|
33
|
+
import { AdminDashboardRoutes } from './admin-dashboard-routes';
|
|
34
|
+
import { AdminSidepanel } from './admin-sidepanel';
|
|
35
|
+
import { AdminHeader } from './admin-header';
|
|
36
|
+
import { isNavGroup, NavEntry } from './nav-types';
|
|
37
|
+
|
|
46
38
|
import { NamespaceAdmin } from './namespace-admin';
|
|
47
|
-
import { NavigationItem } from '../../components/sidepanel/navigation-item';
|
|
48
39
|
import { PublisherAdmin } from './publisher-admin';
|
|
49
40
|
import { ScanAdmin } from './scan-admin';
|
|
50
41
|
import { Tiers } from './tiers/tiers';
|
|
51
|
-
import {
|
|
42
|
+
import { Customers } from './customers/customers';
|
|
43
|
+
import { CustomerDetails } from './customers/customer-details';
|
|
44
|
+
import { Logs } from './logs/logs';
|
|
52
45
|
import { Welcome } from './welcome';
|
|
53
|
-
import { AdminDashboardRoutes } from "./admin-routes";
|
|
54
|
-
|
|
55
|
-
const Message: FunctionComponent<{message: string}> = ({ message }) => {
|
|
56
|
-
return (<Box sx={{
|
|
57
|
-
display: 'flex',
|
|
58
|
-
justifyContent: 'center',
|
|
59
|
-
alignItems: 'center',
|
|
60
|
-
width: '100%'
|
|
61
|
-
}}>
|
|
62
|
-
<Typography variant='h6'>{message}</Typography>
|
|
63
|
-
</Box>);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
interface RouteEntry {
|
|
67
|
-
path: string;
|
|
68
|
-
name: string;
|
|
69
|
-
icon: ReactNode;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
interface NavGroup {
|
|
73
|
-
name: string;
|
|
74
|
-
icon: ReactNode;
|
|
75
|
-
children: RouteEntry[];
|
|
76
|
-
}
|
|
77
46
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const isNavGroup = (entry: NavEntry): entry is NavGroup => 'children' in entry;
|
|
47
|
+
const ExtensionAdmin = lazy(() => import('./extension-admin').then(m => ({ default: m.ExtensionAdmin })));
|
|
48
|
+
const UsageStatsView = lazy(() => import('./usage-stats/usage-stats').then(m => ({ default: m.UsageStatsView })));
|
|
81
49
|
|
|
82
50
|
const navConfig: NavEntry[] = [
|
|
83
|
-
{ path: AdminDashboardRoutes.NAMESPACE_ADMIN, name: 'Namespaces', icon: <AssignmentIndIcon
|
|
84
|
-
{ path: AdminDashboardRoutes.EXTENSION_ADMIN, name: 'Extensions', icon: <ExtensionSharpIcon
|
|
85
|
-
{ path: AdminDashboardRoutes.PUBLISHER_ADMIN, name: 'Publisher', icon: <PersonIcon
|
|
86
|
-
{ path: AdminDashboardRoutes.SCANS_ADMIN, name: 'Scans', icon: <SecurityIcon
|
|
51
|
+
{ path: AdminDashboardRoutes.NAMESPACE_ADMIN, name: 'Namespaces', icon: <AssignmentIndIcon />, description: 'Manage user roles and create new namespaces' },
|
|
52
|
+
{ path: AdminDashboardRoutes.EXTENSION_ADMIN, name: 'Extensions', icon: <ExtensionSharpIcon />, description: 'Search for extensions and remove certain versions' },
|
|
53
|
+
{ path: AdminDashboardRoutes.PUBLISHER_ADMIN, name: 'Publisher', icon: <PersonIcon />, description: 'Search for publishers and revoke their contributions' },
|
|
54
|
+
{ path: AdminDashboardRoutes.SCANS_ADMIN, name: 'Scans', icon: <SecurityIcon />, description: 'View security scan results and manage quarantined extensions' },
|
|
87
55
|
{
|
|
88
56
|
name: 'Rate Limiting',
|
|
89
57
|
icon: <SpeedIcon />,
|
|
90
58
|
children: [
|
|
91
|
-
{ path: AdminDashboardRoutes.TIERS, name: 'Tiers', icon: <StarIcon
|
|
92
|
-
{ path: AdminDashboardRoutes.CUSTOMERS, name: 'Customers', icon: <PeopleIcon
|
|
93
|
-
{ path: AdminDashboardRoutes.USAGE_STATS, name: 'Usage Stats', icon: <BarChartIcon
|
|
59
|
+
{ path: AdminDashboardRoutes.TIERS, name: 'Tiers', icon: <StarIcon />, description: 'Manage rate-limit tiers' },
|
|
60
|
+
{ path: AdminDashboardRoutes.CUSTOMERS, name: 'Customers', icon: <PeopleIcon />, description: 'Manage rate-limit customers' },
|
|
61
|
+
{ path: AdminDashboardRoutes.USAGE_STATS, name: 'Usage Stats', icon: <BarChartIcon />, description: 'Show usage stats for customers' },
|
|
94
62
|
],
|
|
95
63
|
},
|
|
96
|
-
{ path: AdminDashboardRoutes.LOGS, name: 'Logs', icon: <HistoryIcon
|
|
64
|
+
{ path: AdminDashboardRoutes.LOGS, name: 'Logs', icon: <HistoryIcon />, description: 'Browse admin activity logs' },
|
|
97
65
|
];
|
|
98
66
|
|
|
99
|
-
// Flat name lookup for breadcrumbs
|
|
100
67
|
const routeNames: { [key: string]: string } = {
|
|
101
68
|
[AdminDashboardRoutes.MAIN]: 'Admin Dashboard',
|
|
102
69
|
...navConfig.reduce<{ [key: string]: string }>((acc, entry) => {
|
|
@@ -111,183 +78,71 @@ const routeNames: { [key: string]: string } = {
|
|
|
111
78
|
}, {}),
|
|
112
79
|
};
|
|
113
80
|
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
transition: theme.transitions.create(['margin', 'width'], {
|
|
131
|
-
easing: theme.transitions.easing.easeOut,
|
|
132
|
-
duration: theme.transitions.duration.enteringScreen,
|
|
133
|
-
}),
|
|
134
|
-
}),
|
|
81
|
+
const ScrollableContent = styled(Box)(({ theme }) => ({
|
|
82
|
+
flex: 1,
|
|
83
|
+
overflowY: 'auto',
|
|
84
|
+
'&::-webkit-scrollbar': {
|
|
85
|
+
width: '12px',
|
|
86
|
+
},
|
|
87
|
+
'&::-webkit-scrollbar-track': {
|
|
88
|
+
backgroundColor: theme.palette.action.hover,
|
|
89
|
+
},
|
|
90
|
+
'&::-webkit-scrollbar-thumb': {
|
|
91
|
+
backgroundColor: theme.palette.action.selected,
|
|
92
|
+
borderRadius: '6px',
|
|
93
|
+
'&:hover': {
|
|
94
|
+
backgroundColor: theme.palette.action.focus,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
135
97
|
}));
|
|
136
98
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const BreadcrumbsComponent = () => {
|
|
147
|
-
const { pathname } = useLocation();
|
|
148
|
-
|
|
149
|
-
const pathnames = pathname.split("/").filter((segment) => segment);
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<Breadcrumbs aria-label='breadcrumb' sx={{ pt: 2, pb: 2, px: 4 }} >
|
|
153
|
-
<LinkRouter underline='hover' color='inherit' to='/'>
|
|
154
|
-
Home
|
|
155
|
-
</LinkRouter>
|
|
156
|
-
{pathnames.map((value, index) => {
|
|
157
|
-
const last = index === pathnames.length - 1;
|
|
158
|
-
const to = `/${pathnames.slice(0, index + 1).join("/")}`;
|
|
159
|
-
|
|
160
|
-
return last ? (
|
|
161
|
-
<Typography color='text.primary' key={to}>
|
|
162
|
-
{routeNames[to] ?? value}
|
|
163
|
-
</Typography>
|
|
164
|
-
) : (
|
|
165
|
-
<LinkRouter underline='hover' color='inherit' to={to} key={to}>
|
|
166
|
-
{routeNames[to]}
|
|
167
|
-
</LinkRouter>
|
|
168
|
-
);
|
|
169
|
-
})}
|
|
170
|
-
</Breadcrumbs>
|
|
171
|
-
);
|
|
99
|
+
const Message: FunctionComponent<{message: string}> = ({ message }) => {
|
|
100
|
+
return (<Box sx={{
|
|
101
|
+
display: 'flex',
|
|
102
|
+
justifyContent: 'center',
|
|
103
|
+
alignItems: 'center',
|
|
104
|
+
width: '100%'
|
|
105
|
+
}}>
|
|
106
|
+
<Typography variant='h6'>{message}</Typography>
|
|
107
|
+
</Box>);
|
|
172
108
|
};
|
|
173
109
|
|
|
174
|
-
const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })<{
|
|
175
|
-
open?: boolean;
|
|
176
|
-
}>(({ theme, open }) => ({
|
|
177
|
-
flexGrow: 1,
|
|
178
|
-
padding: theme.spacing(3),
|
|
179
|
-
transition: theme.transitions.create('margin', {
|
|
180
|
-
easing: theme.transitions.easing.sharp,
|
|
181
|
-
duration: theme.transitions.duration.leavingScreen,
|
|
182
|
-
}),
|
|
183
|
-
marginLeft: `-${drawerWidth}px`,
|
|
184
|
-
...(open && {
|
|
185
|
-
transition: theme.transitions.create('margin', {
|
|
186
|
-
easing: theme.transitions.easing.easeOut,
|
|
187
|
-
duration: theme.transitions.duration.enteringScreen,
|
|
188
|
-
}),
|
|
189
|
-
marginLeft: 0,
|
|
190
|
-
}),
|
|
191
|
-
}));
|
|
192
|
-
|
|
193
110
|
export const AdminDashboard: FunctionComponent<AdminDashboardProps> = props => {
|
|
194
111
|
const { user, loginProviders } = useContext(MainContext);
|
|
195
|
-
const [drawerOpen, setDrawerOpen] = useState(true);
|
|
196
112
|
|
|
197
113
|
const navigate = useNavigate();
|
|
198
114
|
const toMainPage = () => navigate('/');
|
|
199
115
|
|
|
200
|
-
const [currentPage, setCurrentPage] = useState<string | undefined>(useLocation().pathname);
|
|
201
|
-
const handleOpenRoute = (route: string) => {
|
|
202
|
-
setCurrentPage(route);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
116
|
let content: ReactNode = null;
|
|
206
117
|
if (user?.role === 'admin') {
|
|
207
118
|
content =
|
|
208
|
-
<Box sx={{ display: 'flex', width: '100%' }}>
|
|
119
|
+
<Box sx={{ display: 'flex', width: '100%', height: '100%' }}>
|
|
209
120
|
<CssBaseline />
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
<NavigationItem
|
|
233
|
-
key={entry.name}
|
|
234
|
-
label={entry.name}
|
|
235
|
-
icon={entry.icon}
|
|
236
|
-
>
|
|
237
|
-
{entry.children.map((child) => (
|
|
238
|
-
<NavigationItem key={child.path} onOpenRoute={handleOpenRoute} active={currentPage?.startsWith(child.path)}
|
|
239
|
-
label={child.name} icon={child.icon} route={child.path}/>
|
|
240
|
-
))}
|
|
241
|
-
</NavigationItem>
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
return (
|
|
245
|
-
<NavigationItem key={entry.path} onOpenRoute={handleOpenRoute} active={currentPage?.startsWith(entry.path)}
|
|
246
|
-
label={entry.name} icon={entry.icon} route={entry.path}/>
|
|
247
|
-
);
|
|
248
|
-
})}
|
|
249
|
-
</Sidepanel>
|
|
250
|
-
<Main open={drawerOpen} >
|
|
251
|
-
<DrawerHeader />
|
|
252
|
-
<Box
|
|
253
|
-
overflow='auto'
|
|
254
|
-
flex={1}
|
|
255
|
-
sx={{
|
|
256
|
-
overflowY: 'scroll',
|
|
257
|
-
'&::-webkit-scrollbar': {
|
|
258
|
-
width: '12px',
|
|
259
|
-
},
|
|
260
|
-
'&::-webkit-scrollbar-track': {
|
|
261
|
-
backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
|
262
|
-
},
|
|
263
|
-
'&::-webkit-scrollbar-thumb': {
|
|
264
|
-
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
265
|
-
borderRadius: '6px',
|
|
266
|
-
'&:hover': {
|
|
267
|
-
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
}}
|
|
271
|
-
>
|
|
272
|
-
<Container sx={{ pt: 2, pb: 4, px: 3 }} maxWidth='xl'>
|
|
273
|
-
<Routes>
|
|
274
|
-
<Route path='/namespaces' element={<NamespaceAdmin/>} />
|
|
275
|
-
<Route path='/extensions' element={<ExtensionAdmin/>} />
|
|
276
|
-
<Route path='/extensions/:namespace/:extension' element={<ExtensionAdmin/>} />
|
|
277
|
-
<Route path='/publisher' element={<PublisherAdmin/>} />
|
|
278
|
-
<Route path='/publisher/:publisher' element={<PublisherAdmin/>} />
|
|
279
|
-
<Route path='/scans' element={<ScanAdmin/>} />
|
|
280
|
-
<Route path='/tiers' element={<Tiers/>} />
|
|
281
|
-
<Route path='/customers' element={<Customers/>} />
|
|
282
|
-
<Route path='/customers/:customer' element={<CustomerDetails/>} />
|
|
283
|
-
<Route path='/usage' element={<UsageStatsView/>} />
|
|
284
|
-
<Route path='/usage/:customer' element={<UsageStatsView/>} />
|
|
285
|
-
<Route path='/logs' element={<Logs/>} />
|
|
286
|
-
<Route path='*' element={<Welcome/>} />
|
|
287
|
-
</Routes>
|
|
121
|
+
<AdminSidepanel items={navConfig} />
|
|
122
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', flex: 1, overflow: 'hidden' }}>
|
|
123
|
+
<AdminHeader routeNames={routeNames} onClose={toMainPage} />
|
|
124
|
+
<ScrollableContent>
|
|
125
|
+
<Container sx={{ pt: 3, pb: 4, px: 3 }} maxWidth='xl'>
|
|
126
|
+
<Suspense fallback={null}>
|
|
127
|
+
<Routes>
|
|
128
|
+
<Route path='/namespaces' element={<NamespaceAdmin/>} />
|
|
129
|
+
<Route path='/extensions' element={<ExtensionAdmin/>} />
|
|
130
|
+
<Route path='/extensions/:namespace/:extension' element={<ExtensionAdmin/>} />
|
|
131
|
+
<Route path='/publisher' element={<PublisherAdmin/>} />
|
|
132
|
+
<Route path='/publisher/:publisher' element={<PublisherAdmin/>} />
|
|
133
|
+
<Route path='/scans' element={<ScanAdmin/>} />
|
|
134
|
+
<Route path='/tiers' element={<Tiers/>} />
|
|
135
|
+
<Route path='/customers' element={<Customers/>} />
|
|
136
|
+
<Route path='/customers/:customer' element={<CustomerDetails/>} />
|
|
137
|
+
<Route path='/usage' element={<UsageStatsView/>} />
|
|
138
|
+
<Route path='/usage/:customer' element={<UsageStatsView/>} />
|
|
139
|
+
<Route path='/logs' element={<Logs/>} />
|
|
140
|
+
<Route path='*' element={<Welcome items={navConfig} />} />
|
|
141
|
+
</Routes>
|
|
142
|
+
</Suspense>
|
|
288
143
|
</Container>
|
|
289
|
-
</
|
|
290
|
-
</
|
|
144
|
+
</ScrollableContent>
|
|
145
|
+
</Box>
|
|
291
146
|
</Box>;
|
|
292
147
|
} else if (user) {
|
|
293
148
|
content = <Message message='You are not authorized as administrator.'/>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
|
|
3
|
+
*
|
|
4
|
+
* See the NOTICE file(s) distributed with this work for additional
|
|
5
|
+
* information regarding copyright ownership.
|
|
6
|
+
*
|
|
7
|
+
* This program and the accompanying materials are made available under the
|
|
8
|
+
* terms of the Eclipse Public License 2.0 which is available at
|
|
9
|
+
* https://www.eclipse.org/legal/epl-2.0.
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
12
|
+
*****************************************************************************/
|
|
13
|
+
|
|
14
|
+
import { FunctionComponent } from 'react';
|
|
15
|
+
import { AppBar, Breadcrumbs, IconButton, Link, Toolbar, Typography } from '@mui/material';
|
|
16
|
+
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
|
|
17
|
+
import { Link as RouterLink, useLocation } from 'react-router-dom';
|
|
18
|
+
|
|
19
|
+
export interface AdminHeaderProps {
|
|
20
|
+
routeNames: Record<string, string>;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const BreadcrumbsNav: FunctionComponent<{ routeNames: Record<string, string> }> = ({ routeNames }) => {
|
|
25
|
+
const { pathname } = useLocation();
|
|
26
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Breadcrumbs aria-label='breadcrumb' sx={{ pt: 2, pb: 2, px: 4 }}>
|
|
30
|
+
<Link component={RouterLink} to='/' underline='hover' color='inherit'>
|
|
31
|
+
Home
|
|
32
|
+
</Link>
|
|
33
|
+
{segments.map((value, index) => {
|
|
34
|
+
const to = `/${segments.slice(0, index + 1).join('/')}`;
|
|
35
|
+
const label = routeNames[to] ?? value;
|
|
36
|
+
const isLast = index === segments.length - 1;
|
|
37
|
+
|
|
38
|
+
return isLast ? (
|
|
39
|
+
<Typography color='text.primary' key={to}>{label}</Typography>
|
|
40
|
+
) : (
|
|
41
|
+
<Link component={RouterLink} to={to} underline='hover' color='inherit' key={to}>
|
|
42
|
+
{label}
|
|
43
|
+
</Link>
|
|
44
|
+
);
|
|
45
|
+
})}
|
|
46
|
+
</Breadcrumbs>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const AdminHeader: FunctionComponent<AdminHeaderProps> = ({ routeNames, onClose }) => (
|
|
51
|
+
<AppBar position='sticky' color='default' enableColorOnDark elevation={0}>
|
|
52
|
+
<Toolbar sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
53
|
+
<BreadcrumbsNav routeNames={routeNames} />
|
|
54
|
+
<IconButton onClick={onClose} aria-label='close admin dashboard' sx={{ mt: 1, mr: 1 }}>
|
|
55
|
+
<HighlightOffIcon />
|
|
56
|
+
</IconButton>
|
|
57
|
+
</Toolbar>
|
|
58
|
+
</AppBar>
|
|
59
|
+
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
|
|
3
|
+
*
|
|
4
|
+
* See the NOTICE file(s) distributed with this work for additional
|
|
5
|
+
* information regarding copyright ownership.
|
|
6
|
+
*
|
|
7
|
+
* This program and the accompanying materials are made available under the
|
|
8
|
+
* terms of the Eclipse Public License 2.0 which is available at
|
|
9
|
+
* https://www.eclipse.org/legal/epl-2.0.
|
|
10
|
+
*
|
|
11
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
12
|
+
*****************************************************************************/
|
|
13
|
+
|
|
14
|
+
import { FunctionComponent } from 'react';
|
|
15
|
+
import { useLocation } from 'react-router-dom';
|
|
16
|
+
import { Sidepanel } from '../../components/sidepanel/sidepanel';
|
|
17
|
+
import { NavigationItem } from '../../components/sidepanel/navigation-item';
|
|
18
|
+
import { isNavGroup, NavEntry } from './nav-types';
|
|
19
|
+
import { useLocalStorage } from '../../hooks/use-local-storage';
|
|
20
|
+
|
|
21
|
+
export interface AdminSidepanelProps {
|
|
22
|
+
items: NavEntry[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const AdminSidepanel: FunctionComponent<AdminSidepanelProps> = ({ items }) => {
|
|
26
|
+
const [open, setOpen] = useLocalStorage('openvsx-admin-sidepanel-open', true);
|
|
27
|
+
const { pathname } = useLocation();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Sidepanel open={open} onToggle={() => setOpen(prev => !prev)}>
|
|
31
|
+
{items.map((entry) => {
|
|
32
|
+
if (isNavGroup(entry)) {
|
|
33
|
+
return (
|
|
34
|
+
<NavigationItem key={entry.name} label={entry.name} icon={entry.icon}>
|
|
35
|
+
{entry.children.map((child) => (
|
|
36
|
+
<NavigationItem
|
|
37
|
+
key={child.path}
|
|
38
|
+
active={pathname.startsWith(child.path)}
|
|
39
|
+
label={child.name}
|
|
40
|
+
icon={child.icon}
|
|
41
|
+
route={child.path}
|
|
42
|
+
/>
|
|
43
|
+
))}
|
|
44
|
+
</NavigationItem>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return (
|
|
48
|
+
<NavigationItem
|
|
49
|
+
key={entry.path}
|
|
50
|
+
active={pathname.startsWith(entry.path)}
|
|
51
|
+
label={entry.name}
|
|
52
|
+
icon={entry.icon}
|
|
53
|
+
route={entry.path}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
})}
|
|
57
|
+
</Sidepanel>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
ListItemText, IconButton, type PaperProps, Paper
|
|
25
25
|
} from '@mui/material';
|
|
26
26
|
import { Link as RouterLink } from 'react-router-dom';
|
|
27
|
-
import { AdminDashboardRoutes } from '../admin-routes';
|
|
27
|
+
import { AdminDashboardRoutes } from '../admin-dashboard-routes';
|
|
28
28
|
import { MainContext } from '../../../context';
|
|
29
29
|
import { CustomerMembership, Customer, UserData, isError } from '../../../extension-registry-types';
|
|
30
30
|
import { AddUserDialog } from '../../user/add-user-dialog';
|
|
@@ -34,7 +34,7 @@ import { CustomerFormDialog } from "./customer-form-dialog";
|
|
|
34
34
|
import { DeleteCustomerDialog } from "./delete-customer-dialog";
|
|
35
35
|
import { createRoute, handleError } from "../../../utils";
|
|
36
36
|
import { createMultiSelectFilterOperators, createArrayContainsFilterOperators } from "../components";
|
|
37
|
-
import { AdminDashboardRoutes } from "../admin-routes";
|
|
37
|
+
import { AdminDashboardRoutes } from "../admin-dashboard-routes";
|
|
38
38
|
import { Link } from "react-router-dom";
|
|
39
39
|
|
|
40
40
|
export const Customers: FC = () => {
|
|
@@ -31,6 +31,10 @@ export const NamespaceAdmin: FunctionComponent = props => {
|
|
|
31
31
|
};
|
|
32
32
|
}, []);
|
|
33
33
|
|
|
34
|
+
const handleDeleteNamespace = () => {
|
|
35
|
+
setCurrentNamespace(undefined);
|
|
36
|
+
};
|
|
37
|
+
|
|
34
38
|
const fetchNamespace = async (namespaceName: string) => {
|
|
35
39
|
if (!namespaceName) {
|
|
36
40
|
setCurrentNamespace(undefined);
|
|
@@ -82,6 +86,7 @@ export const NamespaceAdmin: FunctionComponent = props => {
|
|
|
82
86
|
listContainer = <NamespaceDetailConfigContext.Provider value={{ defaultMemberRole: 'owner' }}>
|
|
83
87
|
<NamespaceDetail
|
|
84
88
|
setLoadingState={setLoading}
|
|
89
|
+
onDelete={handleDeleteNamespace}
|
|
85
90
|
namespace={currentNamespace}
|
|
86
91
|
filterUsers={() => true}
|
|
87
92
|
fixSelf={false}
|