@backstage/plugin-user-settings 0.7.11-next.2 → 0.7.11

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/dist/index.esm.js CHANGED
@@ -1,26 +1,28 @@
1
1
  import { WebStorage } from '@backstage/core-app-api';
2
2
  import { ResponseError } from '@backstage/errors';
3
3
  import ObservableImpl from 'zen-observable';
4
- import { createRouteRef, createPlugin, createRoutableExtension, useRouteRef, useApi, errorApiRef, SessionState, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, gitlabAuthApiRef, oktaAuthApiRef, bitbucketAuthApiRef, oneloginAuthApiRef, atlassianAuthApiRef, bitbucketServerAuthApiRef, configApiRef, featureFlagsApiRef, FeatureFlagState, identityApiRef, alertApiRef, appThemeApiRef, attachComponentData, useElementFilter } from '@backstage/core-plugin-api';
5
- import React, { useState, useEffect, useCallback, cloneElement } from 'react';
4
+ import { createRouteRef, createPlugin, createRoutableExtension, useRouteRef, attachComponentData } from '@backstage/core-plugin-api';
5
+ import React from 'react';
6
6
  import SettingsIcon from '@material-ui/icons/Settings';
7
- import { SidebarItem, EmptyState, CodeSnippet, sidebarConfig, InfoCard, useSidebarPinState, Page, Header, RoutedTabs } from '@backstage/core-components';
8
- import { useOutlet } from 'react-router-dom';
9
- import { Typography, Button, makeStyles, Avatar, ListItem, ListItemIcon, ListItemText, Tooltip, Grid, ListItemSecondaryAction, List, Switch, TextField, IconButton, Menu, MenuItem } from '@material-ui/core';
10
- import Star from '@material-ui/icons/Star';
11
- import ClearIcon from '@material-ui/icons/Clear';
12
- import useAsync from 'react-use/lib/useAsync';
13
- import SignOutIcon from '@material-ui/icons/MeetingRoom';
14
- import MoreVertIcon from '@material-ui/icons/MoreVert';
15
- import useObservable from 'react-use/lib/useObservable';
16
- import AutoIcon from '@material-ui/icons/BrightnessAuto';
17
- import ToggleButton from '@material-ui/lab/ToggleButton';
18
- import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
19
- import { useTranslationRef, appLanguageApiRef } from '@backstage/core-plugin-api/alpha';
20
- import { u as userSettingsTranslationRef } from './esm/translation-d20c444b.esm.js';
21
- import { EntityRefLinks } from '@backstage/plugin-catalog-react';
22
- import Grid$1 from '@material-ui/core/Grid';
23
- import Typography$1 from '@material-ui/core/Typography';
7
+ import { SidebarItem } from '@backstage/core-components';
8
+ import { L as LAYOUT_ROUTE_DATA_KEY, S as SettingsLayout } from './esm/SettingsPage-f863b932.esm.js';
9
+ export { D as DefaultProviderSettings, P as ProviderSettingsItem, a as Router, S as SettingsLayout, f as UserSettingsAppearanceCard, U as UserSettingsAuthProviders, k as UserSettingsFeatureFlags, b as UserSettingsGeneral, i as UserSettingsIdentityCard, j as UserSettingsLanguageToggle, d as UserSettingsMenu, h as UserSettingsPinToggle, c as UserSettingsProfileCard, e as UserSettingsSignInAvatar, g as UserSettingsThemeToggle, u as useUserProfile } from './esm/SettingsPage-f863b932.esm.js';
10
+ import 'react-router-dom';
11
+ import '@material-ui/core';
12
+ import '@material-ui/icons/Star';
13
+ import '@material-ui/icons/Clear';
14
+ import 'react-use/lib/useAsync';
15
+ import '@material-ui/icons/MeetingRoom';
16
+ import '@material-ui/icons/MoreVert';
17
+ import 'react-use/lib/useObservable';
18
+ import '@material-ui/icons/BrightnessAuto';
19
+ import '@material-ui/lab/ToggleButton';
20
+ import '@material-ui/lab/ToggleButtonGroup';
21
+ import '@backstage/core-plugin-api/alpha';
22
+ import './esm/translation-d20c444b.esm.js';
23
+ import '@backstage/plugin-catalog-react';
24
+ import '@material-ui/core/Grid';
25
+ import '@material-ui/core/Typography';
24
26
 
25
27
  var __defProp = Object.defineProperty;
