@backstage/core-components 0.17.5-next.1 → 0.17.5
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/CHANGELOG.md +16 -0
- package/dist/components/AlertDisplay/AlertDisplay.esm.js +6 -3
- package/dist/components/AlertDisplay/AlertDisplay.esm.js.map +1 -1
- package/dist/components/AutoLogout/AutoLogout.esm.js.map +1 -1
- package/dist/components/AutoLogout/StillTherePrompt.esm.js.map +1 -1
- package/dist/components/AutoLogout/disconnectedUsers.esm.js.map +1 -1
- package/dist/components/AutoLogout/timestampStore.esm.js.map +1 -1
- package/dist/components/Avatar/Avatar.esm.js.map +1 -1
- package/dist/components/Avatar/utils.esm.js.map +1 -1
- package/dist/components/CodeSnippet/CodeSnippet.esm.js.map +1 -1
- package/dist/components/CopyTextButton/CopyTextButton.esm.js.map +1 -1
- package/dist/components/CreateButton/CreateButton.esm.js.map +1 -1
- package/dist/components/DependencyGraph/DefaultLabel.esm.js.map +1 -1
- package/dist/components/DependencyGraph/DefaultNode.esm.js.map +1 -1
- package/dist/components/DependencyGraph/DependencyGraph.esm.js.map +1 -1
- package/dist/components/DependencyGraph/Edge.esm.js +1 -1
- package/dist/components/DependencyGraph/Edge.esm.js.map +1 -1
- package/dist/components/DependencyGraph/Node.esm.js.map +1 -1
- package/dist/components/DependencyGraph/constants.esm.js.map +1 -1
- package/dist/components/DependencyGraph/types.esm.js.map +1 -1
- package/dist/components/DismissableBanner/DismissableBanner.esm.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.esm.js.map +1 -1
- package/dist/components/EmptyState/EmptyStateImage.esm.js.map +1 -1
- package/dist/components/EmptyState/MissingAnnotationEmptyState.esm.js.map +1 -1
- package/dist/components/ErrorPanel/ErrorPanel.esm.js.map +1 -1
- package/dist/components/FavoriteToggle/FavoriteToggle.esm.js.map +1 -1
- package/dist/components/FeatureDiscovery/FeatureCalloutCircular.esm.js.map +1 -1
- package/dist/components/FeatureDiscovery/lib/usePortal.esm.js.map +1 -1
- package/dist/components/FeatureDiscovery/lib/useShowCallout.esm.js.map +1 -1
- package/dist/components/HeaderIconLinkRow/HeaderIconLinkRow.esm.js.map +1 -1
- package/dist/components/HeaderIconLinkRow/IconLinkVertical.esm.js.map +1 -1
- package/dist/components/HorizontalScrollGrid/HorizontalScrollGrid.esm.js.map +1 -1
- package/dist/components/Lifecycle/Lifecycle.esm.js.map +1 -1
- package/dist/components/Link/Link.esm.js.map +1 -1
- package/dist/components/LinkButton/LinkButton.esm.js.map +1 -1
- package/dist/components/LogViewer/AnsiProcessor.esm.js.map +1 -1
- package/dist/components/LogViewer/LogLine.esm.js.map +1 -1
- package/dist/components/LogViewer/LogViewer.esm.js.map +1 -1
- package/dist/components/LogViewer/LogViewerControls.esm.js.map +1 -1
- package/dist/components/LogViewer/RealLogViewer.esm.js.map +1 -1
- package/dist/components/LogViewer/styles.esm.js.map +1 -1
- package/dist/components/LogViewer/useLogViewerSearch.esm.js.map +1 -1
- package/dist/components/LogViewer/useLogViewerSelection.esm.js.map +1 -1
- package/dist/components/MarkdownContent/MarkdownContent.esm.js.map +1 -1
- package/dist/components/OAuthRequestDialog/LoginRequestListItem.esm.js.map +1 -1
- package/dist/components/OAuthRequestDialog/OAuthRequestDialog.esm.js.map +1 -1
- package/dist/components/OverflowTooltip/OverflowTooltip.esm.js.map +1 -1
- package/dist/components/Progress/Progress.esm.js.map +1 -1
- package/dist/components/ProgressBars/Gauge.esm.js.map +1 -1
- package/dist/components/ProgressBars/GaugeCard.esm.js.map +1 -1
- package/dist/components/ProgressBars/LinearGauge.esm.js.map +1 -1
- package/dist/components/ResponseErrorPanel/ResponseErrorPanel.esm.js.map +1 -1
- package/dist/components/Select/Select.esm.js.map +1 -1
- package/dist/components/Select/static/ClosedDropdown.esm.js.map +1 -1
- package/dist/components/Select/static/OpenedDropdown.esm.js.map +1 -1
- package/dist/components/SimpleStepper/SimpleStepper.esm.js.map +1 -1
- package/dist/components/SimpleStepper/SimpleStepperFooter.esm.js.map +1 -1
- package/dist/components/SimpleStepper/SimpleStepperStep.esm.js.map +1 -1
- package/dist/components/Status/Status.esm.js.map +1 -1
- package/dist/components/Status/icons/AbortedIcon.esm.js.map +1 -1
- package/dist/components/Status/icons/PendingIcon.esm.js.map +1 -1
- package/dist/components/Status/icons/RunningIcon.esm.js.map +1 -1
- package/dist/components/StructuredMetadataTable/MetadataTable.esm.js.map +1 -1
- package/dist/components/StructuredMetadataTable/StructuredMetadataTable.esm.js.map +1 -1
- package/dist/components/SupportButton/SupportButton.esm.js.map +1 -1
- package/dist/components/TabbedLayout/RoutedTabs.esm.js.map +1 -1
- package/dist/components/TabbedLayout/TabbedLayout.esm.js.map +1 -1
- package/dist/components/Table/Filters.esm.js.map +1 -1
- package/dist/components/Table/SubvalueCell.esm.js.map +1 -1
- package/dist/components/Table/Table.esm.js.map +1 -1
- package/dist/components/Table/TableLoadingBody.esm.js.map +1 -1
- package/dist/components/TrendLine/TrendLine.esm.js.map +1 -1
- package/dist/components/WarningPanel/WarningPanel.esm.js.map +1 -1
- package/dist/hooks/useQueryParamState.esm.js.map +1 -1
- package/dist/hooks/useSupportConfig.esm.js.map +1 -1
- package/dist/icons/icons.esm.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/layout/BottomLink/BottomLink.esm.js.map +1 -1
- package/dist/layout/Breadcrumbs/Breadcrumbs.esm.js.map +1 -1
- package/dist/layout/Content/Content.esm.js.map +1 -1
- package/dist/layout/ContentHeader/ContentHeader.esm.js.map +1 -1
- package/dist/layout/ErrorBoundary/ErrorBoundary.esm.js.map +1 -1
- package/dist/layout/ErrorPage/ErrorPage.esm.js.map +1 -1
- package/dist/layout/ErrorPage/MicDrop.esm.js.map +1 -1
- package/dist/layout/ErrorPage/StackDetails.esm.js.map +1 -1
- package/dist/layout/Header/Header.esm.js.map +1 -1
- package/dist/layout/HeaderActionMenu/HeaderActionMenu.esm.js.map +1 -1
- package/dist/layout/HeaderLabel/HeaderLabel.esm.js.map +1 -1
- package/dist/layout/HeaderTabs/HeaderTabs.esm.js.map +1 -1
- package/dist/layout/InfoCard/InfoCard.esm.js.map +1 -1
- package/dist/layout/ItemCard/ItemCard.esm.js.map +1 -1
- package/dist/layout/ItemCard/ItemCardGrid.esm.js.map +1 -1
- package/dist/layout/ItemCard/ItemCardHeader.esm.js.map +1 -1
- package/dist/layout/Page/Page.esm.js.map +1 -1
- package/dist/layout/Page/PageWithHeader.esm.js.map +1 -1
- package/dist/layout/ProxiedSignInPage/ProxiedSignInIdentity.esm.js.map +1 -1
- package/dist/layout/ProxiedSignInPage/ProxiedSignInPage.esm.js.map +1 -1
- package/dist/layout/ProxiedSignInPage/types.esm.js.map +1 -1
- package/dist/layout/Sidebar/Bar.esm.js.map +1 -1
- package/dist/layout/Sidebar/Items.esm.js.map +1 -1
- package/dist/layout/Sidebar/MobileSidebar.esm.js.map +1 -1
- package/dist/layout/Sidebar/MobileSidebarContext.esm.js.map +1 -1
- package/dist/layout/Sidebar/Page.esm.js.map +1 -1
- package/dist/layout/Sidebar/SidebarGroup.esm.js.map +1 -1
- package/dist/layout/Sidebar/SidebarOpenStateContext.esm.js.map +1 -1
- package/dist/layout/Sidebar/SidebarPinStateContext.esm.js.map +1 -1
- package/dist/layout/Sidebar/SidebarSubmenu.esm.js.map +1 -1
- package/dist/layout/Sidebar/SidebarSubmenuItem.esm.js.map +1 -1
- package/dist/layout/Sidebar/config.esm.js.map +1 -1
- package/dist/layout/Sidebar/icons/DoubleArrowLeft.esm.js.map +1 -1
- package/dist/layout/Sidebar/icons/DoubleArrowRight.esm.js.map +1 -1
- package/dist/layout/Sidebar/localStorage.esm.js.map +1 -1
- package/dist/layout/Sidebar/utils.esm.js.map +1 -1
- package/dist/layout/SignInPage/GuestUserIdentity.esm.js.map +1 -1
- package/dist/layout/SignInPage/IdentityApiSignOutProxy.esm.js.map +1 -1
- package/dist/layout/SignInPage/LegacyUserIdentity.esm.js.map +1 -1
- package/dist/layout/SignInPage/SignInPage.esm.js.map +1 -1
- package/dist/layout/SignInPage/UserIdentity.esm.js.map +1 -1
- package/dist/layout/SignInPage/commonProvider.esm.js.map +1 -1
- package/dist/layout/SignInPage/customProvider.esm.js.map +1 -1
- package/dist/layout/SignInPage/guestProvider.esm.js +1 -1
- package/dist/layout/SignInPage/guestProvider.esm.js.map +1 -1
- package/dist/layout/SignInPage/providers.esm.js.map +1 -1
- package/dist/layout/SignInPage/styles.esm.js.map +1 -1
- package/dist/layout/TabbedCard/TabbedCard.esm.js.map +1 -1
- package/dist/testUtils.esm.js.map +1 -1
- package/dist/translation.esm.js.map +1 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @backstage/core-components
|
|
2
2
|
|
|
3
|
+
## 0.17.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1de1186: Added missing space for alert display component
|
|
8
|
+
- 77467bb: Updated dependency `linkifyjs` to `4.3.2`.
|
|
9
|
+
- 5563605: Added `FavoriteToggleProps`.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/theme@0.6.8
|
|
12
|
+
|
|
13
|
+
## 0.17.5-next.2
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 77467bb: Updated dependency `linkifyjs` to `4.3.2`.
|
|
18
|
+
|
|
3
19
|
## 0.17.5-next.1
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -59,9 +59,12 @@ function AlertDisplay(props) {
|
|
|
59
59
|
severity: firstMessage.severity,
|
|
60
60
|
children: /* @__PURE__ */ jsxs(Typography, { component: "span", children: [
|
|
61
61
|
String(firstMessage.message),
|
|
62
|
-
messages.length > 1 && /* @__PURE__ */
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
messages.length > 1 && /* @__PURE__ */ jsxs("em", { children: [
|
|
63
|
+
" ",
|
|
64
|
+
t("alertDisplay.message", {
|
|
65
|
+
count: messages.length - 1
|
|
66
|
+
})
|
|
67
|
+
] })
|
|
65
68
|
] })
|
|
66
69
|
}
|
|
67
70
|
) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlertDisplay.esm.js","sources":["../../../src/components/AlertDisplay/AlertDisplay.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { alertApiRef, AlertMessage, useApi } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport IconButton from '@material-ui/core/IconButton';\nimport Snackbar from '@material-ui/core/Snackbar';\nimport Typography from '@material-ui/core/Typography';\nimport CloseIcon from '@material-ui/icons/Close';\nimport Alert from '@material-ui/lab/Alert';\nimport { useEffect, useState } from 'react';\nimport { coreComponentsTranslationRef } from '../../translation';\n\n/**\n * Properties for {@link AlertDisplay}\n *\n * @public\n */\nexport type AlertDisplayProps = {\n anchorOrigin?: {\n vertical: 'top' | 'bottom';\n horizontal: 'left' | 'center' | 'right';\n };\n transientTimeoutMs?: number;\n};\n\n/**\n * Displays alerts from {@link @backstage/core-plugin-api#AlertApi}\n *\n * @public\n * @remarks\n *\n * Shown as SnackBar at the center top of the page by default. Configurable with props.\n *\n * @param anchorOrigin - The `vertical` property will set the vertical orientation of where the AlertDisplay will be located\n * and the `horizontal` property will set the horizontal orientation of where the AlertDisplay will be located\n * @param transientTimeoutMs - Number of milliseconds a transient alert will stay open for. Default value is 5000\n *\n * @example\n * Here's some examples:\n * ```\n * // This example shows the default usage, the SnackBar will show up at the top in the center and any transient messages will stay open for 5000ms\n * <AlertDisplay />\n *\n * // With this example the SnackBar will show up in the bottom right hand corner and any transient messages will stay open for 2500ms\n * <AlertDisplay transientTimeoutMs={2500} anchorOrigin={{vertical: 'bottom', horizontal: 'right'}}/>\n *\n * // If you want to just set the time a transientTimeoutMs, you can do that like this:\n * <AlertDisplay transientTimeoutMs={10000} />\n * ```\n */\nexport function AlertDisplay(props: AlertDisplayProps) {\n const [messages, setMessages] = useState<Array<AlertMessage>>([]);\n const alertApi = useApi(alertApiRef);\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n\n const {\n anchorOrigin = { vertical: 'top', horizontal: 'center' },\n transientTimeoutMs,\n } = props;\n const timeoutMs = transientTimeoutMs ?? 5000;\n\n useEffect(() => {\n const subscription = alertApi\n .alert$()\n .subscribe(message => setMessages(msgs => msgs.concat(message)));\n\n return () => {\n subscription.unsubscribe();\n };\n }, [alertApi]);\n\n const [firstMessage] = messages;\n\n useEffect(() => {\n if (firstMessage && firstMessage.display === 'transient') {\n const timeout = setTimeout(() => {\n setMessages(msgs => {\n const newMsgs = msgs.filter(msg => msg !== firstMessage);\n return newMsgs.length === msgs.length ? msgs : newMsgs;\n });\n }, timeoutMs);\n return () => clearTimeout(timeout);\n }\n return undefined;\n }, [firstMessage, timeoutMs]);\n\n if (messages.length === 0) {\n return null;\n }\n\n const handleClose = () => {\n setMessages(msgs => msgs.filter(msg => msg !== firstMessage));\n };\n\n return (\n <Snackbar open anchorOrigin={anchorOrigin}>\n <Alert\n action={\n <IconButton\n color=\"inherit\"\n size=\"small\"\n onClick={handleClose}\n data-testid=\"error-button-close\"\n >\n <CloseIcon />\n </IconButton>\n }\n severity={firstMessage.severity}\n >\n <Typography component=\"span\">\n {String(firstMessage.message)}\n {messages.length > 1 && (\n <em>\n {t('alertDisplay.message', {\n count: messages.length - 1,\n })}\n </em>\n )}\n </Typography>\n </Alert>\n </Snackbar>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA+DO,SAAS,aAAa,
|
|
1
|
+
{"version":3,"file":"AlertDisplay.esm.js","sources":["../../../src/components/AlertDisplay/AlertDisplay.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { alertApiRef, AlertMessage, useApi } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport IconButton from '@material-ui/core/IconButton';\nimport Snackbar from '@material-ui/core/Snackbar';\nimport Typography from '@material-ui/core/Typography';\nimport CloseIcon from '@material-ui/icons/Close';\nimport Alert from '@material-ui/lab/Alert';\nimport { useEffect, useState } from 'react';\nimport { coreComponentsTranslationRef } from '../../translation';\n\n/**\n * Properties for {@link AlertDisplay}\n *\n * @public\n */\nexport type AlertDisplayProps = {\n anchorOrigin?: {\n vertical: 'top' | 'bottom';\n horizontal: 'left' | 'center' | 'right';\n };\n transientTimeoutMs?: number;\n};\n\n/**\n * Displays alerts from {@link @backstage/core-plugin-api#AlertApi}\n *\n * @public\n * @remarks\n *\n * Shown as SnackBar at the center top of the page by default. Configurable with props.\n *\n * @param anchorOrigin - The `vertical` property will set the vertical orientation of where the AlertDisplay will be located\n * and the `horizontal` property will set the horizontal orientation of where the AlertDisplay will be located\n * @param transientTimeoutMs - Number of milliseconds a transient alert will stay open for. Default value is 5000\n *\n * @example\n * Here's some examples:\n * ```\n * // This example shows the default usage, the SnackBar will show up at the top in the center and any transient messages will stay open for 5000ms\n * <AlertDisplay />\n *\n * // With this example the SnackBar will show up in the bottom right hand corner and any transient messages will stay open for 2500ms\n * <AlertDisplay transientTimeoutMs={2500} anchorOrigin={{vertical: 'bottom', horizontal: 'right'}}/>\n *\n * // If you want to just set the time a transientTimeoutMs, you can do that like this:\n * <AlertDisplay transientTimeoutMs={10000} />\n * ```\n */\nexport function AlertDisplay(props: AlertDisplayProps) {\n const [messages, setMessages] = useState<Array<AlertMessage>>([]);\n const alertApi = useApi(alertApiRef);\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n\n const {\n anchorOrigin = { vertical: 'top', horizontal: 'center' },\n transientTimeoutMs,\n } = props;\n const timeoutMs = transientTimeoutMs ?? 5000;\n\n useEffect(() => {\n const subscription = alertApi\n .alert$()\n .subscribe(message => setMessages(msgs => msgs.concat(message)));\n\n return () => {\n subscription.unsubscribe();\n };\n }, [alertApi]);\n\n const [firstMessage] = messages;\n\n useEffect(() => {\n if (firstMessage && firstMessage.display === 'transient') {\n const timeout = setTimeout(() => {\n setMessages(msgs => {\n const newMsgs = msgs.filter(msg => msg !== firstMessage);\n return newMsgs.length === msgs.length ? msgs : newMsgs;\n });\n }, timeoutMs);\n return () => clearTimeout(timeout);\n }\n return undefined;\n }, [firstMessage, timeoutMs]);\n\n if (messages.length === 0) {\n return null;\n }\n\n const handleClose = () => {\n setMessages(msgs => msgs.filter(msg => msg !== firstMessage));\n };\n\n return (\n <Snackbar open anchorOrigin={anchorOrigin}>\n <Alert\n action={\n <IconButton\n color=\"inherit\"\n size=\"small\"\n onClick={handleClose}\n data-testid=\"error-button-close\"\n >\n <CloseIcon />\n </IconButton>\n }\n severity={firstMessage.severity}\n >\n <Typography component=\"span\">\n {String(firstMessage.message)}\n {messages.length > 1 && (\n <em>\n {' '}\n {t('alertDisplay.message', {\n count: messages.length - 1,\n })}\n </em>\n )}\n </Typography>\n </Alert>\n </Snackbar>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoLogout.esm.js","sources":["../../../src/components/AutoLogout/AutoLogout.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ConfigApi,\n configApiRef,\n IdentityApi,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n EventsType,\n IIdleTimer,\n workerTimers,\n useIdleTimer,\n} from 'react-idle-timer';\n\nimport {\n LAST_SEEN_ONLINE_STORAGE_KEY,\n useLogoutDisconnectedUserEffect,\n} from './disconnectedUsers';\nimport { StillTherePrompt } from './StillTherePrompt';\nimport { DefaultTimestampStore, TimestampStore } from './timestampStore';\n\ntype AutoLogoutTrackableEvent = EventsType;\n\n/** @public */\nexport type AutoLogoutProps = {\n /**\n * Enable/disable the AutoLogoutMechanism.\n * defaults to true.\n */\n enabled?: boolean;\n /**\n * The amount of time (in minutes) of inactivity\n * after which the user is automatically logged out.\n * defaults to 60 minutes.\n */\n idleTimeoutMinutes?: number;\n /**\n * The number of seconds before the idleTimeout expires,\n * at which the user will be alerted by a Dialog that\n * they are about to be logged out.\n * defaults to 10 seconds\n */\n promptBeforeIdleSeconds?: number;\n /**\n * Enable/disable the usage of Node's worker thread timers instead of main thread timers.\n * This is helpful if you notice that the your browser is killing inactive tab's timers, like the one used by AutoLogout.\n * If you experience some browser incompatibility, you may try to set this to false.\n * defaults to true.\n */\n useWorkerTimers?: boolean;\n /**\n * Enable/disable the autologout for disconnected users.\n * disconnected users are the ones that are logged in but have no Backstage tab open in their browsers.\n * If enabled, disconnected users will be automatically logged out after `idleTimeoutMinutes`\n * defaults to true\n */\n logoutIfDisconnected?: boolean;\n};\n\ntype AutoLogoutInternalProps = Omit<Required<AutoLogoutProps>, 'enabled'> & {\n events: AutoLogoutTrackableEvent[];\n promptOpen: boolean;\n setPromptOpen: (value: boolean) => void;\n remainingTimeCountdown: number;\n setRemainingTimeCountdown: (amount: number) => void;\n identityApi: IdentityApi;\n lastSeenOnlineStore: TimestampStore;\n};\n\nconst ConditionalAutoLogout = ({\n idleTimeoutMinutes,\n events,\n useWorkerTimers,\n logoutIfDisconnected,\n promptBeforeIdleSeconds,\n promptOpen,\n setPromptOpen,\n remainingTimeCountdown,\n setRemainingTimeCountdown,\n identityApi,\n lastSeenOnlineStore,\n}: AutoLogoutInternalProps): JSX.Element => {\n const promptBeforeIdleMillis = promptBeforeIdleSeconds * 1000;\n const promptBeforeIdle = promptBeforeIdleMillis > 0 ? true : false;\n\n const onPrompt = async () => {\n // onPrompt will be called `promptBeforeIdle` milliseconds before `timeout`.\n // All events are disabled while the prompt is active.\n // If the user wishes to stay active, call the `activate()` method.\n // You can get the remaining prompt time with the `getRemainingTime()` method,\n setPromptOpen(true);\n setRemainingTimeCountdown(promptBeforeIdleMillis);\n };\n\n const onIdle = () => {\n // onIdle will be called after the timeout is reached.\n // Events will be rebound as long as `stopOnMount` is not set.\n setPromptOpen(false);\n setRemainingTimeCountdown(0);\n identityApi.signOut();\n };\n\n const onActive = () => {\n // onActive will only be called if `activate()` is called while `isPrompted()`\n // is true. Here you will also want to close your modal and perform\n // any active actions.\n setPromptOpen(false);\n setRemainingTimeCountdown(0);\n };\n\n const onAction = (\n _event?: Event | undefined,\n _idleTimer?: IIdleTimer | null,\n ) => {\n // onAction will be called if any user event is detected. The list of events that triggers a user event detection is the list of configured events\n // If any user event is detected we update the Last seen online in storage\n lastSeenOnlineStore.save(new Date());\n };\n\n const timer = useIdleTimer({\n timeout: idleTimeoutMinutes * 60 * 1000,\n events: events,\n crossTab: true,\n name: 'autologout-timer',\n timers: useWorkerTimers ? workerTimers : undefined,\n onIdle: onIdle,\n onActive: promptBeforeIdle ? onActive : undefined,\n onAction: logoutIfDisconnected ? onAction : undefined,\n onPrompt: promptBeforeIdle ? onPrompt : undefined,\n promptBeforeIdle: promptBeforeIdle ? promptBeforeIdleMillis : undefined,\n syncTimers: 1000,\n });\n\n return (\n <>\n {promptBeforeIdle && (\n <StillTherePrompt\n idleTimer={timer}\n open={promptOpen}\n setOpen={setPromptOpen}\n remainingTime={remainingTimeCountdown}\n setRemainingTime={setRemainingTimeCountdown}\n promptTimeoutMillis={promptBeforeIdleMillis}\n />\n )}\n </>\n );\n};\n\nconst defaultConfig: Required<AutoLogoutProps> = {\n enabled: true,\n idleTimeoutMinutes: 0.5,\n promptBeforeIdleSeconds: 10,\n useWorkerTimers: true,\n logoutIfDisconnected: true,\n};\n\n/**\n * A list of DOM events that the activity tracker will use to determine if the user is active or not.\n */\nconst defaultTrackedEvents: AutoLogoutTrackableEvent[] = [\n 'mousemove',\n 'keydown',\n 'wheel',\n 'DOMMouseScroll',\n 'mousewheel',\n 'mousedown',\n 'touchstart',\n 'touchmove',\n 'MSPointerDown',\n 'MSPointerMove',\n 'visibilitychange',\n];\n\n/**\n * Parses configuration for the AutoLogout. Properties configured in `app-config` take precedence over the props passed to the React component.\n * If neither props nor config properties are found, a default value will be set accordingly.\n */\nconst parseConfig = (\n configApi: ConfigApi,\n props: AutoLogoutProps,\n): Required<AutoLogoutProps> => {\n return {\n enabled:\n configApi.getOptionalBoolean('auth.autologout.enabled') ??\n props.enabled ??\n defaultConfig.enabled,\n idleTimeoutMinutes:\n configApi.getOptionalNumber('auth.autologout.idleTimeoutMinutes') ??\n props.idleTimeoutMinutes ??\n defaultConfig.idleTimeoutMinutes,\n promptBeforeIdleSeconds:\n configApi.getOptionalNumber('auth.autologout.promptBeforeIdleSeconds') ??\n props.promptBeforeIdleSeconds ??\n defaultConfig.promptBeforeIdleSeconds,\n useWorkerTimers:\n configApi.getOptionalBoolean('auth.autologout.useWorkerTimers') ??\n props.useWorkerTimers ??\n defaultConfig.useWorkerTimers,\n logoutIfDisconnected:\n configApi.getOptionalBoolean('auth.autologout.logoutIfDisconnected') ??\n props.logoutIfDisconnected ??\n defaultConfig.logoutIfDisconnected,\n };\n};\n\n/**\n * The Autologout feature enables platform engineers to add a mechanism to log out users after a configurable amount of time of inactivity.\n * When enabled, the mechanism will track user actions (mouse movement, mouse click, key pressing, taps, etc.) in order to determine if they are active or not.\n * After a certain amount of inactivity/idle time, the user session is invalidated and they are required to sign in again.\n *\n * @public\n */\nexport const AutoLogout = (props: AutoLogoutProps): JSX.Element | null => {\n const identityApi = useApi(identityApiRef);\n const configApi = useApi(configApiRef);\n const [isLogged, setIsLogged] = useState(false);\n useEffect(() => {\n // if the user is not logged in, the autologout feature won't affect the app even if enabled\n async function isLoggedIn(identity: IdentityApi) {\n if ((await identity.getCredentials()).token) {\n setIsLogged(true);\n } else {\n setIsLogged(false);\n }\n }\n isLoggedIn(identityApi);\n }, [identityApi]);\n\n const {\n enabled,\n idleTimeoutMinutes,\n promptBeforeIdleSeconds,\n logoutIfDisconnected,\n useWorkerTimers,\n }: AutoLogoutProps = useMemo(() => {\n return parseConfig(configApi, props);\n }, [configApi, props]);\n\n useEffect(() => {\n if (idleTimeoutMinutes < 0.5) {\n throw new Error(\n '❌ idleTimeoutMinutes property should be >= 0.5 minutes (30 seconds).',\n );\n }\n\n if (promptBeforeIdleSeconds < 0) {\n throw new Error(\n '❌ promptBeforeIdleSeconds property should be >= 0 seconds. Set to 0 to disable the prompt.',\n );\n }\n\n if (idleTimeoutMinutes * 60 <= promptBeforeIdleSeconds) {\n throw new Error(\n `❌ promptBeforeIdleSeconds should be smaller than idleTimeoutMinutes`,\n );\n }\n }, [idleTimeoutMinutes, promptBeforeIdleSeconds]);\n\n const lastSeenOnlineStore: TimestampStore = useMemo(\n () => new DefaultTimestampStore(LAST_SEEN_ONLINE_STORAGE_KEY),\n [],\n );\n const [promptOpen, setPromptOpen] = useState<boolean>(false);\n\n const [remainingTimeCountdown, setRemainingTimeCountdown] =\n useState<number>(0);\n\n useLogoutDisconnectedUserEffect({\n enableEffect: logoutIfDisconnected,\n autologoutIsEnabled: enabled && isLogged,\n idleTimeoutSeconds: idleTimeoutMinutes * 60,\n lastSeenOnlineStore,\n identityApi,\n });\n\n if (!enabled || !isLogged) {\n return null;\n }\n\n return (\n <ConditionalAutoLogout\n idleTimeoutMinutes={idleTimeoutMinutes}\n promptBeforeIdleSeconds={promptBeforeIdleSeconds}\n useWorkerTimers={useWorkerTimers}\n events={defaultTrackedEvents}\n logoutIfDisconnected={logoutIfDisconnected}\n promptOpen={promptOpen}\n setPromptOpen={setPromptOpen}\n remainingTimeCountdown={remainingTimeCountdown}\n setRemainingTimeCountdown={setRemainingTimeCountdown}\n identityApi={identityApi}\n lastSeenOnlineStore={lastSeenOnlineStore}\n />\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AutoLogout.esm.js","sources":["../../../src/components/AutoLogout/AutoLogout.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ConfigApi,\n configApiRef,\n IdentityApi,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n EventsType,\n IIdleTimer,\n workerTimers,\n useIdleTimer,\n} from 'react-idle-timer';\n\nimport {\n LAST_SEEN_ONLINE_STORAGE_KEY,\n useLogoutDisconnectedUserEffect,\n} from './disconnectedUsers';\nimport { StillTherePrompt } from './StillTherePrompt';\nimport { DefaultTimestampStore, TimestampStore } from './timestampStore';\n\ntype AutoLogoutTrackableEvent = EventsType;\n\n/** @public */\nexport type AutoLogoutProps = {\n /**\n * Enable/disable the AutoLogoutMechanism.\n * defaults to true.\n */\n enabled?: boolean;\n /**\n * The amount of time (in minutes) of inactivity\n * after which the user is automatically logged out.\n * defaults to 60 minutes.\n */\n idleTimeoutMinutes?: number;\n /**\n * The number of seconds before the idleTimeout expires,\n * at which the user will be alerted by a Dialog that\n * they are about to be logged out.\n * defaults to 10 seconds\n */\n promptBeforeIdleSeconds?: number;\n /**\n * Enable/disable the usage of Node's worker thread timers instead of main thread timers.\n * This is helpful if you notice that the your browser is killing inactive tab's timers, like the one used by AutoLogout.\n * If you experience some browser incompatibility, you may try to set this to false.\n * defaults to true.\n */\n useWorkerTimers?: boolean;\n /**\n * Enable/disable the autologout for disconnected users.\n * disconnected users are the ones that are logged in but have no Backstage tab open in their browsers.\n * If enabled, disconnected users will be automatically logged out after `idleTimeoutMinutes`\n * defaults to true\n */\n logoutIfDisconnected?: boolean;\n};\n\ntype AutoLogoutInternalProps = Omit<Required<AutoLogoutProps>, 'enabled'> & {\n events: AutoLogoutTrackableEvent[];\n promptOpen: boolean;\n setPromptOpen: (value: boolean) => void;\n remainingTimeCountdown: number;\n setRemainingTimeCountdown: (amount: number) => void;\n identityApi: IdentityApi;\n lastSeenOnlineStore: TimestampStore;\n};\n\nconst ConditionalAutoLogout = ({\n idleTimeoutMinutes,\n events,\n useWorkerTimers,\n logoutIfDisconnected,\n promptBeforeIdleSeconds,\n promptOpen,\n setPromptOpen,\n remainingTimeCountdown,\n setRemainingTimeCountdown,\n identityApi,\n lastSeenOnlineStore,\n}: AutoLogoutInternalProps): JSX.Element => {\n const promptBeforeIdleMillis = promptBeforeIdleSeconds * 1000;\n const promptBeforeIdle = promptBeforeIdleMillis > 0 ? true : false;\n\n const onPrompt = async () => {\n // onPrompt will be called `promptBeforeIdle` milliseconds before `timeout`.\n // All events are disabled while the prompt is active.\n // If the user wishes to stay active, call the `activate()` method.\n // You can get the remaining prompt time with the `getRemainingTime()` method,\n setPromptOpen(true);\n setRemainingTimeCountdown(promptBeforeIdleMillis);\n };\n\n const onIdle = () => {\n // onIdle will be called after the timeout is reached.\n // Events will be rebound as long as `stopOnMount` is not set.\n setPromptOpen(false);\n setRemainingTimeCountdown(0);\n identityApi.signOut();\n };\n\n const onActive = () => {\n // onActive will only be called if `activate()` is called while `isPrompted()`\n // is true. Here you will also want to close your modal and perform\n // any active actions.\n setPromptOpen(false);\n setRemainingTimeCountdown(0);\n };\n\n const onAction = (\n _event?: Event | undefined,\n _idleTimer?: IIdleTimer | null,\n ) => {\n // onAction will be called if any user event is detected. The list of events that triggers a user event detection is the list of configured events\n // If any user event is detected we update the Last seen online in storage\n lastSeenOnlineStore.save(new Date());\n };\n\n const timer = useIdleTimer({\n timeout: idleTimeoutMinutes * 60 * 1000,\n events: events,\n crossTab: true,\n name: 'autologout-timer',\n timers: useWorkerTimers ? workerTimers : undefined,\n onIdle: onIdle,\n onActive: promptBeforeIdle ? onActive : undefined,\n onAction: logoutIfDisconnected ? onAction : undefined,\n onPrompt: promptBeforeIdle ? onPrompt : undefined,\n promptBeforeIdle: promptBeforeIdle ? promptBeforeIdleMillis : undefined,\n syncTimers: 1000,\n });\n\n return (\n <>\n {promptBeforeIdle && (\n <StillTherePrompt\n idleTimer={timer}\n open={promptOpen}\n setOpen={setPromptOpen}\n remainingTime={remainingTimeCountdown}\n setRemainingTime={setRemainingTimeCountdown}\n promptTimeoutMillis={promptBeforeIdleMillis}\n />\n )}\n </>\n );\n};\n\nconst defaultConfig: Required<AutoLogoutProps> = {\n enabled: true,\n idleTimeoutMinutes: 0.5,\n promptBeforeIdleSeconds: 10,\n useWorkerTimers: true,\n logoutIfDisconnected: true,\n};\n\n/**\n * A list of DOM events that the activity tracker will use to determine if the user is active or not.\n */\nconst defaultTrackedEvents: AutoLogoutTrackableEvent[] = [\n 'mousemove',\n 'keydown',\n 'wheel',\n 'DOMMouseScroll',\n 'mousewheel',\n 'mousedown',\n 'touchstart',\n 'touchmove',\n 'MSPointerDown',\n 'MSPointerMove',\n 'visibilitychange',\n];\n\n/**\n * Parses configuration for the AutoLogout. Properties configured in `app-config` take precedence over the props passed to the React component.\n * If neither props nor config properties are found, a default value will be set accordingly.\n */\nconst parseConfig = (\n configApi: ConfigApi,\n props: AutoLogoutProps,\n): Required<AutoLogoutProps> => {\n return {\n enabled:\n configApi.getOptionalBoolean('auth.autologout.enabled') ??\n props.enabled ??\n defaultConfig.enabled,\n idleTimeoutMinutes:\n configApi.getOptionalNumber('auth.autologout.idleTimeoutMinutes') ??\n props.idleTimeoutMinutes ??\n defaultConfig.idleTimeoutMinutes,\n promptBeforeIdleSeconds:\n configApi.getOptionalNumber('auth.autologout.promptBeforeIdleSeconds') ??\n props.promptBeforeIdleSeconds ??\n defaultConfig.promptBeforeIdleSeconds,\n useWorkerTimers:\n configApi.getOptionalBoolean('auth.autologout.useWorkerTimers') ??\n props.useWorkerTimers ??\n defaultConfig.useWorkerTimers,\n logoutIfDisconnected:\n configApi.getOptionalBoolean('auth.autologout.logoutIfDisconnected') ??\n props.logoutIfDisconnected ??\n defaultConfig.logoutIfDisconnected,\n };\n};\n\n/**\n * The Autologout feature enables platform engineers to add a mechanism to log out users after a configurable amount of time of inactivity.\n * When enabled, the mechanism will track user actions (mouse movement, mouse click, key pressing, taps, etc.) in order to determine if they are active or not.\n * After a certain amount of inactivity/idle time, the user session is invalidated and they are required to sign in again.\n *\n * @public\n */\nexport const AutoLogout = (props: AutoLogoutProps): JSX.Element | null => {\n const identityApi = useApi(identityApiRef);\n const configApi = useApi(configApiRef);\n const [isLogged, setIsLogged] = useState(false);\n useEffect(() => {\n // if the user is not logged in, the autologout feature won't affect the app even if enabled\n async function isLoggedIn(identity: IdentityApi) {\n if ((await identity.getCredentials()).token) {\n setIsLogged(true);\n } else {\n setIsLogged(false);\n }\n }\n isLoggedIn(identityApi);\n }, [identityApi]);\n\n const {\n enabled,\n idleTimeoutMinutes,\n promptBeforeIdleSeconds,\n logoutIfDisconnected,\n useWorkerTimers,\n }: AutoLogoutProps = useMemo(() => {\n return parseConfig(configApi, props);\n }, [configApi, props]);\n\n useEffect(() => {\n if (idleTimeoutMinutes < 0.5) {\n throw new Error(\n '❌ idleTimeoutMinutes property should be >= 0.5 minutes (30 seconds).',\n );\n }\n\n if (promptBeforeIdleSeconds < 0) {\n throw new Error(\n '❌ promptBeforeIdleSeconds property should be >= 0 seconds. Set to 0 to disable the prompt.',\n );\n }\n\n if (idleTimeoutMinutes * 60 <= promptBeforeIdleSeconds) {\n throw new Error(\n `❌ promptBeforeIdleSeconds should be smaller than idleTimeoutMinutes`,\n );\n }\n }, [idleTimeoutMinutes, promptBeforeIdleSeconds]);\n\n const lastSeenOnlineStore: TimestampStore = useMemo(\n () => new DefaultTimestampStore(LAST_SEEN_ONLINE_STORAGE_KEY),\n [],\n );\n const [promptOpen, setPromptOpen] = useState<boolean>(false);\n\n const [remainingTimeCountdown, setRemainingTimeCountdown] =\n useState<number>(0);\n\n useLogoutDisconnectedUserEffect({\n enableEffect: logoutIfDisconnected,\n autologoutIsEnabled: enabled && isLogged,\n idleTimeoutSeconds: idleTimeoutMinutes * 60,\n lastSeenOnlineStore,\n identityApi,\n });\n\n if (!enabled || !isLogged) {\n return null;\n }\n\n return (\n <ConditionalAutoLogout\n idleTimeoutMinutes={idleTimeoutMinutes}\n promptBeforeIdleSeconds={promptBeforeIdleSeconds}\n useWorkerTimers={useWorkerTimers}\n events={defaultTrackedEvents}\n logoutIfDisconnected={logoutIfDisconnected}\n promptOpen={promptOpen}\n setPromptOpen={setPromptOpen}\n remainingTimeCountdown={remainingTimeCountdown}\n setRemainingTimeCountdown={setRemainingTimeCountdown}\n identityApi={identityApi}\n lastSeenOnlineStore={lastSeenOnlineStore}\n />\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StillTherePrompt.esm.js","sources":["../../../src/components/AutoLogout/StillTherePrompt.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport { useEffect } from 'react';\nimport { IIdleTimer } from 'react-idle-timer';\nimport { coreComponentsTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nexport interface StillTherePromptProps {\n idleTimer: IIdleTimer;\n promptTimeoutMillis: number;\n remainingTime: number;\n setRemainingTime: (amount: number) => void;\n open: boolean;\n setOpen: (value: boolean) => void;\n}\n\nexport const StillTherePrompt = (props: StillTherePromptProps) => {\n const {\n idleTimer,\n setOpen,\n open,\n promptTimeoutMillis,\n remainingTime,\n setRemainingTime,\n } = props;\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n\n useEffect(() => {\n const interval = setInterval(() => {\n setRemainingTime(Math.ceil(idleTimer.getRemainingTime()));\n }, 500);\n\n return () => {\n clearInterval(interval);\n };\n }, [idleTimer, setRemainingTime]);\n\n const handleStillHere = () => {\n setOpen(false);\n idleTimer.activate();\n };\n\n const timeTillPrompt = Math.max(\n remainingTime - promptTimeoutMillis / 1000,\n 0,\n );\n const seconds = timeTillPrompt > 1 ? 'seconds' : 'second';\n\n return (\n <Dialog open={open} data-testid=\"inactivity-prompt-dialog\">\n <DialogTitle>{t('autoLogout.stillTherePrompt.title')}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n You are about to be disconnected in{' '}\n <b>\n {Math.ceil(remainingTime / 1000)} {seconds}\n </b>\n . Are you still there?\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={handleStillHere}\n color=\"secondary\"\n variant=\"contained\"\n size=\"small\"\n >\n {t('autoLogout.stillTherePrompt.buttonText')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"StillTherePrompt.esm.js","sources":["../../../src/components/AutoLogout/StillTherePrompt.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport { useEffect } from 'react';\nimport { IIdleTimer } from 'react-idle-timer';\nimport { coreComponentsTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nexport interface StillTherePromptProps {\n idleTimer: IIdleTimer;\n promptTimeoutMillis: number;\n remainingTime: number;\n setRemainingTime: (amount: number) => void;\n open: boolean;\n setOpen: (value: boolean) => void;\n}\n\nexport const StillTherePrompt = (props: StillTherePromptProps) => {\n const {\n idleTimer,\n setOpen,\n open,\n promptTimeoutMillis,\n remainingTime,\n setRemainingTime,\n } = props;\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n\n useEffect(() => {\n const interval = setInterval(() => {\n setRemainingTime(Math.ceil(idleTimer.getRemainingTime()));\n }, 500);\n\n return () => {\n clearInterval(interval);\n };\n }, [idleTimer, setRemainingTime]);\n\n const handleStillHere = () => {\n setOpen(false);\n idleTimer.activate();\n };\n\n const timeTillPrompt = Math.max(\n remainingTime - promptTimeoutMillis / 1000,\n 0,\n );\n const seconds = timeTillPrompt > 1 ? 'seconds' : 'second';\n\n return (\n <Dialog open={open} data-testid=\"inactivity-prompt-dialog\">\n <DialogTitle>{t('autoLogout.stillTherePrompt.title')}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n You are about to be disconnected in{' '}\n <b>\n {Math.ceil(remainingTime / 1000)} {seconds}\n </b>\n . Are you still there?\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={handleStillHere}\n color=\"secondary\"\n variant=\"contained\"\n size=\"small\"\n >\n {t('autoLogout.stillTherePrompt.buttonText')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAoCO,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAiC;AAChE,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,OAAA;AAAA,IACA,IAAA;AAAA,IACA,mBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AACJ,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,4BAA4B,CAAA;AAE5D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,MAAA,gBAAA,CAAiB,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,gBAAA,EAAkB,CAAC,CAAA;AAAA,IAC1D,GAAG,GAAG,CAAA;AAEN,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,QAAQ,CAAA;AAAA,IACxB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,SAAA,EAAW,gBAAgB,CAAC,CAAA;AAEhC,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,OAAA,CAAQ,KAAK,CAAA;AACb,IAAA,SAAA,CAAU,QAAA,EAAS;AAAA,EACrB,CAAA;AAEA,EAAA,MAAM,iBAAiB,IAAA,CAAK,GAAA;AAAA,IAC1B,gBAAgB,mBAAA,GAAsB,GAAA;AAAA,IACtC;AAAA,GACF;AACA,EAAA,MAAM,OAAA,GAAU,cAAA,GAAiB,CAAA,GAAI,SAAA,GAAY,QAAA;AAEjD,EAAA,uBACE,IAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAY,aAAA,EAAY,0BAAA,EAC9B,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,WAAA,EAAA,EAAa,QAAA,EAAA,CAAA,CAAE,mCAAmC,CAAA,EAAE,CAAA;AAAA,oBACrD,GAAA,CAAC,aAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,iBAAA,EAAA,EAAkB,QAAA,EAAA;AAAA,MAAA,qCAAA;AAAA,MACmB,GAAA;AAAA,2BACnC,GAAA,EAAA,EACE,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,IAAA,CAAK,gBAAgB,GAAI,CAAA;AAAA,QAAE,GAAA;AAAA,QAAE;AAAA,OAAA,EACrC,CAAA;AAAA,MAAI;AAAA,KAAA,EAEN,CAAA,EACF,CAAA;AAAA,wBACC,aAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,eAAA;AAAA,QACT,KAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAQ,WAAA;AAAA,QACR,IAAA,EAAK,OAAA;AAAA,QAEJ,YAAE,wCAAwC;AAAA;AAAA,KAC7C,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disconnectedUsers.esm.js","sources":["../../../src/components/AutoLogout/disconnectedUsers.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { IdentityApi } from '@backstage/core-plugin-api';\nimport { useEffect } from 'react';\n\nimport { TimestampStore } from './timestampStore';\n\nexport const LAST_SEEN_ONLINE_STORAGE_KEY =\n '@backstage/autologout:lastSeenOnline';\n\nexport type UseLogoutDisconnectedUserEffectProps = {\n enableEffect: boolean;\n autologoutIsEnabled: boolean;\n idleTimeoutSeconds: number;\n lastSeenOnlineStore: TimestampStore;\n identityApi: IdentityApi;\n};\n\nexport const useLogoutDisconnectedUserEffect = ({\n enableEffect,\n autologoutIsEnabled,\n idleTimeoutSeconds,\n lastSeenOnlineStore,\n identityApi,\n}: UseLogoutDisconnectedUserEffectProps) => {\n useEffect(() => {\n /**\n * Considers disconnected users as inactive users.\n * If all Backstage tabs are closed and idleTimeoutMinutes are passed then logout the user anyway.\n */\n if (autologoutIsEnabled && enableEffect) {\n const lastSeenOnline = lastSeenOnlineStore.get();\n if (lastSeenOnline) {\n const now = new Date();\n const nowSeconds = Math.ceil(now.getTime() / 1000);\n const lastSeenOnlineSeconds = Math.ceil(\n lastSeenOnline.getTime() / 1000,\n );\n if (nowSeconds - lastSeenOnlineSeconds > idleTimeoutSeconds) {\n identityApi.signOut();\n }\n }\n /**\n * save for the first time when app is loaded, so that\n * if user logs in and does nothing we still have a\n * lastSeenOnline value in store\n */\n lastSeenOnlineStore.save(new Date());\n } else {\n lastSeenOnlineStore.delete();\n }\n }, [\n autologoutIsEnabled,\n enableEffect,\n identityApi,\n idleTimeoutSeconds,\n lastSeenOnlineStore,\n ]);\n};\n"],"names":[],"mappings":";;AAoBO,MAAM,
|
|
1
|
+
{"version":3,"file":"disconnectedUsers.esm.js","sources":["../../../src/components/AutoLogout/disconnectedUsers.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { IdentityApi } from '@backstage/core-plugin-api';\nimport { useEffect } from 'react';\n\nimport { TimestampStore } from './timestampStore';\n\nexport const LAST_SEEN_ONLINE_STORAGE_KEY =\n '@backstage/autologout:lastSeenOnline';\n\nexport type UseLogoutDisconnectedUserEffectProps = {\n enableEffect: boolean;\n autologoutIsEnabled: boolean;\n idleTimeoutSeconds: number;\n lastSeenOnlineStore: TimestampStore;\n identityApi: IdentityApi;\n};\n\nexport const useLogoutDisconnectedUserEffect = ({\n enableEffect,\n autologoutIsEnabled,\n idleTimeoutSeconds,\n lastSeenOnlineStore,\n identityApi,\n}: UseLogoutDisconnectedUserEffectProps) => {\n useEffect(() => {\n /**\n * Considers disconnected users as inactive users.\n * If all Backstage tabs are closed and idleTimeoutMinutes are passed then logout the user anyway.\n */\n if (autologoutIsEnabled && enableEffect) {\n const lastSeenOnline = lastSeenOnlineStore.get();\n if (lastSeenOnline) {\n const now = new Date();\n const nowSeconds = Math.ceil(now.getTime() / 1000);\n const lastSeenOnlineSeconds = Math.ceil(\n lastSeenOnline.getTime() / 1000,\n );\n if (nowSeconds - lastSeenOnlineSeconds > idleTimeoutSeconds) {\n identityApi.signOut();\n }\n }\n /**\n * save for the first time when app is loaded, so that\n * if user logs in and does nothing we still have a\n * lastSeenOnline value in store\n */\n lastSeenOnlineStore.save(new Date());\n } else {\n lastSeenOnlineStore.delete();\n }\n }, [\n autologoutIsEnabled,\n enableEffect,\n identityApi,\n idleTimeoutSeconds,\n lastSeenOnlineStore,\n ]);\n};\n"],"names":[],"mappings":";;AAoBO,MAAM,4BAAA,GACX;AAUK,MAAM,kCAAkC,CAAC;AAAA,EAC9C,YAAA;AAAA,EACA,mBAAA;AAAA,EACA,kBAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAA,KAA4C;AAC1C,EAAA,SAAA,CAAU,MAAM;AAKd,IAAA,IAAI,uBAAuB,YAAA,EAAc;AACvC,MAAA,MAAM,cAAA,GAAiB,oBAAoB,GAAA,EAAI;AAC/C,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,QAAA,MAAM,aAAa,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,OAAA,KAAY,GAAI,CAAA;AACjD,QAAA,MAAM,wBAAwB,IAAA,CAAK,IAAA;AAAA,UACjC,cAAA,CAAe,SAAQ,GAAI;AAAA,SAC7B;AACA,QAAA,IAAI,UAAA,GAAa,wBAAwB,kBAAA,EAAoB;AAC3D,UAAA,WAAA,CAAY,OAAA,EAAQ;AAAA,QACtB;AAAA,MACF;AAMA,MAAA,mBAAA,CAAoB,IAAA,iBAAK,IAAI,IAAA,EAAM,CAAA;AAAA,IACrC,CAAA,MAAO;AACL,MAAA,mBAAA,CAAoB,MAAA,EAAO;AAAA,IAC7B;AAAA,EACF,CAAA,EAAG;AAAA,IACD,mBAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timestampStore.esm.js","sources":["../../../src/components/AutoLogout/timestampStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport interface TimestampStore {\n save(date: Date): void;\n delete(): void;\n get(): Date | null;\n}\n\nexport class DefaultTimestampStore implements TimestampStore {\n constructor(private readonly key: string) {}\n\n save(date: Date): void {\n localStorage.setItem(this.key, date.toJSON());\n }\n\n delete(): void {\n localStorage.removeItem(this.key);\n }\n\n get(): Date | null {\n const timestamp = localStorage.getItem(this.key);\n\n return timestamp !== null ? new Date(Date.parse(timestamp)) : null;\n }\n}\n"],"names":[],"mappings":"AAsBO,MAAM,
|
|
1
|
+
{"version":3,"file":"timestampStore.esm.js","sources":["../../../src/components/AutoLogout/timestampStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport interface TimestampStore {\n save(date: Date): void;\n delete(): void;\n get(): Date | null;\n}\n\nexport class DefaultTimestampStore implements TimestampStore {\n constructor(private readonly key: string) {}\n\n save(date: Date): void {\n localStorage.setItem(this.key, date.toJSON());\n }\n\n delete(): void {\n localStorage.removeItem(this.key);\n }\n\n get(): Date | null {\n const timestamp = localStorage.getItem(this.key);\n\n return timestamp !== null ? new Date(Date.parse(timestamp)) : null;\n }\n}\n"],"names":[],"mappings":"AAsBO,MAAM,qBAAA,CAAgD;AAAA,EAC3D,YAA6B,GAAA,EAAa;AAAb,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAAA,EAAc;AAAA,EAE3C,KAAK,IAAA,EAAkB;AACrB,IAAA,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,QAAQ,CAAA;AAAA,EAC9C;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,YAAA,CAAa,UAAA,CAAW,KAAK,GAAG,CAAA;AAAA,EAClC;AAAA,EAEA,GAAA,GAAmB;AACjB,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA;AAE/C,IAAA,OAAO,SAAA,KAAc,OAAO,IAAI,IAAA,CAAK,KAAK,KAAA,CAAM,SAAS,CAAC,CAAA,GAAI,IAAA;AAAA,EAChE;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.esm.js","sources":["../../../src/components/Avatar/Avatar.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport MaterialAvatar from '@material-ui/core/Avatar';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport { CSSProperties } from 'react';\n\nimport { extractInitials, stringToColor } from './utils';\nimport classNames from 'classnames';\n\n/** @public */\nexport type AvatarClassKey = 'avatar';\n\nconst useStyles = makeStyles(\n (theme: Theme) => ({\n avatar: {\n width: '4rem',\n height: '4rem',\n color: theme.palette.common.white,\n backgroundColor: (props: { backgroundColor?: string }) =>\n props.backgroundColor,\n },\n avatarText: {\n fontWeight: theme.typography.fontWeightBold,\n letterSpacing: '1px',\n textTransform: 'uppercase',\n },\n }),\n { name: 'BackstageAvatar' },\n);\n\n/**\n * Properties for {@link Avatar}.\n *\n * @public\n */\nexport interface AvatarProps {\n /**\n * A display name, which will be used to generate initials as a fallback in case a picture is not provided.\n */\n displayName?: string;\n /**\n * URL to avatar image source\n */\n picture?: string;\n /**\n * Custom styles applied to avatar\n * @deprecated - use the classes property instead\n */\n customStyles?: CSSProperties;\n\n /**\n * Custom styles applied to avatar\n */\n classes?: { [key in 'avatar' | 'avatarText']?: string };\n}\n\n/**\n * Component rendering an Avatar\n *\n * @public\n * @remarks\n *\n * Based on https://v4.mui.com/components/avatars/#avatar with some styling adjustment and two-letter initials\n */\nexport function Avatar(props: AvatarProps) {\n const { displayName, picture, customStyles } = props;\n const styles = { ...customStyles };\n\n // TODO: Remove this with the customStyles deprecation\n const fontStyles = {\n fontFamily: styles.fontFamily,\n fontSize: styles.fontSize,\n fontWeight: styles.fontWeight,\n };\n\n // We only calculate the background color if there's not an avatar\n // picture. If there is a picture, it might have a transparent\n // background and we don't know whether the calculated background\n // color will clash.\n const classes = useStyles(\n !picture ? { backgroundColor: stringToColor(displayName || '') } : {},\n );\n\n const avatarClassNames = classNames(props.classes?.avatar, classes.avatar);\n const avatarTextClassNames = classNames(\n props.classes?.avatarText,\n classes.avatarText,\n );\n\n return (\n <MaterialAvatar\n alt={displayName}\n src={picture}\n className={avatarClassNames}\n style={styles}\n >\n {displayName && (\n <Typography\n variant=\"h6\"\n component=\"span\"\n className={avatarTextClassNames}\n style={fontStyles}\n >\n {extractInitials(displayName)}\n </Typography>\n )}\n </MaterialAvatar>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA0BA,MAAM,
|
|
1
|
+
{"version":3,"file":"Avatar.esm.js","sources":["../../../src/components/Avatar/Avatar.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport MaterialAvatar from '@material-ui/core/Avatar';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport { CSSProperties } from 'react';\n\nimport { extractInitials, stringToColor } from './utils';\nimport classNames from 'classnames';\n\n/** @public */\nexport type AvatarClassKey = 'avatar';\n\nconst useStyles = makeStyles(\n (theme: Theme) => ({\n avatar: {\n width: '4rem',\n height: '4rem',\n color: theme.palette.common.white,\n backgroundColor: (props: { backgroundColor?: string }) =>\n props.backgroundColor,\n },\n avatarText: {\n fontWeight: theme.typography.fontWeightBold,\n letterSpacing: '1px',\n textTransform: 'uppercase',\n },\n }),\n { name: 'BackstageAvatar' },\n);\n\n/**\n * Properties for {@link Avatar}.\n *\n * @public\n */\nexport interface AvatarProps {\n /**\n * A display name, which will be used to generate initials as a fallback in case a picture is not provided.\n */\n displayName?: string;\n /**\n * URL to avatar image source\n */\n picture?: string;\n /**\n * Custom styles applied to avatar\n * @deprecated - use the classes property instead\n */\n customStyles?: CSSProperties;\n\n /**\n * Custom styles applied to avatar\n */\n classes?: { [key in 'avatar' | 'avatarText']?: string };\n}\n\n/**\n * Component rendering an Avatar\n *\n * @public\n * @remarks\n *\n * Based on https://v4.mui.com/components/avatars/#avatar with some styling adjustment and two-letter initials\n */\nexport function Avatar(props: AvatarProps) {\n const { displayName, picture, customStyles } = props;\n const styles = { ...customStyles };\n\n // TODO: Remove this with the customStyles deprecation\n const fontStyles = {\n fontFamily: styles.fontFamily,\n fontSize: styles.fontSize,\n fontWeight: styles.fontWeight,\n };\n\n // We only calculate the background color if there's not an avatar\n // picture. If there is a picture, it might have a transparent\n // background and we don't know whether the calculated background\n // color will clash.\n const classes = useStyles(\n !picture ? { backgroundColor: stringToColor(displayName || '') } : {},\n );\n\n const avatarClassNames = classNames(props.classes?.avatar, classes.avatar);\n const avatarTextClassNames = classNames(\n props.classes?.avatarText,\n classes.avatarText,\n );\n\n return (\n <MaterialAvatar\n alt={displayName}\n src={picture}\n className={avatarClassNames}\n style={styles}\n >\n {displayName && (\n <Typography\n variant=\"h6\"\n component=\"span\"\n className={avatarTextClassNames}\n style={fontStyles}\n >\n {extractInitials(displayName)}\n </Typography>\n )}\n </MaterialAvatar>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA0BA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAC,KAAA,MAAkB;AAAA,IACjB,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ,MAAA;AAAA,MACR,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,KAAA;AAAA,MAC5B,eAAA,EAAiB,CAAC,KAAA,KAChB,KAAA,CAAM;AAAA,KACV;AAAA,IACA,UAAA,EAAY;AAAA,MACV,UAAA,EAAY,MAAM,UAAA,CAAW,cAAA;AAAA,MAC7B,aAAA,EAAe,KAAA;AAAA,MACf,aAAA,EAAe;AAAA;AACjB,GACF,CAAA;AAAA,EACA,EAAE,MAAM,iBAAA;AACV,CAAA;AAoCO,SAAS,OAAO,KAAA,EAAoB;AACzC,EAAA,MAAM,EAAE,WAAA,EAAa,OAAA,EAAS,YAAA,EAAa,GAAI,KAAA;AAC/C,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,YAAA,EAAa;AAGjC,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,YAAY,MAAA,CAAO;AAAA,GACrB;AAMA,EAAA,MAAM,OAAA,GAAU,SAAA;AAAA,IACd,CAAC,UAAU,EAAE,eAAA,EAAiB,cAAc,WAAA,IAAe,EAAE,CAAA,EAAE,GAAI;AAAC,GACtE;AAEA,EAAA,MAAM,mBAAmB,UAAA,CAAW,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAM,CAAA;AACzE,EAAA,MAAM,oBAAA,GAAuB,UAAA;AAAA,IAC3B,MAAM,OAAA,EAAS,UAAA;AAAA,IACf,OAAA,CAAQ;AAAA,GACV;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,WAAA;AAAA,MACL,GAAA,EAAK,OAAA;AAAA,MACL,SAAA,EAAW,gBAAA;AAAA,MACX,KAAA,EAAO,MAAA;AAAA,MAEN,QAAA,EAAA,WAAA,oBACC,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAQ,IAAA;AAAA,UACR,SAAA,EAAU,MAAA;AAAA,UACV,SAAA,EAAW,oBAAA;AAAA,UACX,KAAA,EAAO,UAAA;AAAA,UAEN,0BAAgB,WAAW;AAAA;AAAA;AAC9B;AAAA,GAEJ;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.esm.js","sources":["../../../src/components/Avatar/utils.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function stringToColor(str: string) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = str.charCodeAt(i) + ((hash << 5) - hash);\n }\n let color = '#';\n for (let i = 0; i < 3; i++) {\n const value = (hash >> (i * 8)) & 0xff;\n color += `00${value.toString(16)}`.slice(-2);\n }\n return color;\n}\n\nexport function extractInitials(name: string) {\n const names = name.trim().split(' ');\n const firstName = names[0] ?? '';\n const lastName = names.length > 1 ? names[names.length - 1] : '';\n return firstName && lastName\n ? `${firstName.charAt(0)}${lastName.charAt(0)}`\n : firstName.charAt(0);\n}\n"],"names":[],"mappings":"AAgBO,SAAS,cAAc,
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../../../src/components/Avatar/utils.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function stringToColor(str: string) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = str.charCodeAt(i) + ((hash << 5) - hash);\n }\n let color = '#';\n for (let i = 0; i < 3; i++) {\n const value = (hash >> (i * 8)) & 0xff;\n color += `00${value.toString(16)}`.slice(-2);\n }\n return color;\n}\n\nexport function extractInitials(name: string) {\n const names = name.trim().split(' ');\n const firstName = names[0] ?? '';\n const lastName = names.length > 1 ? names[names.length - 1] : '';\n return firstName && lastName\n ? `${firstName.charAt(0)}${lastName.charAt(0)}`\n : firstName.charAt(0);\n}\n"],"names":[],"mappings":"AAgBO,SAAS,cAAc,GAAA,EAAa;AACzC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,IAAA,GAAO,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA,IAAA,CAAM,QAAQ,CAAA,IAAK,IAAA,CAAA;AAAA,EAC5C;AACA,EAAA,IAAI,KAAA,GAAQ,GAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,KAAA,GAAS,IAAA,IAAS,CAAA,GAAI,CAAA,GAAM,GAAA;AAClC,IAAA,KAAA,IAAS,KAAK,KAAA,CAAM,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,CAAG,MAAM,EAAE,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,gBAAgB,IAAA,EAAc;AAC5C,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,MAAM,GAAG,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAC9B,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,GAAS,CAAA,GAAI,MAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,GAAI,EAAA;AAC9D,EAAA,OAAO,SAAA,IAAa,QAAA,GAChB,CAAA,EAAG,SAAA,CAAU,OAAO,CAAC,CAAC,CAAA,EAAG,QAAA,CAAS,OAAO,CAAC,CAAC,CAAA,CAAA,GAC3C,SAAA,CAAU,OAAO,CAAC,CAAA;AACxB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeSnippet.esm.js","sources":["../../../src/components/CodeSnippet/CodeSnippet.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport { useTheme } from '@material-ui/core/styles';\nimport type {} from 'react-syntax-highlighter';\nimport LightAsync from 'react-syntax-highlighter/dist/esm/light-async';\nimport dark from 'react-syntax-highlighter/dist/esm/styles/hljs/dark';\nimport docco from 'react-syntax-highlighter/dist/esm/styles/hljs/docco';\n\nimport { CopyTextButton } from '../CopyTextButton';\n\n/**\n * Properties for {@link CodeSnippet}\n *\n * @public\n */\nexport interface CodeSnippetProps {\n /**\n * Code Snippet text\n */\n text: string;\n /**\n * Language used by {@link CodeSnippetProps.text}\n */\n language: string;\n /**\n * Whether to show line number\n *\n * @remarks\n *\n * Default: false\n */\n showLineNumbers?: boolean;\n /**\n * Whether to show button to copy code snippet\n *\n * @remarks\n *\n * Default: false\n */\n showCopyCodeButton?: boolean;\n /**\n * Array of line numbers to highlight\n */\n highlightedNumbers?: number[];\n /**\n * Custom styles applied to code\n *\n * @remarks\n *\n * Passed to {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}\n */\n customStyle?: any;\n}\n\n/**\n * Thin wrapper on top of {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}\n * providing consistent theming and copy code button\n *\n * @public\n */\nexport function CodeSnippet(props: CodeSnippetProps) {\n const {\n text,\n language,\n showLineNumbers = false,\n highlightedNumbers,\n customStyle,\n showCopyCodeButton = false,\n } = props;\n const theme = useTheme();\n const mode = theme.palette.type === 'dark' ? dark : docco;\n const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';\n\n return (\n <Box position=\"relative\">\n <LightAsync\n customStyle={customStyle}\n language={language}\n style={mode}\n showLineNumbers={showLineNumbers}\n wrapLines\n lineNumberStyle={{ color: theme.palette.textVerySubtle }}\n lineProps={(lineNumber: number) =>\n highlightedNumbers?.includes(lineNumber)\n ? {\n style: {\n backgroundColor: highlightColor,\n },\n }\n : {}\n }\n >\n {text}\n </LightAsync>\n {showCopyCodeButton && (\n <Box position=\"absolute\" top={0} right={0}>\n <CopyTextButton text={text} />\n </Box>\n )}\n </Box>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AA2EO,SAAS,YAAY,
|
|
1
|
+
{"version":3,"file":"CodeSnippet.esm.js","sources":["../../../src/components/CodeSnippet/CodeSnippet.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport { useTheme } from '@material-ui/core/styles';\nimport type {} from 'react-syntax-highlighter';\nimport LightAsync from 'react-syntax-highlighter/dist/esm/light-async';\nimport dark from 'react-syntax-highlighter/dist/esm/styles/hljs/dark';\nimport docco from 'react-syntax-highlighter/dist/esm/styles/hljs/docco';\n\nimport { CopyTextButton } from '../CopyTextButton';\n\n/**\n * Properties for {@link CodeSnippet}\n *\n * @public\n */\nexport interface CodeSnippetProps {\n /**\n * Code Snippet text\n */\n text: string;\n /**\n * Language used by {@link CodeSnippetProps.text}\n */\n language: string;\n /**\n * Whether to show line number\n *\n * @remarks\n *\n * Default: false\n */\n showLineNumbers?: boolean;\n /**\n * Whether to show button to copy code snippet\n *\n * @remarks\n *\n * Default: false\n */\n showCopyCodeButton?: boolean;\n /**\n * Array of line numbers to highlight\n */\n highlightedNumbers?: number[];\n /**\n * Custom styles applied to code\n *\n * @remarks\n *\n * Passed to {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}\n */\n customStyle?: any;\n}\n\n/**\n * Thin wrapper on top of {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}\n * providing consistent theming and copy code button\n *\n * @public\n */\nexport function CodeSnippet(props: CodeSnippetProps) {\n const {\n text,\n language,\n showLineNumbers = false,\n highlightedNumbers,\n customStyle,\n showCopyCodeButton = false,\n } = props;\n const theme = useTheme();\n const mode = theme.palette.type === 'dark' ? dark : docco;\n const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';\n\n return (\n <Box position=\"relative\">\n <LightAsync\n customStyle={customStyle}\n language={language}\n style={mode}\n showLineNumbers={showLineNumbers}\n wrapLines\n lineNumberStyle={{ color: theme.palette.textVerySubtle }}\n lineProps={(lineNumber: number) =>\n highlightedNumbers?.includes(lineNumber)\n ? {\n style: {\n backgroundColor: highlightColor,\n },\n }\n : {}\n }\n >\n {text}\n </LightAsync>\n {showCopyCodeButton && (\n <Box position=\"absolute\" top={0} right={0}>\n <CopyTextButton text={text} />\n </Box>\n )}\n </Box>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AA2EO,SAAS,YAAY,KAAA,EAAyB;AACnD,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA,GAAkB,KAAA;AAAA,IAClB,kBAAA;AAAA,IACA,WAAA;AAAA,IACA,kBAAA,GAAqB;AAAA,GACvB,GAAI,KAAA;AACJ,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,KAAS,SAAS,IAAA,GAAO,KAAA;AACpD,EAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,OAAA,CAAQ,IAAA,KAAS,SAAS,SAAA,GAAY,SAAA;AAEnE,EAAA,uBACE,IAAA,CAAC,GAAA,EAAA,EAAI,QAAA,EAAS,UAAA,EACZ,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,WAAA;AAAA,QACA,QAAA;AAAA,QACA,KAAA,EAAO,IAAA;AAAA,QACP,eAAA;AAAA,QACA,SAAA,EAAS,IAAA;AAAA,QACT,eAAA,EAAiB,EAAE,KAAA,EAAO,KAAA,CAAM,QAAQ,cAAA,EAAe;AAAA,QACvD,WAAW,CAAC,UAAA,KACV,kBAAA,EAAoB,QAAA,CAAS,UAAU,CAAA,GACnC;AAAA,UACE,KAAA,EAAO;AAAA,YACL,eAAA,EAAiB;AAAA;AACnB,YAEF,EAAC;AAAA,QAGN,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,IACC,kBAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAI,QAAA,EAAS,UAAA,EAAW,GAAA,EAAK,CAAA,EAAG,KAAA,EAAO,CAAA,EACtC,QAAA,kBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY,CAAA,EAC9B;AAAA,GAAA,EAEJ,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopyTextButton.esm.js","sources":["../../../src/components/CopyTextButton/CopyTextButton.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport CopyIcon from '@material-ui/icons/FileCopy';\nimport { MouseEventHandler, useEffect, useState } from 'react';\nimport useCopyToClipboard from 'react-use/esm/useCopyToClipboard';\nimport { coreComponentsTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Properties for {@link CopyTextButton}\n *\n * @public\n */\nexport interface CopyTextButtonProps {\n /**\n * The text to be copied\n */\n text: string;\n /**\n * Number of milliseconds that the tooltip is shown\n *\n * @remarks\n *\n * Default: 1000\n */\n tooltipDelay?: number;\n /**\n * Text to show in the tooltip when user has clicked the button\n *\n * @remarks\n *\n * Default: \"Text copied to clipboard\"\n */\n tooltipText?: string;\n\n /**\n * Text to use as aria-label prop on the button\n *\n * @remarks\n *\n * Default: \"Copy text\"\n */\n 'aria-label'?: string;\n}\n\n/**\n * Copy text button with visual feedback\n *\n * @public\n * @remarks\n *\n * Visual feedback takes form of:\n * - a hover color\n * - click ripple\n * - Tooltip shown when user has clicked\n *\n * @example\n *\n * ```\n * <CopyTextButton\n * text=\"My text that I want to be copied to the clipboard\"\n * arial-label=\"Accessible label for this button\" />\n * ```\n */\nexport function CopyTextButton(props: CopyTextButtonProps) {\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n const {\n text,\n tooltipDelay = 1000,\n tooltipText = t('copyTextButton.tooltipText'),\n 'aria-label': ariaLabel = 'Copy text',\n } = props;\n const errorApi = useApi(errorApiRef);\n const [open, setOpen] = useState(false);\n const [{ error }, copyToClipboard] = useCopyToClipboard();\n\n useEffect(() => {\n if (error) {\n errorApi.post(error);\n }\n }, [error, errorApi]);\n\n const handleCopyClick: MouseEventHandler = e => {\n e.stopPropagation();\n setOpen(true);\n copyToClipboard(text);\n };\n\n return (\n <>\n <Tooltip\n id=\"copy-test-tooltip\"\n title={tooltipText}\n placement=\"top\"\n leaveDelay={tooltipDelay}\n onClose={() => setOpen(false)}\n open={open}\n >\n <IconButton onClick={handleCopyClick} aria-label={ariaLabel}>\n <CopyIcon />\n </IconButton>\n </Tooltip>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAiFO,SAAS,eAAe,
|
|
1
|
+
{"version":3,"file":"CopyTextButton.esm.js","sources":["../../../src/components/CopyTextButton/CopyTextButton.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport CopyIcon from '@material-ui/icons/FileCopy';\nimport { MouseEventHandler, useEffect, useState } from 'react';\nimport useCopyToClipboard from 'react-use/esm/useCopyToClipboard';\nimport { coreComponentsTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Properties for {@link CopyTextButton}\n *\n * @public\n */\nexport interface CopyTextButtonProps {\n /**\n * The text to be copied\n */\n text: string;\n /**\n * Number of milliseconds that the tooltip is shown\n *\n * @remarks\n *\n * Default: 1000\n */\n tooltipDelay?: number;\n /**\n * Text to show in the tooltip when user has clicked the button\n *\n * @remarks\n *\n * Default: \"Text copied to clipboard\"\n */\n tooltipText?: string;\n\n /**\n * Text to use as aria-label prop on the button\n *\n * @remarks\n *\n * Default: \"Copy text\"\n */\n 'aria-label'?: string;\n}\n\n/**\n * Copy text button with visual feedback\n *\n * @public\n * @remarks\n *\n * Visual feedback takes form of:\n * - a hover color\n * - click ripple\n * - Tooltip shown when user has clicked\n *\n * @example\n *\n * ```\n * <CopyTextButton\n * text=\"My text that I want to be copied to the clipboard\"\n * arial-label=\"Accessible label for this button\" />\n * ```\n */\nexport function CopyTextButton(props: CopyTextButtonProps) {\n const { t } = useTranslationRef(coreComponentsTranslationRef);\n const {\n text,\n tooltipDelay = 1000,\n tooltipText = t('copyTextButton.tooltipText'),\n 'aria-label': ariaLabel = 'Copy text',\n } = props;\n const errorApi = useApi(errorApiRef);\n const [open, setOpen] = useState(false);\n const [{ error }, copyToClipboard] = useCopyToClipboard();\n\n useEffect(() => {\n if (error) {\n errorApi.post(error);\n }\n }, [error, errorApi]);\n\n const handleCopyClick: MouseEventHandler = e => {\n e.stopPropagation();\n setOpen(true);\n copyToClipboard(text);\n };\n\n return (\n <>\n <Tooltip\n id=\"copy-test-tooltip\"\n title={tooltipText}\n placement=\"top\"\n leaveDelay={tooltipDelay}\n onClose={() => setOpen(false)}\n open={open}\n >\n <IconButton onClick={handleCopyClick} aria-label={ariaLabel}>\n <CopyIcon />\n </IconButton>\n </Tooltip>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAiFO,SAAS,eAAe,KAAA,EAA4B;AACzD,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,4BAA4B,CAAA;AAC5D,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,YAAA,GAAe,GAAA;AAAA,IACf,WAAA,GAAc,EAAE,4BAA4B,CAAA;AAAA,IAC5C,cAAc,SAAA,GAAY;AAAA,GAC5B,GAAI,KAAA;AACJ,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,CAAC,EAAE,KAAA,EAAM,EAAG,eAAe,IAAI,kBAAA,EAAmB;AAExD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AAAA,IACrB;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,QAAQ,CAAC,CAAA;AAEpB,EAAA,MAAM,kBAAqC,CAAA,CAAA,KAAK;AAC9C,IAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,EACtB,CAAA;AAEA,EAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACE,QAAA,kBAAA,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAG,mBAAA;AAAA,MACH,KAAA,EAAO,WAAA;AAAA,MACP,SAAA,EAAU,KAAA;AAAA,MACV,UAAA,EAAY,YAAA;AAAA,MACZ,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAA;AAAA,MAC5B,IAAA;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,cAAW,OAAA,EAAS,eAAA,EAAiB,cAAY,SAAA,EAChD,QAAA,kBAAA,GAAA,CAAC,YAAS,CAAA,EACZ;AAAA;AAAA,GACF,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateButton.esm.js","sources":["../../../src/components/CreateButton/CreateButton.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Button from '@material-ui/core/Button';\nimport IconButton from '@material-ui/core/IconButton';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { Link as RouterLink, LinkProps } from 'react-router-dom';\nimport AddCircleOutline from '@material-ui/icons/AddCircleOutline';\nimport { Theme } from '@material-ui/core/styles';\n\n/**\n * Properties for {@link CreateButton}\n *\n * @public\n */\nexport type CreateButtonProps = {\n title: string;\n} & Partial<Pick<LinkProps, 'to'>>;\n\n/**\n * Responsive Button giving consistent UX for creation of different things\n *\n * @public\n */\nexport function CreateButton(props: CreateButtonProps) {\n const { title, to } = props;\n const isXSScreen = useMediaQuery<Theme>(theme =>\n theme.breakpoints.down('xs'),\n );\n\n if (!to) {\n return null;\n }\n\n return isXSScreen ? (\n <IconButton\n component={RouterLink}\n color=\"primary\"\n title={title}\n size=\"small\"\n to={to}\n >\n <AddCircleOutline />\n </IconButton>\n ) : (\n <Button component={RouterLink} variant=\"contained\" color=\"primary\" to={to}>\n {title}\n </Button>\n );\n}\n"],"names":["RouterLink"],"mappings":";;;;;;;AAqCO,SAAS,aAAa,
|
|
1
|
+
{"version":3,"file":"CreateButton.esm.js","sources":["../../../src/components/CreateButton/CreateButton.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Button from '@material-ui/core/Button';\nimport IconButton from '@material-ui/core/IconButton';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { Link as RouterLink, LinkProps } from 'react-router-dom';\nimport AddCircleOutline from '@material-ui/icons/AddCircleOutline';\nimport { Theme } from '@material-ui/core/styles';\n\n/**\n * Properties for {@link CreateButton}\n *\n * @public\n */\nexport type CreateButtonProps = {\n title: string;\n} & Partial<Pick<LinkProps, 'to'>>;\n\n/**\n * Responsive Button giving consistent UX for creation of different things\n *\n * @public\n */\nexport function CreateButton(props: CreateButtonProps) {\n const { title, to } = props;\n const isXSScreen = useMediaQuery<Theme>(theme =>\n theme.breakpoints.down('xs'),\n );\n\n if (!to) {\n return null;\n }\n\n return isXSScreen ? (\n <IconButton\n component={RouterLink}\n color=\"primary\"\n title={title}\n size=\"small\"\n to={to}\n >\n <AddCircleOutline />\n </IconButton>\n ) : (\n <Button component={RouterLink} variant=\"contained\" color=\"primary\" to={to}>\n {title}\n </Button>\n );\n}\n"],"names":["RouterLink"],"mappings":";;;;;;;AAqCO,SAAS,aAAa,KAAA,EAA0B;AACrD,EAAA,MAAM,EAAE,KAAA,EAAO,EAAA,EAAG,GAAI,KAAA;AACtB,EAAA,MAAM,UAAA,GAAa,aAAA;AAAA,IAAqB,CAAA,KAAA,KACtC,KAAA,CAAM,WAAA,CAAY,IAAA,CAAK,IAAI;AAAA,GAC7B;AAEA,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,UAAA,mBACL,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWA,IAAA;AAAA,MACX,KAAA,EAAM,SAAA;AAAA,MACN,KAAA;AAAA,MACA,IAAA,EAAK,OAAA;AAAA,MACL,EAAA;AAAA,MAEA,8BAAC,gBAAA,EAAA,EAAiB;AAAA;AAAA,GACpB,mBAEA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAWA,IAAA,EAAY,SAAQ,WAAA,EAAY,KAAA,EAAM,SAAA,EAAU,EAAA,EAChE,QAAA,EAAA,KAAA,EACH,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultLabel.esm.js","sources":["../../../src/components/DependencyGraph/DefaultLabel.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DependencyGraphTypes as Types } from './types';\n\n/** @public */\nexport type DependencyGraphDefaultLabelClassKey = 'text';\n\nconst useStyles = makeStyles(\n theme => ({\n text: {\n fill: theme.palette.textContrast,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultLabel' },\n);\n\n/** @public */\nexport function DefaultLabel({ edge: { label } }: Types.RenderLabelProps) {\n const classes = useStyles();\n return (\n <text className={classes.text} textAnchor=\"middle\">\n {label}\n </text>\n );\n}\n"],"names":[],"mappings":";;;AAsBA,MAAM,
|
|
1
|
+
{"version":3,"file":"DefaultLabel.esm.js","sources":["../../../src/components/DependencyGraph/DefaultLabel.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DependencyGraphTypes as Types } from './types';\n\n/** @public */\nexport type DependencyGraphDefaultLabelClassKey = 'text';\n\nconst useStyles = makeStyles(\n theme => ({\n text: {\n fill: theme.palette.textContrast,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultLabel' },\n);\n\n/** @public */\nexport function DefaultLabel({ edge: { label } }: Types.RenderLabelProps) {\n const classes = useStyles();\n return (\n <text className={classes.text} textAnchor=\"middle\">\n {label}\n </text>\n );\n}\n"],"names":[],"mappings":";;;AAsBA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAA,KAAA,MAAU;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,MAAM,OAAA,CAAQ;AAAA;AACtB,GACF,CAAA;AAAA,EACA,EAAE,MAAM,sCAAA;AACV,CAAA;AAGO,SAAS,aAAa,EAAE,IAAA,EAAM,EAAE,KAAA,IAAQ,EAA2B;AACxE,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,2BACG,MAAA,EAAA,EAAK,SAAA,EAAW,QAAQ,IAAA,EAAM,UAAA,EAAW,UACvC,QAAA,EAAA,KAAA,EACH,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultNode.esm.js","sources":["../../../src/components/DependencyGraph/DefaultNode.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState, useRef, useLayoutEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { DependencyGraphTypes as Types } from './types';\n\n/** @public */\nexport type DependencyGraphDefaultNodeClassKey = 'node' | 'text';\n\nconst useStyles = makeStyles(\n theme => ({\n node: {\n fill: theme.palette.primary.light,\n stroke: theme.palette.primary.light,\n },\n text: {\n fill: theme.palette.primary.contrastText,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultNode' },\n);\n\n/** @public */\nexport function DefaultNode({ node: { id } }: Types.RenderNodeProps) {\n const classes = useStyles();\n const [width, setWidth] = useState(0);\n const [height, setHeight] = useState(0);\n const idRef = useRef<SVGTextElement | null>(null);\n\n useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const padding = 10;\n const paddedWidth = width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n return (\n <g>\n <rect\n className={classes.node}\n width={paddedWidth}\n height={paddedHeight}\n rx={10}\n />\n <text\n ref={idRef}\n className={classes.text}\n y={paddedHeight / 2}\n x={paddedWidth / 2}\n textAnchor=\"middle\"\n alignmentBaseline=\"middle\"\n >\n {id}\n </text>\n </g>\n );\n}\n"],"names":[],"mappings":";;;;AAuBA,MAAM,
|
|
1
|
+
{"version":3,"file":"DefaultNode.esm.js","sources":["../../../src/components/DependencyGraph/DefaultNode.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState, useRef, useLayoutEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { DependencyGraphTypes as Types } from './types';\n\n/** @public */\nexport type DependencyGraphDefaultNodeClassKey = 'node' | 'text';\n\nconst useStyles = makeStyles(\n theme => ({\n node: {\n fill: theme.palette.primary.light,\n stroke: theme.palette.primary.light,\n },\n text: {\n fill: theme.palette.primary.contrastText,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultNode' },\n);\n\n/** @public */\nexport function DefaultNode({ node: { id } }: Types.RenderNodeProps) {\n const classes = useStyles();\n const [width, setWidth] = useState(0);\n const [height, setHeight] = useState(0);\n const idRef = useRef<SVGTextElement | null>(null);\n\n useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const padding = 10;\n const paddedWidth = width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n return (\n <g>\n <rect\n className={classes.node}\n width={paddedWidth}\n height={paddedHeight}\n rx={10}\n />\n <text\n ref={idRef}\n className={classes.text}\n y={paddedHeight / 2}\n x={paddedWidth / 2}\n textAnchor=\"middle\"\n alignmentBaseline=\"middle\"\n >\n {id}\n </text>\n </g>\n );\n}\n"],"names":[],"mappings":";;;;AAuBA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAA,KAAA,MAAU;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA;AAAA,MAC5B,MAAA,EAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ;AAAA,KAChC;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ;AAAA;AAC9B,GACF,CAAA;AAAA,EACA,EAAE,MAAM,qCAAA;AACV,CAAA;AAGO,SAAS,YAAY,EAAE,IAAA,EAAM,EAAE,EAAA,IAAK,EAA0B;AACnE,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,CAAC,CAAA;AACpC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,CAAC,CAAA;AACtC,EAAA,MAAM,KAAA,GAAQ,OAA8B,IAAI,CAAA;AAEhD,EAAA,eAAA,CAAgB,MAAM;AAEpB,IAAA,IAAI,MAAM,OAAA,EAAS;AACjB,MAAA,IAAI,EAAE,QAAQ,cAAA,EAAgB,KAAA,EAAO,eAAc,GACjD,KAAA,CAAM,QAAQ,OAAA,EAAQ;AACxB,MAAA,cAAA,GAAiB,IAAA,CAAK,MAAM,cAAc,CAAA;AAC1C,MAAA,aAAA,GAAgB,IAAA,CAAK,MAAM,aAAa,CAAA;AAExC,MAAA,IAAI,cAAA,KAAmB,MAAA,IAAU,aAAA,KAAkB,KAAA,EAAO;AACxD,QAAA,QAAA,CAAS,aAAa,CAAA;AACtB,QAAA,SAAA,CAAU,cAAc,CAAA;AAAA,MAC1B;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,MAAM,CAAC,CAAA;AAElB,EAAA,MAAM,OAAA,GAAU,EAAA;AAChB,EAAA,MAAM,WAAA,GAAc,QAAQ,OAAA,GAAU,CAAA;AACtC,EAAA,MAAM,YAAA,GAAe,SAAS,OAAA,GAAU,CAAA;AAExC,EAAA,4BACG,GAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,WAAW,OAAA,CAAQ,IAAA;AAAA,QACnB,KAAA,EAAO,WAAA;AAAA,QACP,MAAA,EAAQ,YAAA;AAAA,QACR,EAAA,EAAI;AAAA;AAAA,KACN;AAAA,oBACA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,KAAA;AAAA,QACL,WAAW,OAAA,CAAQ,IAAA;AAAA,QACnB,GAAG,YAAA,GAAe,CAAA;AAAA,QAClB,GAAG,WAAA,GAAc,CAAA;AAAA,QACjB,UAAA,EAAW,QAAA;AAAA,QACX,iBAAA,EAAkB,QAAA;AAAA,QAEjB,QAAA,EAAA;AAAA;AAAA;AACH,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DependencyGraph.esm.js","sources":["../../../src/components/DependencyGraph/DependencyGraph.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SVGProps,\n useState,\n useRef,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport * as d3Zoom from 'd3-zoom';\nimport * as d3Selection from 'd3-selection';\nimport useTheme from '@material-ui/core/styles/useTheme';\nimport dagre from '@dagrejs/dagre';\nimport debounce from 'lodash/debounce';\nimport { DependencyGraphTypes as Types } from './types';\nimport { Node } from './Node';\nimport { Edge, GraphEdge } from './Edge';\nimport { ARROW_MARKER_ID } from './constants';\n\n/**\n * Properties of {@link DependencyGraph}\n *\n * @public\n * @remarks\n * `<NodeData>` and `<EdgeData>` are useful when rendering custom or edge labels\n */\nexport interface DependencyGraphProps<NodeData, EdgeData>\n extends SVGProps<SVGSVGElement> {\n /**\n * Edges of graph\n */\n edges: Types.DependencyEdge<EdgeData>[];\n /**\n * Nodes of Graph\n */\n nodes: Types.DependencyNode<NodeData>[];\n /**\n * Graph {@link DependencyGraphTypes.Direction | direction}\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.Direction.TOP_BOTTOM`\n */\n direction?: Types.Direction;\n /**\n * Node {@link DependencyGraphTypes.Alignment | alignment}\n */\n align?: Types.Alignment;\n /**\n * Margin between nodes on each rank\n *\n * @remarks\n *\n * Default: 50\n */\n nodeMargin?: number;\n /**\n * Margin between edges\n *\n * @remarks\n *\n * Default: 10\n */\n edgeMargin?: number;\n /**\n * Margin between each rank\n *\n * @remarks\n *\n * Default: 50\n */\n rankMargin?: number;\n /**\n * Margin on left and right of whole graph\n *\n * @remarks\n *\n * Default: 0\n */\n paddingX?: number;\n /**\n * Margin on top and bottom of whole graph\n *\n * @remarks\n *\n * Default: 0\n */\n paddingY?: number;\n /**\n * Heuristic used to find set of edges that will make graph acyclic\n */\n acyclicer?: 'greedy';\n /**\n * {@link DependencyGraphTypes.Ranker | Algorithm} used to rank nodes\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.Ranker.NETWORK_SIMPLEX`\n */\n ranker?: Types.Ranker;\n /**\n * {@link DependencyGraphTypes.LabelPosition | Position} of label in relation to edge\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.LabelPosition.RIGHT`\n */\n labelPosition?: Types.LabelPosition;\n /**\n * How much to move label away from edge\n *\n * @remarks\n *\n * Applies only when {@link DependencyGraphProps.labelPosition} is `DependencyGraphTypes.LabelPosition.LEFT` or\n * `DependencyGraphTypes.LabelPosition.RIGHT`\n */\n labelOffset?: number;\n /**\n * Minimum number of ranks to keep between connected nodes\n */\n edgeRanks?: number;\n /**\n * Weight applied to edges in graph\n */\n edgeWeight?: number;\n /**\n * Custom node rendering component\n */\n renderNode?: Types.RenderNodeFunction<NodeData>;\n /**\n * Custom label rendering component\n */\n renderLabel?: Types.RenderLabelFunction<EdgeData>;\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs | Defs} shared by rendered SVG to be used by\n * {@link DependencyGraphProps.renderNode} and/or {@link DependencyGraphProps.renderLabel}\n */\n defs?: JSX.Element | JSX.Element[];\n /**\n * Controls zoom behavior of graph\n *\n * @remarks\n *\n * Default: `enabled`\n */\n zoom?: 'enabled' | 'disabled' | 'enable-on-click';\n /**\n * A factory for curve generators addressing both lines and areas.\n *\n * @remarks\n *\n * Default: 'curveMonotoneX'\n */\n curve?: 'curveStepBefore' | 'curveMonotoneX';\n /**\n * Controls if the arrow heads should be rendered or not.\n *\n * Default: false\n */\n showArrowHeads?: boolean;\n /**\n * Controls if the graph should be contained or grow\n *\n * @remarks\n *\n * Default: 'grow'\n */\n fit?: 'grow' | 'contain';\n}\n\nconst WORKSPACE_ID = 'workspace';\n\n/**\n * Graph component used to visualize relations between entities\n *\n * @public\n */\nexport function DependencyGraph<NodeData, EdgeData>(\n props: DependencyGraphProps<NodeData, EdgeData>,\n) {\n const {\n edges,\n nodes,\n renderNode,\n direction = Types.Direction.TOP_BOTTOM,\n align,\n nodeMargin = 50,\n edgeMargin = 10,\n rankMargin = 50,\n paddingX = 0,\n paddingY = 0,\n acyclicer,\n ranker = Types.Ranker.NETWORK_SIMPLEX,\n labelPosition = Types.LabelPosition.RIGHT,\n labelOffset = 10,\n edgeRanks = 1,\n edgeWeight = 1,\n renderLabel,\n defs,\n zoom = 'enabled',\n curve = 'curveMonotoneX',\n showArrowHeads = false,\n fit = 'grow',\n ...svgProps\n } = props;\n const theme = useTheme();\n const [containerWidth, setContainerWidth] = useState<number>(100);\n const [containerHeight, setContainerHeight] = useState<number>(100);\n\n const graph = useRef<dagre.graphlib.Graph<Types.DependencyNode<NodeData>>>(\n new dagre.graphlib.Graph(),\n );\n const [graphWidth, setGraphWidth] = useState<number>(\n graph.current.graph()?.width || 0,\n );\n const [graphHeight, setGraphHeight] = useState<number>(\n graph.current.graph()?.height || 0,\n );\n const [graphNodes, setGraphNodes] = useState<string[]>([]);\n const [graphEdges, setGraphEdges] = useState<dagre.Edge[]>([]);\n\n const maxWidth = Math.max(graphWidth, containerWidth);\n const maxHeight = Math.max(graphHeight, containerHeight);\n const minHeight = Math.min(graphHeight, containerHeight);\n\n const scalableHeight = fit === 'grow' ? maxHeight : minHeight;\n\n const containerRef = useMemo(\n () =>\n debounce((node: SVGSVGElement) => {\n if (!node) {\n return;\n }\n // Set up zooming + panning\n const container = d3Selection.select<SVGSVGElement, null>(node);\n const workspace = d3Selection.select(node.getElementById(WORKSPACE_ID));\n\n function enableZoom() {\n container.call(\n d3Zoom\n .zoom<SVGSVGElement, null>()\n .scaleExtent([1, Infinity])\n .on('zoom', event => {\n event.transform.x = Math.min(\n 0,\n Math.max(\n event.transform.x,\n maxWidth - maxWidth * event.transform.k,\n ),\n );\n event.transform.y = Math.min(\n 0,\n Math.max(\n event.transform.y,\n maxHeight - maxHeight * event.transform.k,\n ),\n );\n workspace.attr('transform', event.transform);\n }),\n );\n }\n\n if (zoom === 'enabled') {\n enableZoom();\n } else if (zoom === 'enable-on-click') {\n container.on('click', () => enableZoom());\n }\n\n const { width: newContainerWidth, height: newContainerHeight } =\n node.getBoundingClientRect();\n if (containerWidth !== newContainerWidth) {\n setContainerWidth(newContainerWidth);\n }\n if (containerHeight !== newContainerHeight) {\n setContainerHeight(newContainerHeight);\n }\n }, 100),\n [containerHeight, containerWidth, maxWidth, maxHeight, zoom],\n );\n\n const setNodesAndEdges = useCallback(() => {\n // Cleaning up lingering nodes and edges\n const currentGraphNodes = graph.current.nodes();\n const currentGraphEdges = graph.current.edges();\n\n currentGraphNodes.forEach(nodeId => {\n const remainingNode = nodes.some(node => node.id === nodeId);\n if (!remainingNode) {\n graph.current.removeNode(nodeId);\n }\n });\n\n currentGraphEdges.forEach(e => {\n const remainingEdge = edges.some(\n edge => edge.from === e.v && edge.to === e.w,\n );\n if (!remainingEdge) {\n graph.current.removeEdge(e.v, e.w);\n }\n });\n\n // Adding/updating nodes and edges\n nodes.forEach(node => {\n const existingNode = graph.current\n .nodes()\n .find(nodeId => node.id === nodeId);\n\n if (existingNode && graph.current.node(existingNode)) {\n const { width, height, x, y } = graph.current.node(existingNode);\n graph.current.setNode(existingNode, { ...node, width, height, x, y });\n } else {\n graph.current.setNode(node.id, { ...node, width: 0, height: 0 });\n }\n });\n\n edges.forEach(e => {\n graph.current.setEdge(e.from, e.to, {\n ...e,\n label: e.label,\n width: 0,\n height: 0,\n labelpos: labelPosition,\n labeloffset: labelOffset,\n weight: edgeWeight,\n minlen: edgeRanks,\n });\n });\n }, [edges, nodes, labelPosition, labelOffset, edgeWeight, edgeRanks]);\n\n const updateGraph = useMemo(\n () =>\n debounce(\n () => {\n dagre.layout(graph.current);\n const { height, width } = graph.current.graph();\n const newHeight = Math.max(0, height || 0);\n const newWidth = Math.max(0, width || 0);\n setGraphWidth(newWidth);\n setGraphHeight(newHeight);\n\n setGraphNodes(graph.current.nodes());\n setGraphEdges(graph.current.edges());\n },\n 250,\n { leading: true },\n ),\n [],\n );\n\n useEffect(() => {\n graph.current.setGraph({\n rankdir: direction,\n align,\n nodesep: nodeMargin,\n edgesep: edgeMargin,\n ranksep: rankMargin,\n marginx: paddingX,\n marginy: paddingY,\n acyclicer,\n ranker,\n });\n\n setNodesAndEdges();\n updateGraph();\n\n return updateGraph.cancel;\n }, [\n acyclicer,\n align,\n direction,\n edgeMargin,\n paddingX,\n paddingY,\n nodeMargin,\n rankMargin,\n ranker,\n setNodesAndEdges,\n updateGraph,\n ]);\n\n function setNode(id: string, node: Types.DependencyNode<NodeData>) {\n graph.current.setNode(id, node);\n updateGraph();\n return graph.current;\n }\n\n function setEdge(id: dagre.Edge, edge: Types.DependencyEdge<EdgeData>) {\n graph.current.setEdge(id, edge);\n updateGraph();\n return graph.current;\n }\n\n return (\n <svg\n ref={containerRef}\n {...svgProps}\n width=\"100%\"\n height={scalableHeight}\n viewBox={`0 0 ${maxWidth} ${maxHeight}`}\n >\n <defs>\n <marker\n id={ARROW_MARKER_ID}\n viewBox=\"0 0 24 24\"\n markerWidth=\"14\"\n markerHeight=\"14\"\n refX=\"16\"\n refY=\"12\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path\n fill={theme.palette.textSubtle}\n d=\"M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z\"\n />\n </marker>\n {defs}\n </defs>\n <g id={WORKSPACE_ID}>\n <svg\n width={graphWidth}\n height={graphHeight}\n y={maxHeight / 2 - graphHeight / 2}\n x={maxWidth / 2 - graphWidth / 2}\n viewBox={`0 0 ${graphWidth} ${graphHeight}`}\n >\n {graphEdges.map(e => {\n const edge = graph.current.edge(e) as GraphEdge<EdgeData>;\n if (!edge) return null;\n return (\n <Edge\n key={`${e.v}-${e.w}`}\n id={e}\n setEdge={setEdge}\n render={renderLabel}\n edge={edge}\n curve={curve}\n showArrowHeads={showArrowHeads}\n />\n );\n })}\n {graphNodes.map((id: string) => {\n const node = graph.current.node(id);\n if (!node) return null;\n return (\n <Node\n key={id}\n setNode={setNode}\n render={renderNode}\n node={node}\n />\n );\n })}\n </svg>\n </g>\n </svg>\n );\n}\n"],"names":["Types"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DependencyGraph.esm.js","sources":["../../../src/components/DependencyGraph/DependencyGraph.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SVGProps,\n useState,\n useRef,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport * as d3Zoom from 'd3-zoom';\nimport * as d3Selection from 'd3-selection';\nimport useTheme from '@material-ui/core/styles/useTheme';\nimport dagre from '@dagrejs/dagre';\nimport debounce from 'lodash/debounce';\nimport { DependencyGraphTypes as Types } from './types';\nimport { Node } from './Node';\nimport { Edge, GraphEdge } from './Edge';\nimport { ARROW_MARKER_ID } from './constants';\n\n/**\n * Properties of {@link DependencyGraph}\n *\n * @public\n * @remarks\n * `<NodeData>` and `<EdgeData>` are useful when rendering custom or edge labels\n */\nexport interface DependencyGraphProps<NodeData, EdgeData>\n extends SVGProps<SVGSVGElement> {\n /**\n * Edges of graph\n */\n edges: Types.DependencyEdge<EdgeData>[];\n /**\n * Nodes of Graph\n */\n nodes: Types.DependencyNode<NodeData>[];\n /**\n * Graph {@link DependencyGraphTypes.Direction | direction}\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.Direction.TOP_BOTTOM`\n */\n direction?: Types.Direction;\n /**\n * Node {@link DependencyGraphTypes.Alignment | alignment}\n */\n align?: Types.Alignment;\n /**\n * Margin between nodes on each rank\n *\n * @remarks\n *\n * Default: 50\n */\n nodeMargin?: number;\n /**\n * Margin between edges\n *\n * @remarks\n *\n * Default: 10\n */\n edgeMargin?: number;\n /**\n * Margin between each rank\n *\n * @remarks\n *\n * Default: 50\n */\n rankMargin?: number;\n /**\n * Margin on left and right of whole graph\n *\n * @remarks\n *\n * Default: 0\n */\n paddingX?: number;\n /**\n * Margin on top and bottom of whole graph\n *\n * @remarks\n *\n * Default: 0\n */\n paddingY?: number;\n /**\n * Heuristic used to find set of edges that will make graph acyclic\n */\n acyclicer?: 'greedy';\n /**\n * {@link DependencyGraphTypes.Ranker | Algorithm} used to rank nodes\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.Ranker.NETWORK_SIMPLEX`\n */\n ranker?: Types.Ranker;\n /**\n * {@link DependencyGraphTypes.LabelPosition | Position} of label in relation to edge\n *\n * @remarks\n *\n * Default: `DependencyGraphTypes.LabelPosition.RIGHT`\n */\n labelPosition?: Types.LabelPosition;\n /**\n * How much to move label away from edge\n *\n * @remarks\n *\n * Applies only when {@link DependencyGraphProps.labelPosition} is `DependencyGraphTypes.LabelPosition.LEFT` or\n * `DependencyGraphTypes.LabelPosition.RIGHT`\n */\n labelOffset?: number;\n /**\n * Minimum number of ranks to keep between connected nodes\n */\n edgeRanks?: number;\n /**\n * Weight applied to edges in graph\n */\n edgeWeight?: number;\n /**\n * Custom node rendering component\n */\n renderNode?: Types.RenderNodeFunction<NodeData>;\n /**\n * Custom label rendering component\n */\n renderLabel?: Types.RenderLabelFunction<EdgeData>;\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs | Defs} shared by rendered SVG to be used by\n * {@link DependencyGraphProps.renderNode} and/or {@link DependencyGraphProps.renderLabel}\n */\n defs?: JSX.Element | JSX.Element[];\n /**\n * Controls zoom behavior of graph\n *\n * @remarks\n *\n * Default: `enabled`\n */\n zoom?: 'enabled' | 'disabled' | 'enable-on-click';\n /**\n * A factory for curve generators addressing both lines and areas.\n *\n * @remarks\n *\n * Default: 'curveMonotoneX'\n */\n curve?: 'curveStepBefore' | 'curveMonotoneX';\n /**\n * Controls if the arrow heads should be rendered or not.\n *\n * Default: false\n */\n showArrowHeads?: boolean;\n /**\n * Controls if the graph should be contained or grow\n *\n * @remarks\n *\n * Default: 'grow'\n */\n fit?: 'grow' | 'contain';\n}\n\nconst WORKSPACE_ID = 'workspace';\n\n/**\n * Graph component used to visualize relations between entities\n *\n * @public\n */\nexport function DependencyGraph<NodeData, EdgeData>(\n props: DependencyGraphProps<NodeData, EdgeData>,\n) {\n const {\n edges,\n nodes,\n renderNode,\n direction = Types.Direction.TOP_BOTTOM,\n align,\n nodeMargin = 50,\n edgeMargin = 10,\n rankMargin = 50,\n paddingX = 0,\n paddingY = 0,\n acyclicer,\n ranker = Types.Ranker.NETWORK_SIMPLEX,\n labelPosition = Types.LabelPosition.RIGHT,\n labelOffset = 10,\n edgeRanks = 1,\n edgeWeight = 1,\n renderLabel,\n defs,\n zoom = 'enabled',\n curve = 'curveMonotoneX',\n showArrowHeads = false,\n fit = 'grow',\n ...svgProps\n } = props;\n const theme = useTheme();\n const [containerWidth, setContainerWidth] = useState<number>(100);\n const [containerHeight, setContainerHeight] = useState<number>(100);\n\n const graph = useRef<dagre.graphlib.Graph<Types.DependencyNode<NodeData>>>(\n new dagre.graphlib.Graph(),\n );\n const [graphWidth, setGraphWidth] = useState<number>(\n graph.current.graph()?.width || 0,\n );\n const [graphHeight, setGraphHeight] = useState<number>(\n graph.current.graph()?.height || 0,\n );\n const [graphNodes, setGraphNodes] = useState<string[]>([]);\n const [graphEdges, setGraphEdges] = useState<dagre.Edge[]>([]);\n\n const maxWidth = Math.max(graphWidth, containerWidth);\n const maxHeight = Math.max(graphHeight, containerHeight);\n const minHeight = Math.min(graphHeight, containerHeight);\n\n const scalableHeight = fit === 'grow' ? maxHeight : minHeight;\n\n const containerRef = useMemo(\n () =>\n debounce((node: SVGSVGElement) => {\n if (!node) {\n return;\n }\n // Set up zooming + panning\n const container = d3Selection.select<SVGSVGElement, null>(node);\n const workspace = d3Selection.select(node.getElementById(WORKSPACE_ID));\n\n function enableZoom() {\n container.call(\n d3Zoom\n .zoom<SVGSVGElement, null>()\n .scaleExtent([1, Infinity])\n .on('zoom', event => {\n event.transform.x = Math.min(\n 0,\n Math.max(\n event.transform.x,\n maxWidth - maxWidth * event.transform.k,\n ),\n );\n event.transform.y = Math.min(\n 0,\n Math.max(\n event.transform.y,\n maxHeight - maxHeight * event.transform.k,\n ),\n );\n workspace.attr('transform', event.transform);\n }),\n );\n }\n\n if (zoom === 'enabled') {\n enableZoom();\n } else if (zoom === 'enable-on-click') {\n container.on('click', () => enableZoom());\n }\n\n const { width: newContainerWidth, height: newContainerHeight } =\n node.getBoundingClientRect();\n if (containerWidth !== newContainerWidth) {\n setContainerWidth(newContainerWidth);\n }\n if (containerHeight !== newContainerHeight) {\n setContainerHeight(newContainerHeight);\n }\n }, 100),\n [containerHeight, containerWidth, maxWidth, maxHeight, zoom],\n );\n\n const setNodesAndEdges = useCallback(() => {\n // Cleaning up lingering nodes and edges\n const currentGraphNodes = graph.current.nodes();\n const currentGraphEdges = graph.current.edges();\n\n currentGraphNodes.forEach(nodeId => {\n const remainingNode = nodes.some(node => node.id === nodeId);\n if (!remainingNode) {\n graph.current.removeNode(nodeId);\n }\n });\n\n currentGraphEdges.forEach(e => {\n const remainingEdge = edges.some(\n edge => edge.from === e.v && edge.to === e.w,\n );\n if (!remainingEdge) {\n graph.current.removeEdge(e.v, e.w);\n }\n });\n\n // Adding/updating nodes and edges\n nodes.forEach(node => {\n const existingNode = graph.current\n .nodes()\n .find(nodeId => node.id === nodeId);\n\n if (existingNode && graph.current.node(existingNode)) {\n const { width, height, x, y } = graph.current.node(existingNode);\n graph.current.setNode(existingNode, { ...node, width, height, x, y });\n } else {\n graph.current.setNode(node.id, { ...node, width: 0, height: 0 });\n }\n });\n\n edges.forEach(e => {\n graph.current.setEdge(e.from, e.to, {\n ...e,\n label: e.label,\n width: 0,\n height: 0,\n labelpos: labelPosition,\n labeloffset: labelOffset,\n weight: edgeWeight,\n minlen: edgeRanks,\n });\n });\n }, [edges, nodes, labelPosition, labelOffset, edgeWeight, edgeRanks]);\n\n const updateGraph = useMemo(\n () =>\n debounce(\n () => {\n dagre.layout(graph.current);\n const { height, width } = graph.current.graph();\n const newHeight = Math.max(0, height || 0);\n const newWidth = Math.max(0, width || 0);\n setGraphWidth(newWidth);\n setGraphHeight(newHeight);\n\n setGraphNodes(graph.current.nodes());\n setGraphEdges(graph.current.edges());\n },\n 250,\n { leading: true },\n ),\n [],\n );\n\n useEffect(() => {\n graph.current.setGraph({\n rankdir: direction,\n align,\n nodesep: nodeMargin,\n edgesep: edgeMargin,\n ranksep: rankMargin,\n marginx: paddingX,\n marginy: paddingY,\n acyclicer,\n ranker,\n });\n\n setNodesAndEdges();\n updateGraph();\n\n return updateGraph.cancel;\n }, [\n acyclicer,\n align,\n direction,\n edgeMargin,\n paddingX,\n paddingY,\n nodeMargin,\n rankMargin,\n ranker,\n setNodesAndEdges,\n updateGraph,\n ]);\n\n function setNode(id: string, node: Types.DependencyNode<NodeData>) {\n graph.current.setNode(id, node);\n updateGraph();\n return graph.current;\n }\n\n function setEdge(id: dagre.Edge, edge: Types.DependencyEdge<EdgeData>) {\n graph.current.setEdge(id, edge);\n updateGraph();\n return graph.current;\n }\n\n return (\n <svg\n ref={containerRef}\n {...svgProps}\n width=\"100%\"\n height={scalableHeight}\n viewBox={`0 0 ${maxWidth} ${maxHeight}`}\n >\n <defs>\n <marker\n id={ARROW_MARKER_ID}\n viewBox=\"0 0 24 24\"\n markerWidth=\"14\"\n markerHeight=\"14\"\n refX=\"16\"\n refY=\"12\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path\n fill={theme.palette.textSubtle}\n d=\"M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z\"\n />\n </marker>\n {defs}\n </defs>\n <g id={WORKSPACE_ID}>\n <svg\n width={graphWidth}\n height={graphHeight}\n y={maxHeight / 2 - graphHeight / 2}\n x={maxWidth / 2 - graphWidth / 2}\n viewBox={`0 0 ${graphWidth} ${graphHeight}`}\n >\n {graphEdges.map(e => {\n const edge = graph.current.edge(e) as GraphEdge<EdgeData>;\n if (!edge) return null;\n return (\n <Edge\n key={`${e.v}-${e.w}`}\n id={e}\n setEdge={setEdge}\n render={renderLabel}\n edge={edge}\n curve={curve}\n showArrowHeads={showArrowHeads}\n />\n );\n })}\n {graphNodes.map((id: string) => {\n const node = graph.current.node(id);\n if (!node) return null;\n return (\n <Node\n key={id}\n setNode={setNode}\n render={renderNode}\n node={node}\n />\n );\n })}\n </svg>\n </g>\n </svg>\n );\n}\n"],"names":["Types"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { useRef, useLayoutEffect, useMemo } from 'react';
|
|
|
3
3
|
import * as d3Shape from 'd3-shape';
|
|
4
4
|
import isFinite from 'lodash/isFinite';
|
|
5
5
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
|
6
|
-
import {
|
|
6
|
+
import { ARROW_MARKER_ID, EDGE_TEST_ID, LABEL_TEST_ID } from './constants.esm.js';
|
|
7
7
|
import { DefaultLabel } from './DefaultLabel.esm.js';
|
|
8
8
|
|
|
9
9
|
const useStyles = makeStyles(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Edge.esm.js","sources":["../../../src/components/DependencyGraph/Edge.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useRef, useLayoutEffect, useMemo } from 'react';\nimport * as d3Shape from 'd3-shape';\nimport isFinite from 'lodash/isFinite';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DependencyGraphTypes as Types } from './types';\nimport { ARROW_MARKER_ID, EDGE_TEST_ID, LABEL_TEST_ID } from './constants';\nimport { DefaultLabel } from './DefaultLabel';\nimport dagre from '@dagrejs/dagre';\n\n/* Based on: https://github.com/dagrejs/dagre/wiki#configuring-the-layout */\nexport type EdgeProperties = {\n label?: string;\n width?: number;\n height?: number;\n labeloffset?: number;\n labelpos?: Types.LabelPosition;\n minlen?: number;\n weight?: number;\n};\nexport type GraphEdge<T> = Types.DependencyEdge<T> &\n dagre.GraphEdge &\n EdgeProperties;\n\n/** @public */\nexport type DependencyGraphEdgeClassKey = 'path' | 'label';\n\nconst useStyles = makeStyles(\n theme => ({\n path: {\n strokeWidth: 1.3,\n stroke: theme.palette.textSubtle,\n fill: 'none',\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n label: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphEdge' },\n);\n\ntype EdgePoint = dagre.GraphEdge['points'][0];\n\n/** @public */\nexport type EdgeComponentProps<T = unknown> = {\n id: dagre.Edge;\n edge: GraphEdge<T>;\n render?: Types.RenderLabelFunction<T>;\n setEdge: (\n id: dagre.Edge,\n edge: Types.DependencyEdge<T>,\n ) => dagre.graphlib.Graph<{}>;\n curve: 'curveStepBefore' | 'curveMonotoneX';\n showArrowHeads?: boolean;\n};\n\nconst renderDefault = (props: Types.RenderLabelProps<unknown>) => (\n <DefaultLabel {...props} />\n);\n\nexport function Edge<EdgeData>({\n render = renderDefault,\n setEdge,\n id,\n edge,\n curve,\n showArrowHeads,\n}: EdgeComponentProps<EdgeData>) {\n const { x = 0, y = 0, width, height, points } = edge;\n const labelProps: Types.DependencyEdge<EdgeData> = edge;\n const classes = useStyles();\n\n const labelRef = useRef<SVGGElement>(null);\n\n useLayoutEffect(() => {\n // set the label width to the actual rendered width to properly layout graph\n if (labelRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n labelRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setEdge(id, {\n ...edge,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [edge, height, width, setEdge, id]);\n\n let path: string = '';\n\n const createPath = useMemo(\n () =>\n d3Shape\n .line<EdgePoint>()\n .x(d => d.x)\n .y(d => d.y)\n .curve(d3Shape[curve]),\n [curve],\n );\n\n if (points) {\n const finitePoints = points.filter(\n (point: EdgePoint) => isFinite(point.x) && isFinite(point.y),\n );\n path = createPath(finitePoints) || '';\n }\n\n return (\n <>\n {path && (\n <path\n data-testid={EDGE_TEST_ID}\n className={classes.path}\n markerEnd={showArrowHeads ? `url(#${ARROW_MARKER_ID})` : undefined}\n d={path}\n />\n )}\n {labelProps.label ? (\n <g\n ref={labelRef}\n data-testid={LABEL_TEST_ID}\n className={classes.label}\n transform={`translate(${x},${y})`}\n >\n {render({ edge: labelProps })}\n </g>\n ) : null}\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AA0CA,MAAM,
|
|
1
|
+
{"version":3,"file":"Edge.esm.js","sources":["../../../src/components/DependencyGraph/Edge.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useRef, useLayoutEffect, useMemo } from 'react';\nimport * as d3Shape from 'd3-shape';\nimport isFinite from 'lodash/isFinite';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DependencyGraphTypes as Types } from './types';\nimport { ARROW_MARKER_ID, EDGE_TEST_ID, LABEL_TEST_ID } from './constants';\nimport { DefaultLabel } from './DefaultLabel';\nimport dagre from '@dagrejs/dagre';\n\n/* Based on: https://github.com/dagrejs/dagre/wiki#configuring-the-layout */\nexport type EdgeProperties = {\n label?: string;\n width?: number;\n height?: number;\n labeloffset?: number;\n labelpos?: Types.LabelPosition;\n minlen?: number;\n weight?: number;\n};\nexport type GraphEdge<T> = Types.DependencyEdge<T> &\n dagre.GraphEdge &\n EdgeProperties;\n\n/** @public */\nexport type DependencyGraphEdgeClassKey = 'path' | 'label';\n\nconst useStyles = makeStyles(\n theme => ({\n path: {\n strokeWidth: 1.3,\n stroke: theme.palette.textSubtle,\n fill: 'none',\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n label: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphEdge' },\n);\n\ntype EdgePoint = dagre.GraphEdge['points'][0];\n\n/** @public */\nexport type EdgeComponentProps<T = unknown> = {\n id: dagre.Edge;\n edge: GraphEdge<T>;\n render?: Types.RenderLabelFunction<T>;\n setEdge: (\n id: dagre.Edge,\n edge: Types.DependencyEdge<T>,\n ) => dagre.graphlib.Graph<{}>;\n curve: 'curveStepBefore' | 'curveMonotoneX';\n showArrowHeads?: boolean;\n};\n\nconst renderDefault = (props: Types.RenderLabelProps<unknown>) => (\n <DefaultLabel {...props} />\n);\n\nexport function Edge<EdgeData>({\n render = renderDefault,\n setEdge,\n id,\n edge,\n curve,\n showArrowHeads,\n}: EdgeComponentProps<EdgeData>) {\n const { x = 0, y = 0, width, height, points } = edge;\n const labelProps: Types.DependencyEdge<EdgeData> = edge;\n const classes = useStyles();\n\n const labelRef = useRef<SVGGElement>(null);\n\n useLayoutEffect(() => {\n // set the label width to the actual rendered width to properly layout graph\n if (labelRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n labelRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setEdge(id, {\n ...edge,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [edge, height, width, setEdge, id]);\n\n let path: string = '';\n\n const createPath = useMemo(\n () =>\n d3Shape\n .line<EdgePoint>()\n .x(d => d.x)\n .y(d => d.y)\n .curve(d3Shape[curve]),\n [curve],\n );\n\n if (points) {\n const finitePoints = points.filter(\n (point: EdgePoint) => isFinite(point.x) && isFinite(point.y),\n );\n path = createPath(finitePoints) || '';\n }\n\n return (\n <>\n {path && (\n <path\n data-testid={EDGE_TEST_ID}\n className={classes.path}\n markerEnd={showArrowHeads ? `url(#${ARROW_MARKER_ID})` : undefined}\n d={path}\n />\n )}\n {labelProps.label ? (\n <g\n ref={labelRef}\n data-testid={LABEL_TEST_ID}\n className={classes.label}\n transform={`translate(${x},${y})`}\n >\n {render({ edge: labelProps })}\n </g>\n ) : null}\n </>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Node.esm.js","sources":["../../../src/components/DependencyGraph/Node.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useRef, useLayoutEffect } from 'react';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DefaultNode } from './DefaultNode';\nimport { DependencyGraphTypes as Types } from './types';\nimport { NODE_TEST_ID } from './constants';\nimport dagre from '@dagrejs/dagre';\n\n/** @public */\nexport type DependencyGraphNodeClassKey = 'node';\n\nconst useStyles = makeStyles(\n theme => ({\n node: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphNode' },\n);\n\nexport type GraphNode<T> = dagre.Node<Types.DependencyNode<T>>;\n\nexport type NodeComponentProps<T> = {\n node: GraphNode<T>;\n render?: Types.RenderNodeFunction<T>;\n setNode: dagre.graphlib.Graph['setNode'];\n};\n\nconst renderDefault = (props: Types.RenderNodeProps) => (\n <DefaultNode {...props} />\n);\n\nexport function Node<T>({\n render = renderDefault,\n setNode,\n node,\n}: NodeComponentProps<T>) {\n const { width, height, x = 0, y = 0 } = node;\n const nodeProps: Types.DependencyNode<T> = node;\n const classes = useStyles();\n const nodeRef = useRef<SVGGElement | null>(null);\n\n useLayoutEffect(() => {\n // set the node width to the actual rendered width to properly layout graph\n if (nodeRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n nodeRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setNode(node.id, {\n ...node,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [node, width, height, setNode]);\n\n return (\n <g\n ref={nodeRef}\n data-testid={NODE_TEST_ID}\n className={classes.node}\n transform={`translate(${x - width / 2},${y - height / 2})`}\n >\n {render({ node: nodeProps })}\n </g>\n );\n}\n"],"names":[],"mappings":";;;;;;AA0BA,MAAM,
|
|
1
|
+
{"version":3,"file":"Node.esm.js","sources":["../../../src/components/DependencyGraph/Node.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useRef, useLayoutEffect } from 'react';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DefaultNode } from './DefaultNode';\nimport { DependencyGraphTypes as Types } from './types';\nimport { NODE_TEST_ID } from './constants';\nimport dagre from '@dagrejs/dagre';\n\n/** @public */\nexport type DependencyGraphNodeClassKey = 'node';\n\nconst useStyles = makeStyles(\n theme => ({\n node: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphNode' },\n);\n\nexport type GraphNode<T> = dagre.Node<Types.DependencyNode<T>>;\n\nexport type NodeComponentProps<T> = {\n node: GraphNode<T>;\n render?: Types.RenderNodeFunction<T>;\n setNode: dagre.graphlib.Graph['setNode'];\n};\n\nconst renderDefault = (props: Types.RenderNodeProps) => (\n <DefaultNode {...props} />\n);\n\nexport function Node<T>({\n render = renderDefault,\n setNode,\n node,\n}: NodeComponentProps<T>) {\n const { width, height, x = 0, y = 0 } = node;\n const nodeProps: Types.DependencyNode<T> = node;\n const classes = useStyles();\n const nodeRef = useRef<SVGGElement | null>(null);\n\n useLayoutEffect(() => {\n // set the node width to the actual rendered width to properly layout graph\n if (nodeRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n nodeRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setNode(node.id, {\n ...node,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [node, width, height, setNode]);\n\n return (\n <g\n ref={nodeRef}\n data-testid={NODE_TEST_ID}\n className={classes.node}\n transform={`translate(${x - width / 2},${y - height / 2})`}\n >\n {render({ node: nodeProps })}\n </g>\n );\n}\n"],"names":[],"mappings":";;;;;;AA0BA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAA,KAAA,MAAU;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,UAAA,EAAY,CAAA,EAAG,KAAA,CAAM,WAAA,CAAY,SAAS,QAAQ,CAAA,EAAA;AAAA;AACpD,GACF,CAAA;AAAA,EACA,EAAE,MAAM,8BAAA;AACV,CAAA;AAUA,MAAM,gBAAgB,CAAC,KAAA,qBACrB,GAAA,CAAC,WAAA,EAAA,EAAa,GAAG,KAAA,EAAO,CAAA;AAGnB,SAAS,IAAA,CAAQ;AAAA,EACtB,MAAA,GAAS,aAAA;AAAA,EACT,OAAA;AAAA,EACA;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,IAAI,CAAA,EAAG,CAAA,GAAI,GAAE,GAAI,IAAA;AACxC,EAAA,MAAM,SAAA,GAAqC,IAAA;AAC3C,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,OAAA,GAAU,OAA2B,IAAI,CAAA;AAE/C,EAAA,eAAA,CAAgB,MAAM;AAEpB,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAA,IAAI,EAAE,QAAQ,cAAA,EAAgB,KAAA,EAAO,eAAc,GACjD,OAAA,CAAQ,QAAQ,OAAA,EAAQ;AAC1B,MAAA,cAAA,GAAiB,IAAA,CAAK,MAAM,cAAc,CAAA;AAC1C,MAAA,aAAA,GAAgB,IAAA,CAAK,MAAM,aAAa,CAAA;AAExC,MAAA,IAAI,cAAA,KAAmB,MAAA,IAAU,aAAA,KAAkB,KAAA,EAAO;AACxD,QAAA,OAAA,CAAQ,KAAK,EAAA,EAAI;AAAA,UACf,GAAG,IAAA;AAAA,UACH,MAAA,EAAQ,cAAA;AAAA,UACR,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,OAAO,CAAC,CAAA;AAEjC,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,OAAA;AAAA,MACL,aAAA,EAAa,YAAA;AAAA,MACb,WAAW,OAAA,CAAQ,IAAA;AAAA,MACnB,SAAA,EAAW,aAAa,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA,CAAA,EAAI,CAAA,GAAI,SAAS,CAAC,CAAA,CAAA,CAAA;AAAA,MAEtD,QAAA,EAAA,MAAA,CAAO,EAAE,IAAA,EAAM,SAAA,EAAW;AAAA;AAAA,GAC7B;AAEJ;;;;"}
|