openvsx-webui-test 0.19.0-dev.0 → 0.19.0-dev.2
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/error-dialog.d.ts.map +1 -1
- package/lib/components/error-dialog.js +3 -5
- package/lib/components/error-dialog.js.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-content.d.ts +3 -3
- package/lib/components/scan-admin/scan-card/scan-card-content.d.ts.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-content.js +146 -169
- package/lib/components/scan-admin/scan-card/scan-card-content.js.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-header.d.ts.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card-header.js +17 -5
- package/lib/components/scan-admin/scan-card/scan-card-header.js.map +1 -1
- package/lib/components/scan-admin/scan-card/scan-card.js +1 -1
- package/lib/components/scan-admin/scan-card/scan-card.js.map +1 -1
- package/lib/components/timestamp.d.ts +1 -0
- package/lib/components/timestamp.d.ts.map +1 -1
- package/lib/components/timestamp.js +3 -2
- package/lib/components/timestamp.js.map +1 -1
- package/lib/default/menu-content.d.ts +1 -4
- package/lib/default/menu-content.d.ts.map +1 -1
- package/lib/default/menu-content.js +8 -16
- package/lib/default/menu-content.js.map +1 -1
- package/lib/extension-registry-service.js +1 -1
- package/lib/extension-registry-service.js.map +1 -1
- package/lib/extension-registry-types.d.ts +2 -0
- package/lib/extension-registry-types.d.ts.map +1 -1
- package/lib/extension-registry-types.js.map +1 -1
- package/lib/hooks/scan-admin/use-query-params-state.d.ts +15 -0
- package/lib/hooks/scan-admin/use-query-params-state.d.ts.map +1 -0
- package/lib/hooks/scan-admin/use-query-params-state.js +44 -0
- package/lib/hooks/scan-admin/use-query-params-state.js.map +1 -0
- package/lib/pages/admin-dashboard/admin-dashboard.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/admin-dashboard.js +2 -2
- package/lib/pages/admin-dashboard/admin-dashboard.js.map +1 -1
- package/lib/pages/admin-dashboard/extension-admin.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/extension-admin.js +4 -3
- package/lib/pages/admin-dashboard/extension-admin.js.map +1 -1
- package/lib/pages/admin-dashboard/namespace-input.d.ts +1 -0
- package/lib/pages/admin-dashboard/namespace-input.d.ts.map +1 -1
- package/lib/pages/admin-dashboard/namespace-input.js +2 -2
- package/lib/pages/admin-dashboard/namespace-input.js.map +1 -1
- package/lib/pages/extension-detail/extension-detail-overview.js +1 -1
- package/lib/pages/extension-detail/extension-detail-overview.js.map +1 -1
- package/lib/pages/extension-detail/extension-review-dialog.d.ts.map +1 -1
- package/lib/pages/extension-detail/extension-review-dialog.js +2 -11
- package/lib/pages/extension-detail/extension-review-dialog.js.map +1 -1
- package/lib/pages/user/avatar.d.ts.map +1 -1
- package/lib/pages/user/avatar.js +9 -9
- package/lib/pages/user/avatar.js.map +1 -1
- package/lib/pages/user/logout.d.ts +3 -2
- package/lib/pages/user/logout.d.ts.map +1 -1
- package/lib/pages/user/logout.js +5 -4
- package/lib/pages/user/logout.js.map +1 -1
- package/lib/pages/user/user-settings-extensions.js +1 -1
- package/lib/pages/user/user-settings-extensions.js.map +1 -1
- package/lib/pages/user/user-settings-tokens.d.ts.map +1 -1
- package/lib/pages/user/user-settings-tokens.js +1 -1
- package/lib/pages/user/user-settings-tokens.js.map +1 -1
- package/lib/server-request.d.ts.map +1 -1
- package/lib/server-request.js +5 -1
- package/lib/server-request.js.map +1 -1
- package/lib/utils.d.ts +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +56 -22
- package/lib/utils.js.map +1 -1
- package/package.json +5 -4
- package/src/components/error-dialog.tsx +3 -5
- package/src/components/scan-admin/scan-card/scan-card-content.tsx +380 -408
- package/src/components/scan-admin/scan-card/scan-card-header.tsx +35 -6
- package/src/components/scan-admin/scan-card/scan-card.tsx +2 -2
- package/src/components/timestamp.tsx +3 -1
- package/src/default/menu-content.tsx +70 -96
- package/src/extension-registry-service.ts +1 -1
- package/src/extension-registry-types.ts +2 -0
- package/src/hooks/scan-admin/use-query-params-state.ts +55 -0
- package/src/pages/admin-dashboard/admin-dashboard.tsx +2 -1
- package/src/pages/admin-dashboard/extension-admin.tsx +4 -2
- package/src/pages/admin-dashboard/namespace-input.tsx +3 -1
- package/src/pages/extension-detail/extension-detail-overview.tsx +1 -1
- package/src/pages/extension-detail/extension-review-dialog.tsx +2 -12
- package/src/pages/user/avatar.tsx +30 -35
- package/src/pages/user/logout.tsx +6 -4
- package/src/pages/user/user-settings-extensions.tsx +1 -1
- package/src/pages/user/user-settings-tokens.tsx +1 -0
- package/src/server-request.ts +5 -1
- package/src/utils.ts +47 -19
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
********************************************************************************/
|
|
13
13
|
|
|
14
14
|
import { FC, useState } from 'react';
|
|
15
|
-
import { Box, Typography, Chip, CircularProgress } from '@mui/material';
|
|
15
|
+
import { Box, Typography, Chip, CircularProgress, Link } from '@mui/material';
|
|
16
16
|
import {
|
|
17
|
+
AdminPanelSettings as AdminPanelIcon,
|
|
17
18
|
CheckCircle as CheckCircleIcon,
|
|
18
19
|
GppMaybe as WarningIcon,
|
|
19
20
|
Block as BlockIcon,
|
|
@@ -30,6 +31,9 @@ import {
|
|
|
30
31
|
getHypotheticalStatus,
|
|
31
32
|
getStatusColorSx,
|
|
32
33
|
} from './utils';
|
|
34
|
+
import { createRoute } from '../../../utils';
|
|
35
|
+
import { AdminDashboardRoutes } from '../../../pages/admin-dashboard/admin-dashboard';
|
|
36
|
+
import { ExtensionDetailRoutes } from '../../../pages/extension-detail/extension-detail';
|
|
33
37
|
|
|
34
38
|
interface ScanCardHeaderProps {
|
|
35
39
|
scan: ScanResult;
|
|
@@ -61,6 +65,12 @@ export const ScanCardHeader: FC<ScanCardHeaderProps> = ({ scan }) => {
|
|
|
61
65
|
const [imageError, setImageError] = useState(false);
|
|
62
66
|
|
|
63
67
|
const hasValidIcon = scan.extensionIcon && !imageError;
|
|
68
|
+
const extensionRoute = createRoute([ExtensionDetailRoutes.ROOT, scan.namespace, scan.extensionName]);
|
|
69
|
+
const adminRoute = createRoute([AdminDashboardRoutes.ROOT, 'extensions'],
|
|
70
|
+
[
|
|
71
|
+
{ key: "namespace", value: scan.namespace },
|
|
72
|
+
{ key: "extension", value: scan.extensionName }
|
|
73
|
+
]);
|
|
64
74
|
|
|
65
75
|
return (
|
|
66
76
|
<>
|
|
@@ -97,8 +107,8 @@ export const ScanCardHeader: FC<ScanCardHeaderProps> = ({ scan }) => {
|
|
|
97
107
|
)}
|
|
98
108
|
</Box>
|
|
99
109
|
|
|
100
|
-
{/* Columns 2-
|
|
101
|
-
<Box sx={{ gridRow: '1', gridColumn: '
|
|
110
|
+
{/* Columns 2-5: Display Name and Namespace */}
|
|
111
|
+
<Box sx={{ gridRow: '1', gridColumn: 'span 4', minWidth: 0 }}>
|
|
102
112
|
<ConditionalTooltip title={scan.displayName} arrow>
|
|
103
113
|
<Typography
|
|
104
114
|
variant='h6'
|
|
@@ -122,15 +132,34 @@ export const ScanCardHeader: FC<ScanCardHeaderProps> = ({ scan }) => {
|
|
|
122
132
|
whiteSpace: 'nowrap',
|
|
123
133
|
}}
|
|
124
134
|
>
|
|
125
|
-
|
|
135
|
+
<Link
|
|
136
|
+
href={extensionRoute || undefined}
|
|
137
|
+
rel='noopener noreferrer'
|
|
138
|
+
variant='body2'
|
|
139
|
+
>
|
|
140
|
+
{scan.namespace}.{scan.extensionName}
|
|
141
|
+
</Link>
|
|
142
|
+
|
|
143
|
+
{adminRoute !== undefined &&
|
|
144
|
+
<Link
|
|
145
|
+
href={adminRoute}
|
|
146
|
+
rel='noopener noreferrer'
|
|
147
|
+
variant='body2'
|
|
148
|
+
>
|
|
149
|
+
<AdminPanelIcon sx={{
|
|
150
|
+
verticalAlign: 'bottom',
|
|
151
|
+
ml: '3px'
|
|
152
|
+
}} />
|
|
153
|
+
</Link>
|
|
154
|
+
}
|
|
126
155
|
</Typography>
|
|
127
156
|
</ConditionalTooltip>
|
|
128
157
|
</Box>
|
|
129
158
|
|
|
130
|
-
{/* Column
|
|
159
|
+
{/* Column 6: Status Badge */}
|
|
131
160
|
<Box sx={{
|
|
132
161
|
gridRow: '1',
|
|
133
|
-
gridColumn: '
|
|
162
|
+
gridColumn: '6',
|
|
134
163
|
display: 'flex',
|
|
135
164
|
flexDirection: 'column',
|
|
136
165
|
alignItems: 'flex-end',
|
|
@@ -110,10 +110,10 @@ export const ScanCard: FunctionComponent<ScanCardProps> = ({
|
|
|
110
110
|
'&:last-child': { pb: showExpandButton ? 0 : 5 },
|
|
111
111
|
}}
|
|
112
112
|
>
|
|
113
|
-
{/* 3 Row x
|
|
113
|
+
{/* 3 Row x 6 Column Grid Layout */}
|
|
114
114
|
<Box sx={{
|
|
115
115
|
display: 'grid',
|
|
116
|
-
gridTemplateColumns: `${ICON_SIZE}px 1fr 1fr 1fr 180px`,
|
|
116
|
+
gridTemplateColumns: `${ICON_SIZE}px 1fr 1fr 1fr 1fr 180px`,
|
|
117
117
|
gridTemplateRows: 'auto auto auto',
|
|
118
118
|
gap: 2,
|
|
119
119
|
alignItems: 'start',
|
|
@@ -15,16 +15,18 @@ import { toRelativeTime, toLocalTime } from '../utils';
|
|
|
15
15
|
|
|
16
16
|
export const Timestamp: FunctionComponent<TimestampProps> = props => {
|
|
17
17
|
const sx = props.sx ?? [];
|
|
18
|
+
const isFutureTime = props.isFutureTime ?? false;
|
|
18
19
|
const timestamp = props.value;
|
|
19
20
|
return <Box
|
|
20
21
|
component='span'
|
|
21
22
|
title={toLocalTime(timestamp)}
|
|
22
23
|
sx={[...(Array.isArray(sx) ? sx : [sx])]}>
|
|
23
|
-
{toRelativeTime(timestamp)}
|
|
24
|
+
{toRelativeTime(timestamp, isFutureTime)}
|
|
24
25
|
</Box>;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export interface TimestampProps {
|
|
28
29
|
value: string;
|
|
30
|
+
isFutureTime?: boolean;
|
|
29
31
|
sx?: SxProps<Theme>;
|
|
30
32
|
}
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* SPDX-License-Identifier: EPL-2.0
|
|
9
9
|
********************************************************************************/
|
|
10
10
|
|
|
11
|
-
import { FunctionComponent, PropsWithChildren, useContext } from 'react';
|
|
11
|
+
import { FunctionComponent, PropsWithChildren, useContext, useRef } from 'react';
|
|
12
12
|
import { Typography, MenuItem, Link, Button, IconButton, Accordion, AccordionSummary, Avatar, AccordionDetails } from '@mui/material';
|
|
13
|
-
import { useLocation } from 'react-router-dom';
|
|
14
|
-
import { Link as RouteLink } from 'react-router-dom';
|
|
13
|
+
import { useLocation, Link as RouteLink } from 'react-router-dom';
|
|
15
14
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
16
15
|
import GitHubIcon from '@mui/icons-material/GitHub';
|
|
17
16
|
import MenuBookIcon from '@mui/icons-material/MenuBook';
|
|
@@ -31,21 +30,13 @@ import { LogoutForm } from '../pages/user/logout';
|
|
|
31
30
|
import { LoginComponent } from './login';
|
|
32
31
|
|
|
33
32
|
//-------------------- Mobile View --------------------//
|
|
34
|
-
|
|
35
|
-
export const MobileMenuItem = styled(MenuItem)({
|
|
36
|
-
cursor: 'auto',
|
|
37
|
-
'&>a': {
|
|
38
|
-
textDecoration: 'none'
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
33
|
export const itemIcon = {
|
|
43
34
|
mr: 1,
|
|
44
35
|
width: '16px',
|
|
45
36
|
height: '16px',
|
|
46
37
|
};
|
|
47
38
|
|
|
48
|
-
export const
|
|
39
|
+
export const MenuItemText: FunctionComponent<PropsWithChildren> = ({ children }) => {
|
|
49
40
|
return (
|
|
50
41
|
<Typography variant='body2' color='text.primary' sx={{ display: 'flex', alignItems: 'center', textTransform: 'none' }}>
|
|
51
42
|
{children}
|
|
@@ -56,6 +47,7 @@ export const MobileMenuItemText: FunctionComponent<PropsWithChildren> = ({ child
|
|
|
56
47
|
export const MobileUserAvatar: FunctionComponent = () => {
|
|
57
48
|
const context = useContext(MainContext);
|
|
58
49
|
const user = context.user;
|
|
50
|
+
const logoutFormRef = useRef<HTMLFormElement>(null);
|
|
59
51
|
if (!user) {
|
|
60
52
|
return null;
|
|
61
53
|
}
|
|
@@ -66,52 +58,46 @@ export const MobileUserAvatar: FunctionComponent = () => {
|
|
|
66
58
|
aria-controls='user-actions'
|
|
67
59
|
id='user-avatar'
|
|
68
60
|
>
|
|
69
|
-
<
|
|
61
|
+
<MenuItemText>
|
|
70
62
|
<Avatar
|
|
71
63
|
src={user.avatarUrl}
|
|
72
64
|
alt={user.loginName}
|
|
73
65
|
variant='rounded'
|
|
74
66
|
sx={itemIcon} />
|
|
75
67
|
{user.loginName}
|
|
76
|
-
</
|
|
68
|
+
</MenuItemText>
|
|
77
69
|
</AccordionSummary>
|
|
78
70
|
<AccordionDetails>
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Settings
|
|
92
|
-
</MobileMenuItemText>
|
|
93
|
-
</RouteLink>
|
|
94
|
-
</MobileMenuItem>
|
|
71
|
+
<MenuItem component={Link} href={user.homepage}>
|
|
72
|
+
<MenuItemText>
|
|
73
|
+
<GitHubIcon sx={itemIcon} />
|
|
74
|
+
{user.loginName}
|
|
75
|
+
</MenuItemText>
|
|
76
|
+
</MenuItem>
|
|
77
|
+
<MenuItem component={RouteLink} to={UserSettingsRoutes.PROFILE}>
|
|
78
|
+
<MenuItemText>
|
|
79
|
+
<SettingsIcon sx={itemIcon} />
|
|
80
|
+
Settings
|
|
81
|
+
</MenuItemText>
|
|
82
|
+
</MenuItem>
|
|
95
83
|
{
|
|
96
84
|
user.role === 'admin'
|
|
97
|
-
? <
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
</RouteLink>
|
|
104
|
-
</MobileMenuItem>
|
|
85
|
+
? <MenuItem component={RouteLink} to={AdminDashboardRoutes.MAIN}>
|
|
86
|
+
<MenuItemText>
|
|
87
|
+
<AdminPanelSettingsIcon sx={itemIcon} />
|
|
88
|
+
Admin Dashboard
|
|
89
|
+
</MenuItemText>
|
|
90
|
+
</MenuItem>
|
|
105
91
|
: null
|
|
106
92
|
}
|
|
107
|
-
<
|
|
108
|
-
<LogoutForm>
|
|
109
|
-
<
|
|
93
|
+
<MenuItem onClick={() => logoutFormRef.current?.submit()}>
|
|
94
|
+
<LogoutForm ref={logoutFormRef}>
|
|
95
|
+
<MenuItemText>
|
|
110
96
|
<LogoutIcon sx={itemIcon} />
|
|
111
97
|
Log Out
|
|
112
|
-
</
|
|
98
|
+
</MenuItemText>
|
|
113
99
|
</LogoutForm>
|
|
114
|
-
</
|
|
100
|
+
</MenuItem>
|
|
115
101
|
</AccordionDetails>
|
|
116
102
|
</Accordion>;
|
|
117
103
|
};
|
|
@@ -125,63 +111,51 @@ export const MobileMenuContent: FunctionComponent = () => {
|
|
|
125
111
|
user ? (
|
|
126
112
|
<MobileUserAvatar />
|
|
127
113
|
) : (
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
/>
|
|
140
|
-
</MobileMenuItem>
|
|
114
|
+
<LoginComponent
|
|
115
|
+
loginProviders={loginProviders}
|
|
116
|
+
renderButton={(href, onClick) => (
|
|
117
|
+
<MenuItem component={Link} href={href} onClick={onClick}>
|
|
118
|
+
<MenuItemText>
|
|
119
|
+
<AccountBoxIcon sx={itemIcon} />
|
|
120
|
+
Log In
|
|
121
|
+
</MenuItemText>
|
|
122
|
+
</MenuItem>
|
|
123
|
+
)}
|
|
124
|
+
/>
|
|
141
125
|
)
|
|
142
126
|
)}
|
|
143
127
|
{loginProviders && !location.pathname.startsWith(UserSettingsRoutes.ROOT) && (
|
|
144
|
-
<
|
|
145
|
-
<
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
</RouteLink>
|
|
151
|
-
</MobileMenuItem>
|
|
128
|
+
<MenuItem component={RouteLink} to='/user-settings/extensions'>
|
|
129
|
+
<MenuItemText>
|
|
130
|
+
<PublishIcon sx={itemIcon} />
|
|
131
|
+
Publish Extension
|
|
132
|
+
</MenuItemText>
|
|
133
|
+
</MenuItem>
|
|
152
134
|
)}
|
|
153
|
-
<
|
|
154
|
-
<
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
</
|
|
176
|
-
</
|
|
177
|
-
<MobileMenuItem>
|
|
178
|
-
<RouteLink to='/about'>
|
|
179
|
-
<MobileMenuItemText>
|
|
180
|
-
<InfoIcon sx={itemIcon} />
|
|
181
|
-
About This Service
|
|
182
|
-
</MobileMenuItemText>
|
|
183
|
-
</RouteLink>
|
|
184
|
-
</MobileMenuItem>
|
|
135
|
+
<MenuItem component={Link} href='https://github.com/eclipse/openvsx' target='_blank'>
|
|
136
|
+
<MenuItemText>
|
|
137
|
+
<GitHubIcon sx={itemIcon} />
|
|
138
|
+
Source Code
|
|
139
|
+
</MenuItemText>
|
|
140
|
+
</MenuItem>
|
|
141
|
+
<MenuItem component={Link} href='https://github.com/eclipse/openvsx/wiki'>
|
|
142
|
+
<MenuItemText>
|
|
143
|
+
<MenuBookIcon sx={itemIcon} />
|
|
144
|
+
Documentation
|
|
145
|
+
</MenuItemText>
|
|
146
|
+
</MenuItem>
|
|
147
|
+
<MenuItem component={Link} href='https://join.slack.com/t/openvsxworkinggroup/shared_invite/zt-2y07y1ggy-ct3IfJljjGI6xWUQ9llv6A'>
|
|
148
|
+
<MenuItemText>
|
|
149
|
+
<ForumIcon sx={itemIcon} />
|
|
150
|
+
Slack Workspace
|
|
151
|
+
</MenuItemText>
|
|
152
|
+
</MenuItem>
|
|
153
|
+
<MenuItem component={RouteLink} to='/about'>
|
|
154
|
+
<MenuItemText>
|
|
155
|
+
<InfoIcon sx={itemIcon} />
|
|
156
|
+
About This Service
|
|
157
|
+
</MenuItemText>
|
|
158
|
+
</MenuItem>
|
|
185
159
|
</>;
|
|
186
160
|
};
|
|
187
161
|
|
|
@@ -397,7 +397,7 @@ export class ExtensionRegistryService {
|
|
|
397
397
|
payload: extensionPackage,
|
|
398
398
|
headers: headers,
|
|
399
399
|
endpoint: createAbsoluteURL([this.serverUrl, 'api', 'user', 'publish'])
|
|
400
|
-
});
|
|
400
|
+
}, false); // do not retry publishing an extension but show the explicit error received
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
async createNamespace(abortController: AbortController, name: string): Promise<Readonly<SuccessResult | ErrorResult>> {
|
|
@@ -180,6 +180,8 @@ export interface PersonalAccessToken {
|
|
|
180
180
|
value?: string;
|
|
181
181
|
createdTimestamp: TimestampString;
|
|
182
182
|
accessedTimestamp?: TimestampString;
|
|
183
|
+
expiresTimestamp?: TimestampString;
|
|
184
|
+
notified?: boolean;
|
|
183
185
|
description: string;
|
|
184
186
|
deleteTokenUrl: UrlString;
|
|
185
187
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { useState } from 'react';
|
|
15
|
+
|
|
16
|
+
const getQuery = () => {
|
|
17
|
+
if (typeof window !== 'undefined') {
|
|
18
|
+
return new URLSearchParams(window.location.search);
|
|
19
|
+
}
|
|
20
|
+
return new URLSearchParams();
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getQueryStringVal = (key: string): string | null => {
|
|
24
|
+
return getQuery().get(key);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const useQueryParam = (
|
|
28
|
+
key: string,
|
|
29
|
+
defaultVal: string
|
|
30
|
+
): [string, (val: string) => void] => {
|
|
31
|
+
const [query, setQuery] = useState(getQueryStringVal(key) || defaultVal);
|
|
32
|
+
|
|
33
|
+
const updateUrl = (newVal: string) => {
|
|
34
|
+
setQuery(newVal);
|
|
35
|
+
|
|
36
|
+
const query = getQuery();
|
|
37
|
+
|
|
38
|
+
if (newVal.trim() !== '') {
|
|
39
|
+
query.set(key, newVal);
|
|
40
|
+
} else {
|
|
41
|
+
query.delete(key);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// This check is necessary if using the hook with Gatsby
|
|
45
|
+
if (typeof window !== 'undefined') {
|
|
46
|
+
const { protocol, pathname, host } = window.location;
|
|
47
|
+
const newUrl = `${protocol}//${host}${pathname}?${query.toString()}`;
|
|
48
|
+
window.history.pushState({}, '', newUrl);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return [query, updateUrl];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default useQueryParam;
|
|
@@ -34,7 +34,7 @@ import { Customers } from './customers/customers';
|
|
|
34
34
|
import { UsageStatsView } from './usage-stats/usage-stats';
|
|
35
35
|
import { Logs } from './logs/logs';
|
|
36
36
|
import { LoginComponent } from "../../default/login";
|
|
37
|
-
import AccountBoxIcon from
|
|
37
|
+
import AccountBoxIcon from '@mui/icons-material/AccountBox';
|
|
38
38
|
|
|
39
39
|
export namespace AdminDashboardRoutes {
|
|
40
40
|
export const ROOT = 'admin-dashboard';
|
|
@@ -109,6 +109,7 @@ export const AdminDashboard: FunctionComponent<AdminDashboardProps> = props => {
|
|
|
109
109
|
<Routes>
|
|
110
110
|
<Route path='/namespaces' element={<NamespaceAdmin/>} />
|
|
111
111
|
<Route path='/extensions' element={<ExtensionAdmin/>} />
|
|
112
|
+
<Route path='/extensions/:namespace/:extension' element={<ExtensionAdmin/>} />
|
|
112
113
|
<Route path='/publisher' element={<PublisherAdmin/>} />
|
|
113
114
|
<Route path='/scans' element={<ScanAdmin/>} />
|
|
114
115
|
<Route path='/tiers' element={<Tiers/>} />
|
|
@@ -16,6 +16,7 @@ import { MainContext } from '../../context';
|
|
|
16
16
|
import { isError, Extension, TargetPlatformVersion } from '../../extension-registry-types';
|
|
17
17
|
import { ExtensionVersionContainer } from './extension-version-container';
|
|
18
18
|
import { StyledInput } from './namespace-input';
|
|
19
|
+
import useQueryParam from '../../hooks/scan-admin/use-query-params-state';
|
|
19
20
|
|
|
20
21
|
export const ExtensionAdmin: FunctionComponent = props => {
|
|
21
22
|
const abortController = useRef<AbortController>(new AbortController());
|
|
@@ -27,12 +28,12 @@ export const ExtensionAdmin: FunctionComponent = props => {
|
|
|
27
28
|
|
|
28
29
|
const [loading, setLoading] = useState(false);
|
|
29
30
|
|
|
30
|
-
const [extensionValue, setExtensionValue] =
|
|
31
|
+
const [extensionValue, setExtensionValue] = useQueryParam('extension', '');
|
|
31
32
|
const handleExtensionChange = (value: string) => {
|
|
32
33
|
setExtensionValue(value);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const [namespaceValue, setNamespaceValue] =
|
|
36
|
+
const [namespaceValue, setNamespaceValue] = useQueryParam('namespace', '');
|
|
36
37
|
const handleNamespaceChange = (value: string) => {
|
|
37
38
|
setNamespaceValue(value);
|
|
38
39
|
};
|
|
@@ -93,6 +94,7 @@ export const ExtensionAdmin: FunctionComponent = props => {
|
|
|
93
94
|
error={namespaceFieldError}
|
|
94
95
|
key='nsi'
|
|
95
96
|
onChange={handleNamespaceChange}
|
|
97
|
+
value={namespaceValue}
|
|
96
98
|
hideIconButton={true}
|
|
97
99
|
autoFocus={true} />,
|
|
98
100
|
<ExtensionListSearchfield
|
|
@@ -16,6 +16,7 @@ import { MainContext } from '../../context';
|
|
|
16
16
|
interface InputProps {
|
|
17
17
|
onSubmit?: (inputValue: string) => void;
|
|
18
18
|
onChange: (inputValue: string) => void;
|
|
19
|
+
value?: string;
|
|
19
20
|
hideIconButton?: boolean;
|
|
20
21
|
error?: boolean;
|
|
21
22
|
autoFocus?: boolean;
|
|
@@ -23,7 +24,7 @@ interface InputProps {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export const StyledInput: FunctionComponent<InputProps> = props => {
|
|
26
|
-
const [inputValue, setInputValue] = useState('');
|
|
27
|
+
const [inputValue, setInputValue] = useState(props.value || '');
|
|
27
28
|
const { pageSettings } = useContext(MainContext);
|
|
28
29
|
const onChangeInputValue = (ev: ChangeEvent<HTMLInputElement>) => {
|
|
29
30
|
const inputValue = ev.target.value;
|
|
@@ -53,6 +54,7 @@ export const StyledInput: FunctionComponent<InputProps> = props => {
|
|
|
53
54
|
sx={{ flex: 1, pl: 1 }}
|
|
54
55
|
placeholder={props.placeholder}
|
|
55
56
|
onChange={onChangeInputValue}
|
|
57
|
+
value={inputValue}
|
|
56
58
|
onKeyDown={(e: KeyboardEvent) => {
|
|
57
59
|
if (e.key === 'Enter' && props.onSubmit) {
|
|
58
60
|
props.onSubmit(inputValue);
|
|
@@ -46,7 +46,7 @@ export const ExtensionDetailOverview: FunctionComponent<ExtensionDetailOverviewP
|
|
|
46
46
|
name: getEngineDisplayName(engine),
|
|
47
47
|
version: engines[engine]
|
|
48
48
|
}))
|
|
49
|
-
.filter((d) => d.name
|
|
49
|
+
.filter((d) => d.name); // only display engines with a known display name
|
|
50
50
|
|
|
51
51
|
return (<>
|
|
52
52
|
<Grid item xs='auto'>
|
|
@@ -27,11 +27,7 @@ export const ExtensionReviewDialog: FunctionComponent<ExtensionReviewDialogProps
|
|
|
27
27
|
const abortController = useRef<AbortController>(new AbortController());
|
|
28
28
|
|
|
29
29
|
useEffect(() => {
|
|
30
|
-
|
|
31
|
-
return () => {
|
|
32
|
-
abortController.current.abort();
|
|
33
|
-
document.removeEventListener('keydown', handleEnter);
|
|
34
|
-
};
|
|
30
|
+
return () => abortController.current.abort();
|
|
35
31
|
}, []);
|
|
36
32
|
|
|
37
33
|
const handleOpenButton = () => {
|
|
@@ -70,12 +66,6 @@ export const ExtensionReviewDialog: FunctionComponent<ExtensionReviewDialogProps
|
|
|
70
66
|
setCommentError(commentError);
|
|
71
67
|
};
|
|
72
68
|
|
|
73
|
-
const handleEnter = (e: KeyboardEvent) => {
|
|
74
|
-
if (e.code === 'Enter') {
|
|
75
|
-
handlePost();
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
69
|
if (!context.user) {
|
|
80
70
|
return null;
|
|
81
71
|
}
|
|
@@ -109,7 +99,7 @@ export const ExtensionReviewDialog: FunctionComponent<ExtensionReviewDialogProps
|
|
|
109
99
|
helperText={commentError}
|
|
110
100
|
onChange={handleCommentChange} />
|
|
111
101
|
</DialogContent>
|
|
112
|
-
<DialogActions sx={{ justifyContent: { xs: 'center', sm: '
|
|
102
|
+
<DialogActions sx={{ justifyContent: { xs: 'center', sm: 'end', md: 'end', lg: 'end', xl: 'end' } }}>
|
|
113
103
|
<Button
|
|
114
104
|
onClick={handleCancel}
|
|
115
105
|
color='secondary' >
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
********************************************************************************/
|
|
10
10
|
|
|
11
11
|
import { FunctionComponent, useContext, useRef, useState } from 'react';
|
|
12
|
-
import { styled } from '@mui/material/styles';
|
|
13
12
|
import { Avatar, Menu, Typography, MenuItem, Link, Divider, IconButton } from '@mui/material';
|
|
14
13
|
import { Link as RouteLink } from 'react-router-dom';
|
|
15
14
|
import { UserSettingsRoutes } from './user-settings';
|
|
@@ -17,18 +16,12 @@ import { AdminDashboardRoutes } from '../admin-dashboard/admin-dashboard';
|
|
|
17
16
|
import { MainContext } from '../../context';
|
|
18
17
|
import { LogoutForm } from './logout';
|
|
19
18
|
|
|
20
|
-
const AvatarRouteLink = styled(RouteLink)({
|
|
21
|
-
cursor: 'pointer',
|
|
22
|
-
textDecoration: 'none'
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const AvatarMenuItem = styled(MenuItem)({ cursor: 'auto' });
|
|
26
|
-
|
|
27
19
|
|
|
28
20
|
export const UserAvatar: FunctionComponent = () => {
|
|
29
21
|
const [open, setOpen] = useState<boolean>(false);
|
|
30
22
|
const context = useContext(MainContext);
|
|
31
23
|
const avatarButton = useRef<any>();
|
|
24
|
+
const logoutFormRef = useRef<HTMLFormElement>(null);
|
|
32
25
|
|
|
33
26
|
const handleAvatarClick = () => {
|
|
34
27
|
setOpen(!open);
|
|
@@ -60,43 +53,45 @@ export const UserAvatar: FunctionComponent = () => {
|
|
|
60
53
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
|
61
54
|
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
|
62
55
|
onClose={handleClose} >
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
<MenuItem
|
|
57
|
+
component={Link}
|
|
58
|
+
href={user.homepage}
|
|
59
|
+
sx={{
|
|
60
|
+
display: 'block',
|
|
61
|
+
'&:hover': {
|
|
62
|
+
textDecoration: 'underline'
|
|
63
|
+
}
|
|
64
|
+
}} >
|
|
65
|
+
<Typography variant='body2' color='text.primary' sx={{ mr: 1 }}>
|
|
66
|
+
Logged in as
|
|
67
|
+
</Typography>
|
|
68
|
+
<Typography variant='overline' color='text.primary'>
|
|
69
|
+
{user.loginName}
|
|
70
|
+
</Typography>
|
|
71
|
+
</MenuItem>
|
|
73
72
|
<Divider />
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</AvatarRouteLink>
|
|
80
|
-
</AvatarMenuItem>
|
|
73
|
+
<MenuItem component={RouteLink} to={UserSettingsRoutes.PROFILE} onClick={handleClose}>
|
|
74
|
+
<Typography variant='button' color='text.primary'>
|
|
75
|
+
Settings
|
|
76
|
+
</Typography>
|
|
77
|
+
</MenuItem>
|
|
81
78
|
{
|
|
82
79
|
user.role && user.role === 'admin' ?
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</AvatarRouteLink>
|
|
89
|
-
</AvatarMenuItem>
|
|
80
|
+
<MenuItem component={RouteLink} to={AdminDashboardRoutes.MAIN} onClick={handleClose}>
|
|
81
|
+
<Typography variant='button' color='text.primary'>
|
|
82
|
+
Admin Dashboard
|
|
83
|
+
</Typography>
|
|
84
|
+
</MenuItem>
|
|
90
85
|
:
|
|
91
86
|
''
|
|
92
87
|
}
|
|
93
|
-
<
|
|
94
|
-
<LogoutForm>
|
|
88
|
+
<MenuItem onClick={() => logoutFormRef.current?.submit()}>
|
|
89
|
+
<LogoutForm ref={logoutFormRef}>
|
|
95
90
|
<Typography variant='button' sx={{ color: 'primary.dark' }}>
|
|
96
91
|
Log Out
|
|
97
92
|
</Typography>
|
|
98
93
|
</LogoutForm>
|
|
99
|
-
</
|
|
94
|
+
</MenuItem>
|
|
100
95
|
</Menu>
|
|
101
96
|
</>;
|
|
102
97
|
};
|