26
28
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -182,7 +184,7 @@ const userSettingsPlugin = createPlugin({
182
184
  const UserSettingsPage = userSettingsPlugin.provide(
183
185
  createRoutableExtension({
184
186
  name: "UserSettingsPage",
185
- component: () => import('./esm/index-355b96f0.esm.js').then((m) => m.SettingsPage),
187
+ component: () => import('./esm/index-ca302ff8.esm.js').then((m) => m.SettingsPage),
186
188
  mountPoint: settingsRouteRef
187
189
  })
188
190
  );
@@ -193,743 +195,9 @@ const Settings = (props) => {
193
195
  return /* @__PURE__ */ React.createElement(SidebarItem, { text: "Settings", to: routePath(), icon: Icon });
194
196
  };
195
197
 
196
- const EXAMPLE$1 = `auth:
197
- providers:
198
- google:
199
- development:
200
- clientId: \${AUTH_GOOGLE_CLIENT_ID}
201
- clientSecret: \${AUTH_GOOGLE_CLIENT_SECRET}
202
- `;
203
- const EmptyProviders = () => /* @__PURE__ */ React.createElement(
204
- EmptyState,
205
- {
206
- missing: "content",
207
- title: "No Authentication Providers",
208
- description: "You can add Authentication Providers to Backstage which allows you to use these providers to authenticate yourself.",
209
- action: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, "Open ", /* @__PURE__ */ React.createElement("code", null, "app-config.yaml"), " and make the changes as highlighted below:"), /* @__PURE__ */ React.createElement(
210
- CodeSnippet,
211
- {
212
- text: EXAMPLE$1,
213
- language: "yaml",
214
- showLineNumbers: true,
215
- highlightedNumbers: [3, 4, 5, 6, 7, 8],
216
- customStyle: { background: "inherit", fontSize: "115%" }
217
- }
218
- ), /* @__PURE__ */ React.createElement(
219
- Button,
220
- {
221
- variant: "contained",
222
- color: "primary",
223
- href: "https://backstage.io/docs/auth/add-auth-provider"
224
- },
225
- "Read More"
226
- ))
227
- }
228
- );
229
-
230
- const useStyles$3 = makeStyles((theme) => ({
231
- avatar: {
232
- width: ({ size }) => size,
233
- height: ({ size }) => size,
234
- fontSize: ({ size }) => size * 0.7,
235
- border: `1px solid ${theme.palette.textSubtle}`
236
- }
237
- }));
238
- const ProviderSettingsAvatar = ({ size, picture }) => {
239
- const { iconSize } = sidebarConfig;
240
- const classes = useStyles$3(size ? { size } : { size: iconSize });
241
- return /* @__PURE__ */ React.createElement(Avatar, { src: picture, className: classes.avatar });
242
- };
243
-
244
- const emptyProfile = {};
245
- const ProviderSettingsItem = (props) => {
246
- const { title, description, icon: Icon, apiRef } = props;
247
- const api = useApi(apiRef);
248
- const errorApi = useApi(errorApiRef);
249
- const [signedIn, setSignedIn] = useState(false);
250
- const [profile, setProfile] = useState(emptyProfile);
251
- useEffect(() => {
252
- let didCancel = false;
253
- const subscription = api.sessionState$().subscribe((sessionState) => {
254
- if (sessionState !== SessionState.SignedIn) {
255
- setProfile(emptyProfile);
256
- setSignedIn(false);
257
- }
258
- if (!didCancel) {
259
- api.getProfile({ optional: true }).then((profileResponse) => {
260
- if (!didCancel) {
261
- if (sessionState === SessionState.SignedIn) {
262
- setSignedIn(true);
263
- }
264
- if (profileResponse) {
265
- setProfile(profileResponse);
266
- }
267
- }
268
- });
269
- }
270
- });
271
- return () => {
272
- didCancel = true;
273
- subscription.unsubscribe();
274
- };
275
- }, [api]);
276
- return /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Icon, null)), /* @__PURE__ */ React.createElement(
277
- ListItemText,
278
- {
279
- primary: title,
280
- secondary: /* @__PURE__ */ React.createElement(Tooltip, { placement: "top", arrow: true, title: description }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 6 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(ProviderSettingsAvatar, { size: 48, picture: profile.picture })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: true, container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true, container: true, direction: "column", spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(
281
- Typography,
282
- {
283
- variant: "subtitle1",
284
- color: "textPrimary",
285
- gutterBottom: true
286
- },
287
- profile.displayName
288
- ), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, profile.email), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, description)))))),
289
- secondaryTypographyProps: { noWrap: true, style: { width: "80%" } }
290
- }
291
- ), /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(
292
- Tooltip,
293
- {
294
- placement: "top",
295
- arrow: true,
296
- title: signedIn ? `Sign out from ${title}` : `Sign in to ${title}`
297
- },
298
- /* @__PURE__ */ React.createElement(
299
- Button,
300
- {
301
- variant: "outlined",
302
- color: "primary",
303
- onClick: () => {
304
- const action = signedIn ? api.signOut() : api.signIn();
305
- action.catch((error) => errorApi.post(error));
306
- }
307
- },
308
- signedIn ? `Sign out` : `Sign in`
309
- )
310
- )));
311
- };
312
-
313
- const DefaultProviderSettings = (props) => {
314
- const { configuredProviders } = props;
315
- return /* @__PURE__ */ React.createElement(React.Fragment, null, configuredProviders.includes("google") && /* @__PURE__ */ React.createElement(
316
- ProviderSettingsItem,
317
- {
318
- title: "Google",
319
- description: "Provides authentication towards Google APIs and identities",
320
- apiRef: googleAuthApiRef,
321
- icon: Star
322
- }
323
- ), configuredProviders.includes("microsoft") && /* @__PURE__ */ React.createElement(
324
- ProviderSettingsItem,
325
- {
326
- title: "Microsoft",
327
- description: "Provides authentication towards Microsoft APIs and identities",
328
- apiRef: microsoftAuthApiRef,
329
- icon: Star
330
- }
331
- ), configuredProviders.includes("github") && /* @__PURE__ */ React.createElement(
332
- ProviderSettingsItem,
333
- {
334
- title: "GitHub",
335
- description: "Provides authentication towards GitHub APIs",
336
- apiRef: githubAuthApiRef,
337
- icon: Star
338
- }
339
- ), configuredProviders.includes("gitlab") && /* @__PURE__ */ React.createElement(
340
- ProviderSettingsItem,
341
- {
342
- title: "GitLab",
343
- description: "Provides authentication towards GitLab APIs",
344
- apiRef: gitlabAuthApiRef,
345
- icon: Star
346
- }
347
- ), configuredProviders.includes("okta") && /* @__PURE__ */ React.createElement(
348
- ProviderSettingsItem,
349
- {
350
- title: "Okta",
351
- description: "Provides authentication towards Okta APIs",
352
- apiRef: oktaAuthApiRef,
353
- icon: Star
354
- }
355
- ), configuredProviders.includes("bitbucket") && /* @__PURE__ */ React.createElement(
356
- ProviderSettingsItem,
357
- {
358
- title: "Bitbucket",
359
- description: "Provides authentication towards Bitbucket APIs",
360
- apiRef: bitbucketAuthApiRef,
361
- icon: Star
362
- }
363
- ), configuredProviders.includes("onelogin") && /* @__PURE__ */ React.createElement(
364
- ProviderSettingsItem,
365
- {
366
- title: "OneLogin",
367
- description: "Provides authentication towards OneLogin APIs",
368
- apiRef: oneloginAuthApiRef,
369
- icon: Star
370
- }
371
- ), configuredProviders.includes("atlassian") && /* @__PURE__ */ React.createElement(
372
- ProviderSettingsItem,
373
- {
374
- title: "Atlassian",
375
- description: "Provides authentication towards Atlassian APIs",
376
- apiRef: atlassianAuthApiRef,
377
- icon: Star
378
- }
379
- ), configuredProviders.includes("bitbucketServer") && /* @__PURE__ */ React.createElement(
380
- ProviderSettingsItem,
381
- {
382
- title: "Bitbucket Server",
383
- description: "Provides authentication towards Bitbucket Server APIs",
384
- apiRef: bitbucketServerAuthApiRef,
385
- icon: Star
386
- }
387
- ));
388
- };
389
-
390
- const UserSettingsAuthProviders = (props) => {
391
- const { providerSettings } = props;
392
- const configApi = useApi(configApiRef);
393
- const providersConfig = configApi.getOptionalConfig("auth.providers");
394
- const configuredProviders = (providersConfig == null ? void 0 : providersConfig.keys()) || [];
395
- const providers = providerSettings != null ? providerSettings : /* @__PURE__ */ React.createElement(DefaultProviderSettings, { configuredProviders });
396
- if (!providerSettings && !(configuredProviders == null ? void 0 : configuredProviders.length)) {
397
- return /* @__PURE__ */ React.createElement(EmptyProviders, null);
398
- }
399
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Available Providers" }, /* @__PURE__ */ React.createElement(List, { dense: true }, providers));
400
- };
401
-
402
- const EXAMPLE = `import { createPlugin } from '@backstage/core-plugin-api';
403
-
404
- export default createPlugin({
405
- id: 'plugin-name',
406
- featureFlags: [{ name: 'enable-example-feature' }],
407
- });
408
- `;
409
- const EmptyFlags = () => /* @__PURE__ */ React.createElement(
410
- EmptyState,
411
- {
412
- missing: "content",
413
- title: "No Feature Flags",
414
- description: "Feature Flags make it possible for plugins to register features in Backstage for users to opt into. You can use this to split out logic in your code for manual A/B testing, etc.",
415
- action: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, "An example for how to add a feature flag is highlighted below:"), /* @__PURE__ */ React.createElement(
416
- CodeSnippet,
417
- {
418
- text: EXAMPLE,
419
- language: "typescript",
420
- showLineNumbers: true,
421
- highlightedNumbers: [6],
422
- customStyle: { background: "inherit", fontSize: "115%" }
423
- }
424
- ), /* @__PURE__ */ React.createElement(
425
- Button,
426
- {
427
- variant: "contained",
428
- color: "primary",
429
- href: "https://backstage.io/docs/api/utility-apis"
430
- },
431
- "Read More"
432
- ))
433
- }
434
- );
435
-
436
- const getSecondaryText = (flag) => {
437
- if (flag.description) {
438
- return flag.description;
439
- }
440
- return flag.pluginId ? `Registered in ${flag.pluginId} plugin` : "Registered in the application";
441
- };
442
- const FlagItem = ({ flag, enabled, toggleHandler }) => /* @__PURE__ */ React.createElement(ListItem, { divider: true, button: true, onClick: () => toggleHandler(flag.name) }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { placement: "top", arrow: true, title: enabled ? "Disable" : "Enable" }, /* @__PURE__ */ React.createElement(Switch, { color: "primary", checked: enabled, name: flag.name }))), /* @__PURE__ */ React.createElement(ListItemText, { primary: flag.name, secondary: getSecondaryText(flag) }));
443
-
444
- const sortFlags = (flags, featureFlagsApi) => {
445
- const activeFlags = flags.filter((flag) => featureFlagsApi.isActive(flag.name));
446
- const idleFlags = flags.filter((flag) => !featureFlagsApi.isActive(flag.name));
447
- return [...activeFlags, ...idleFlags];
448
- };
449
- const UserSettingsFeatureFlags = () => {
450
- const featureFlagsApi = useApi(featureFlagsApiRef);
451
- const inputRef = React.useRef();
452
- const initialFeatureFlags = featureFlagsApi.getRegisteredFlags();
453
- const initialFeatureFlagsSorted = sortFlags(
454
- initialFeatureFlags,
455
- featureFlagsApi
456
- );
457
- const [featureFlags] = useState(initialFeatureFlagsSorted);
458
- const initialFlagState = Object.fromEntries(
459
- featureFlags.map(({ name }) => [name, featureFlagsApi.isActive(name)])
460
- );
461
- const [state, setState] = useState(initialFlagState);
462
- const [filterInput, setFilterInput] = useState("");
463
- const toggleFlag = useCallback(
464
- (flagName) => {
465
- const newState = featureFlagsApi.isActive(flagName) ? FeatureFlagState.None : FeatureFlagState.Active;
466
- featureFlagsApi.save({
467
- states: { [flagName]: newState },
468
- merge: true
469
- });
470
- setState((prevState) => ({
471
- ...prevState,
472
- [flagName]: newState === FeatureFlagState.Active
473
- }));
474
- },
475
- [featureFlagsApi]
476
- );
477
- if (!featureFlags.length) {
478
- return /* @__PURE__ */ React.createElement(EmptyFlags, null);
479
- }
480
- const clearFilterInput = () => {
481
- var _a;
482
- setFilterInput("");
483
- (_a = inputRef == null ? void 0 : inputRef.current) == null ? void 0 : _a.focus();
484
- };
485
- const filteredFeatureFlags = featureFlags.filter((featureFlag) => {
486
- const featureFlagName = featureFlag.name.toLocaleLowerCase("en-US");
487
- return featureFlagName.includes(filterInput.toLocaleLowerCase("en-US"));
488
- });
489
- const Header = () => /* @__PURE__ */ React.createElement(Grid, { container: true, style: { justifyContent: "space-between" } }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 6, md: 8 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Feature Flags"), /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, "Please refresh the page when toggling feature flags")), featureFlags.length >= 10 && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 6, md: 4 }, /* @__PURE__ */ React.createElement(
490
- TextField,
491
- {
492
- label: "Filter",
493
- style: { display: "flex", justifyContent: "flex-end" },
494
- inputRef: (ref) => ref && ref.focus(),
495
- InputProps: {
496
- ...filterInput.length && {
497
- endAdornment: /* @__PURE__ */ React.createElement(
498
- IconButton,
499
- {
500
- "aria-label": "Clear filter",
501
- onClick: clearFilterInput,
502
- edge: "end"
503
- },
504
- /* @__PURE__ */ React.createElement(ClearIcon, null)
505
- )
506
- }
507
- },
508
- onChange: (e) => setFilterInput(e.target.value),
509
- value: filterInput
510
- }
511
- )));
512
- return /* @__PURE__ */ React.createElement(InfoCard, { title: /* @__PURE__ */ React.createElement(Header, null) }, /* @__PURE__ */ React.createElement(List, { dense: true }, filteredFeatureFlags.map((featureFlag) => {
513
- const enabled = Boolean(state[featureFlag.name]);
514
- return /* @__PURE__ */ React.createElement(
515
- FlagItem,
516
- {
517
- key: featureFlag.name,
518
- flag: featureFlag,
519
- enabled,
520
- toggleHandler: toggleFlag
521
- }
522
- );
523
- })));
524
- };
525
-
526
- const useUserProfile = () => {
527
- var _a;
528
- const identityApi = useApi(identityApiRef);
529
- const alertApi = useApi(alertApiRef);
530
- const { value, loading, error } = useAsync(async () => {
531
- return {
532
- profile: await identityApi.getProfileInfo(),
533
- identity: await identityApi.getBackstageIdentity()
534
- };
535
- }, []);
536
- useEffect(() => {
537
- if (error) {
538
- alertApi.post({
539
- message: `Failed to load user identity: ${error}`,
540
- severity: "error"
541
- });
542
- }
543
- }, [error, alertApi]);
544
- if (loading || error) {
545
- return {
546
- profile: {},
547
- displayName: "",
548
- loading
549
- };
550
- }
551
- return {
552
- profile: value.profile,
553
- backstageIdentity: value.identity,
554
- displayName: (_a = value.profile.displayName) != null ? _a : value.identity.userEntityRef,
555
- loading
556
- };
557
- };
558
-
559
- const useStyles$2 = makeStyles((theme) => ({
560
- avatar: {
561
- width: ({ size }) => size,
562
- height: ({ size }) => size,
563
- fontSize: ({ size }) => size * 0.7,
564
- border: `1px solid ${theme.palette.textSubtle}`
565
- }
566
- }));
567
- const UserSettingsSignInAvatar = (props) => {
568
- const { size } = props;
569
- const { iconSize } = sidebarConfig;
570
- const classes = useStyles$2(size ? { size } : { size: iconSize });
571
- const { profile } = useUserProfile();
572
- return /* @__PURE__ */ React.createElement(
573
- Avatar,
574
- {
575
- src: profile.picture,
576
- className: classes.avatar,
577
- alt: "Profile picture"
578
- }
579
- );
580
- };
581
-
582
- const UserSettingsMenu = () => {
583
- const errorApi = useApi(errorApiRef);
584
- const identityApi = useApi(identityApiRef);
585
- const [open, setOpen] = React.useState(false);
586
- const [anchorEl, setAnchorEl] = React.useState(
587
- void 0
588
- );
589
- const handleOpen = (event) => {
590
- setAnchorEl(event.currentTarget);
591
- setOpen(true);
592
- };
593
- const handleClose = () => {
594
- setAnchorEl(void 0);
595
- setOpen(false);
596
- };
597
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
598
- IconButton,
599
- {
600
- "data-testid": "user-settings-menu",
601
- "aria-label": "more",
602
- onClick: handleOpen
603
- },
604
- /* @__PURE__ */ React.createElement(MoreVertIcon, null)
605
- ), /* @__PURE__ */ React.createElement(Menu, { anchorEl, open, onClose: handleClose }, /* @__PURE__ */ React.createElement(
606
- MenuItem,
607
- {
608
- "data-testid": "sign-out",
609
- onClick: () => identityApi.signOut().catch((error) => errorApi.post(error))
610
- },
611
- /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(SignOutIcon, null)),
612
- "Sign Out"
613
- )));
614
- };
615
-
616
- const UserSettingsProfileCard = () => {
617
- const { profile, displayName } = useUserProfile();
618
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Profile", variant: "gridItem" }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 6 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(UserSettingsSignInAvatar, { size: 96 })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: true, container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true, container: true, direction: "column", spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1", gutterBottom: true }, displayName), profile.email && /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, profile.email))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(UserSettingsMenu, null)))));
619
- };
620
-
621
- const UserSettingsPinToggle = () => {
622
- const { isPinned, toggleSidebarPinState } = useSidebarPinState();
623
- return /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(
624
- ListItemText,
625
- {
626
- primary: "Pin Sidebar",
627
- secondary: "Prevent the sidebar from collapsing"
628
- }
629
- ), /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(
630
- Tooltip,
631
- {
632
- placement: "top",
633
- arrow: true,
634
- title: `${isPinned ? "Unpin" : "Pin"} Sidebar`
635
- },
636
- /* @__PURE__ */ React.createElement(
637
- Switch,
638
- {
639
- color: "primary",
640
- checked: isPinned,
641
- onChange: () => toggleSidebarPinState(),
642
- name: "pin",
643
- inputProps: { "aria-label": "Pin Sidebar Switch" }
644
- }
645
- )
646
- )));
647
- };
648
-
649
- const ThemeIcon = ({ id, activeId, icon }) => icon ? cloneElement(icon, {
650
- color: activeId === id ? "primary" : void 0
651
- }) : /* @__PURE__ */ React.createElement(AutoIcon, { color: activeId === id ? "primary" : void 0 });
652
- const useStyles$1 = makeStyles((theme) => ({
653
- container: {
654
- display: "flex",
655
- flexWrap: "wrap",
656
- width: "100%",
657
- justifyContent: "space-between",
658
- alignItems: "center",
659
- paddingBottom: 8,
660
- paddingRight: 16
661
- },
662
- list: {
663
- width: "initial",
664
- [theme.breakpoints.down("xs")]: {
665
- width: "100%",
666
- padding: `0 0 12px`
667
- }
668
- },
669
- listItemText: {
670
- paddingRight: 0,
671
- paddingLeft: 0
672
- },
673
- listItemSecondaryAction: {
674
- position: "relative",
675
- transform: "unset",
676
- top: "auto",
677
- right: "auto",
678
- paddingLeft: 16,
679
- [theme.breakpoints.down("xs")]: {
680
- paddingLeft: 0
681
- }
682
- }
683
- }));
684
- const TooltipToggleButton$1 = ({
685
- children,
686
- title,
687
- value,
688
- ...props
689
- }) => /* @__PURE__ */ React.createElement(Tooltip, { placement: "top", arrow: true, title }, /* @__PURE__ */ React.createElement(ToggleButton, { value, ...props }, children));
690
- const UserSettingsThemeToggle = () => {
691
- const classes = useStyles$1();
692
- const appThemeApi = useApi(appThemeApiRef);
693
- const activeThemeId = useObservable(
694
- appThemeApi.activeThemeId$(),
695
- appThemeApi.getActiveThemeId()
696
- );
697
- const themeIds = appThemeApi.getInstalledThemes();
698
- const { t } = useTranslationRef(userSettingsTranslationRef);
699
- const handleSetTheme = (_event, newThemeId) => {
700
- if (themeIds.some((it) => it.id === newThemeId)) {
701
- appThemeApi.setActiveThemeId(newThemeId);
702
- } else {
703
- appThemeApi.setActiveThemeId(void 0);
704
- }
705
- };
706
- return /* @__PURE__ */ React.createElement(
707
- ListItem,
708
- {
709
- className: classes.list,
710
- classes: { container: classes.container }
711
- },
712
- /* @__PURE__ */ React.createElement(
713
- ListItemText,
714
- {
715
- className: classes.listItemText,
716
- primary: t("theme"),
717
- secondary: t("change_the_theme_mode")
718
- }
719
- ),
720
- /* @__PURE__ */ React.createElement(ListItemSecondaryAction, { className: classes.listItemSecondaryAction }, /* @__PURE__ */ React.createElement(
721
- ToggleButtonGroup,
722
- {
723
- exclusive: true,
724
- size: "small",
725
- value: activeThemeId != null ? activeThemeId : "auto",
726
- onChange: handleSetTheme
727
- },
728
- themeIds.map((theme) => {
729
- const themeId = theme.id;
730
- const themeIcon = theme.icon;
731
- const themeTitle = theme.title || (themeId === "light" || themeId === "dark" ? t(`theme_${themeId}`) : themeId);
732
- return /* @__PURE__ */ React.createElement(
733
- TooltipToggleButton$1,
734
- {
735
- key: themeId,
736
- title: t("select_theme", { theme: themeTitle }),
737
- value: themeId
738
- },
739
- /* @__PURE__ */ React.createElement(React.Fragment, null, themeTitle, "\xA0", /* @__PURE__ */ React.createElement(
740
- ThemeIcon,
741
- {
742
- id: themeId,
743
- icon: themeIcon,
744
- activeId: activeThemeId
745
- }
746
- ))
747
- );
748
- }),
749
- /* @__PURE__ */ React.createElement(Tooltip, { placement: "top", arrow: true, title: t("select_theme_auto") }, /* @__PURE__ */ React.createElement(ToggleButton, { value: "auto", selected: activeThemeId === void 0 }, t("theme_auto"), "\xA0", /* @__PURE__ */ React.createElement(
750
- AutoIcon,
751
- {
752
- color: activeThemeId === void 0 ? "primary" : void 0
753
- }
754
- )))
755
- ))
756
- );
757
- };
758
-
759
- const useStyles = makeStyles((theme) => ({
760
- container: {
761
- display: "flex",
762
- flexWrap: "wrap",
763
- width: "100%",
764
- justifyContent: "space-between",
765
- alignItems: "center",
766
- paddingBottom: 8,
767
- paddingRight: 16
768
- },
769
- list: {
770
- width: "initial",
771
- [theme.breakpoints.down("xs")]: {
772
- width: "100%",
773
- padding: `0 0 12px`
774
- }
775
- },
776
- listItemText: {
777
- paddingRight: 0,
778
- paddingLeft: 0
779
- },
780
- listItemSecondaryAction: {
781
- position: "relative",
782
- transform: "unset",
783
- top: "auto",
784
- right: "auto",
785
- paddingLeft: 16,
786
- [theme.breakpoints.down("xs")]: {
787
- paddingLeft: 0
788
- }
789
- }
790
- }));
791
- const TooltipToggleButton = ({
792
- children,
793
- title,
794
- value,
795
- ...props
796
- }) => /* @__PURE__ */ React.createElement(Tooltip, { placement: "top", arrow: true, title }, /* @__PURE__ */ React.createElement(ToggleButton, { value, ...props }, children));
797
- const UserSettingsLanguageToggle = () => {
798
- const classes = useStyles();
799
- const languageApi = useApi(appLanguageApiRef);
800
- const { t } = useTranslationRef(userSettingsTranslationRef);
801
- const [languageObservable] = useState(() => languageApi.language$());
802
- const { language: currentLanguage } = useObservable(
803
- languageObservable,
804
- languageApi.getLanguage()
805
- );
806
- const { languages } = languageApi.getAvailableLanguages();
807
- if (languages.length <= 1) {
808
- return null;
809
- }
810
- const handleSetLanguage = (_event, newLanguage) => {
811
- languageApi.setLanguage(newLanguage);
812
- };
813
- return /* @__PURE__ */ React.createElement(
814
- ListItem,
815
- {
816
- className: classes.list,
817
- classes: { container: classes.container }
818
- },
819
- /* @__PURE__ */ React.createElement(
820
- ListItemText,
821
- {
822
- className: classes.listItemText,
823
- primary: t("language"),
824
- secondary: t("change_the_language")
825
- }
826
- ),
827
- /* @__PURE__ */ React.createElement(ListItemSecondaryAction, { className: classes.listItemSecondaryAction }, /* @__PURE__ */ React.createElement(
828
- ToggleButtonGroup,
829
- {
830
- exclusive: true,
831
- size: "small",
832
- value: currentLanguage,
833
- onChange: handleSetLanguage
834
- },
835
- languages.map((language) => {
836
- return /* @__PURE__ */ React.createElement(
837
- TooltipToggleButton,
838
- {
839
- key: language,
840
- title: t("select_lng", { language }),
841
- value: language
842
- },
843
- /* @__PURE__ */ React.createElement(React.Fragment, null, language)
844
- );
845
- })
846
- ))
847
- );
848
- };
849
-
850
- const UserSettingsAppearanceCard = () => {
851
- const { isMobile } = useSidebarPinState();
852
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Appearance", variant: "gridItem" }, /* @__PURE__ */ React.createElement(List, { dense: true }, /* @__PURE__ */ React.createElement(UserSettingsThemeToggle, null), /* @__PURE__ */ React.createElement(UserSettingsLanguageToggle, null), !isMobile && /* @__PURE__ */ React.createElement(UserSettingsPinToggle, null)));
853
- };
854
-
855
- const Contents = () => {
856
- const { backstageIdentity } = useUserProfile();
857
- if (!backstageIdentity) {
858
- return /* @__PURE__ */ React.createElement(Typography$1, null, "No Backstage Identity");
859
- }
860
- return /* @__PURE__ */ React.createElement(Grid$1, { container: true, spacing: 1 }, /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "subtitle1", gutterBottom: true }, "User Entity:", " ", /* @__PURE__ */ React.createElement(
861
- EntityRefLinks,
862
- {
863
- entityRefs: [backstageIdentity.userEntityRef],
864
- getTitle: (ref) => ref
865
- }
866
- ))), /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "subtitle1" }, "Ownership Entities:", " ", /* @__PURE__ */ React.createElement(
867
- EntityRefLinks,
868
- {
869
- entityRefs: backstageIdentity.ownershipEntityRefs,
870
- getTitle: (ref) => ref
871
- }
872
- ))));
873
- };
874
- const UserSettingsIdentityCard = () => /* @__PURE__ */ React.createElement(InfoCard, { title: "Backstage Identity" }, /* @__PURE__ */ React.createElement(Contents, null));
875
-
876
- const UserSettingsGeneral = () => {
877
- return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row", spacing: 3 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(UserSettingsProfileCard, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(UserSettingsAppearanceCard, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(UserSettingsIdentityCard, null)));
878
- };
879
-
880
- const LAYOUT_DATA_KEY = "plugin.user-settings.settingsLayout";
881
- const LAYOUT_ROUTE_DATA_KEY = "plugin.user-settings.settingsLayoutRoute";
882
- const Route = () => null;
883
- attachComponentData(Route, LAYOUT_ROUTE_DATA_KEY, true);
884
- attachComponentData(Route, "core.gatherMountPoints", true);
885
- const SettingsLayout = (props) => {
886
- const { title, children } = props;
887
- const { isMobile } = useSidebarPinState();
888
- const routes = useElementFilter(
889
- children,
890
- (elements) => elements.selectByComponentData({
891
- key: LAYOUT_ROUTE_DATA_KEY,
892
- withStrictError: "Child of SettingsLayout must be an SettingsLayout.Route"
893
- }).getElements().map((child) => child.props)
894
- );
895
- return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, !isMobile && /* @__PURE__ */ React.createElement(Header, { title: title != null ? title : "Settings" }), /* @__PURE__ */ React.createElement(RoutedTabs, { routes }));
896
- };
897
- attachComponentData(SettingsLayout, LAYOUT_DATA_KEY, true);
898
- SettingsLayout.Route = Route;
899
-
900
- const DefaultSettingsPage = (props) => {
901
- const { providerSettings, tabs } = props;
902
- return /* @__PURE__ */ React.createElement(SettingsLayout, null, /* @__PURE__ */ React.createElement(SettingsLayout.Route, { path: "general", title: "General" }, /* @__PURE__ */ React.createElement(UserSettingsGeneral, null)), /* @__PURE__ */ React.createElement(
903
- SettingsLayout.Route,
904
- {
905
- path: "auth-providers",
906
- title: "Authentication Providers"
907
- },
908
- /* @__PURE__ */ React.createElement(UserSettingsAuthProviders, { providerSettings })
909
- ), /* @__PURE__ */ React.createElement(SettingsLayout.Route, { path: "feature-flags", title: "Feature Flags" }, /* @__PURE__ */ React.createElement(UserSettingsFeatureFlags, null)), tabs);
910
- };
911
-
912
- const SettingsPage = (props) => {
913
- const { providerSettings } = props;
914
- const outlet = useOutlet();
915
- const layout = useElementFilter(
916
- outlet,
917
- (elements) => elements.selectByComponentData({
918
- key: LAYOUT_DATA_KEY
919
- }).getElements()
920
- );
921
- const tabs = useElementFilter(
922
- outlet,
923
- (elements) => elements.selectByComponentData({
924
- key: LAYOUT_ROUTE_DATA_KEY
925
- }).getElements()
926
- );
927
- return /* @__PURE__ */ React.createElement(React.Fragment, null, layout.length !== 0 && layout || /* @__PURE__ */ React.createElement(DefaultSettingsPage, { tabs, providerSettings }));
928
- };
929
-
930
198
  const USER_SETTINGS_TAB_KEY = LAYOUT_ROUTE_DATA_KEY;
931
199
  const UserSettingsTab = (props) => /* @__PURE__ */ React.createElement(SettingsLayout.Route, { path: props.path, title: props.title }, /* @__PURE__ */ React.createElement(React.Fragment, null, "props.children"));
932
200
  attachComponentData(UserSettingsTab, USER_SETTINGS_TAB_KEY, "UserSettingsTab");
933
201
 
934
- export { DefaultProviderSettings, ProviderSettingsItem, SettingsPage as Router, Settings, SettingsLayout, USER_SETTINGS_TAB_KEY, UserSettingsAppearanceCard, UserSettingsAuthProviders, UserSettingsFeatureFlags, UserSettingsGeneral, UserSettingsIdentityCard, UserSettingsLanguageToggle, UserSettingsMenu, UserSettingsPage, UserSettingsPinToggle, UserSettingsProfileCard, UserSettingsSignInAvatar, UserSettingsStorage, UserSettingsTab, UserSettingsThemeToggle, userSettingsPlugin as plugin, useUserProfile, userSettingsPlugin };
202
+ export { Settings, USER_SETTINGS_TAB_KEY, UserSettingsPage, UserSettingsStorage, UserSettingsTab, userSettingsPlugin as plugin, userSettingsPlugin };
935
203
  //# sourceMappingURL=index.esm.js.map