1 |
- {"version":3,"file":"PluginPage.35821bcc5f6830ed7e8b.js","mappings":"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","sources":["webpack://grafana/./public/app/features/datasources/DashboardsTable.tsx","webpack://grafana/./public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx","webpack://grafana/./public/app/features/plugins/admin/components/Badges/sharedStyles.ts","webpack://grafana/./public/app/features/plugins/admin/components/Badges/PluginInstallBadge.tsx","webpack://grafana/./public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx","webpack://grafana/./public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginLogo.tsx","webpack://grafana/./public/app/features/plugins/admin/components/VersionList.tsx","webpack://grafana/./public/app/features/plugins/admin/hooks/usePluginConfig.tsx","webpack://grafana/./public/app/features/plugins/utils.ts","webpack://grafana/./public/app/features/plugins/admin/components/AppConfigWrapper.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDashboards.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsBody.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx","webpack://grafana/./public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx","webpack://grafana/./public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx","webpack://grafana/./public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithPlugin.tsx","webpack://grafana/./public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.tsx","webpack://grafana/./public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx","webpack://grafana/./public/app/features/plugins/admin/components/InstallControls/InstallControls.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsHeaderDependencies.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsHeaderSignature.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsHeader.tsx","webpack://grafana/./public/app/features/plugins/admin/components/PluginDetailsSignature.tsx","webpack://grafana/./public/app/features/plugins/admin/pages/PluginDetails.tsx","webpack://grafana/./public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx","webpack://grafana/./public/app/features/plugins/admin/state/selectors.ts","webpack://grafana/./public/app/features/plugins/admin/state/hooks.ts","webpack://grafana/./.yarn/__virtual__/react-use-virtual-00326e70ba/3/opt/drone/yarncache/react-use-npm-17.3.2-a032cbeb01-7379460f51.zip/node_modules/react-use/esm/usePrevious.js"],"sourcesContent":["import React, { FC } from 'react';\n\nimport { Button, Icon } from '@grafana/ui';\n\nimport { PluginDashboard } from '../../types';\n\nexport interface Props {\n dashboards: PluginDashboard[];\n onImport: (dashboard: PluginDashboard, overwrite: boolean) => void;\n onRemove: (dashboard: PluginDashboard) => void;\n}\n\nconst DashboardsTable: FC<Props> = ({ dashboards, onImport, onRemove }) => {\n function buttonText(dashboard: PluginDashboard) {\n return dashboard.revision !== dashboard.importedRevision ? 'Update' : 'Re-import';\n }\n\n return (\n <table className=\"filter-table\">\n <tbody>\n {dashboards.map((dashboard, index) => {\n return (\n <tr key={`${dashboard.dashboardId}-${index}`}>\n <td className=\"width-1\">\n <Icon name=\"apps\" />\n </td>\n <td>\n {dashboard.imported ? (\n <a href={dashboard.importedUrl}>{dashboard.title}</a>\n ) : (\n <span>{dashboard.title}</span>\n )}\n </td>\n <td style={{ textAlign: 'right' }}>\n {!dashboard.imported ? (\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onImport(dashboard, false)}>\n Import\n </Button>\n ) : (\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onImport(dashboard, true)}>\n {buttonText(dashboard)}\n </Button>\n )}\n {dashboard.imported && (\n <Button icon=\"trash-alt\" variant=\"destructive\" size=\"sm\" onClick={() => onRemove(dashboard)} />\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nexport default DashboardsTable;\n","import React from 'react';\n\nimport { PluginErrorCode } from '@grafana/data';\nimport { Badge } from '@grafana/ui';\n\ntype Props = { error?: PluginErrorCode };\n\nexport function PluginDisabledBadge({ error }: Props): React.ReactElement {\n const tooltip = errorCodeToTooltip(error);\n return <Badge icon=\"exclamation-triangle\" text=\"Disabled\" color=\"red\" tooltip={tooltip} />;\n}\n\nfunction errorCodeToTooltip(error?: PluginErrorCode): string | undefined {\n switch (error) {\n case PluginErrorCode.modifiedSignature:\n return 'Plugin disabled due to modified content';\n case PluginErrorCode.invalidSignature:\n return 'Plugin disabled due to invalid plugin signature';\n case PluginErrorCode.missingSignature:\n return 'Plugin disabled due to missing plugin signature';\n default:\n return `Plugin disabled due to unkown error: ${error}`;\n }\n}\n","import { css } from '@emotion/css';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nexport const getBadgeColor = (theme: GrafanaTheme2) => css`\n background: ${theme.colors.background.primary};\n border-color: ${theme.colors.border.strong};\n color: ${theme.colors.text.secondary};\n`;\n","import React from 'react';\n\nimport { Badge, useStyles2 } from '@grafana/ui';\n\nimport { getBadgeColor } from './sharedStyles';\n\nexport function PluginInstalledBadge(): React.ReactElement {\n const customBadgeStyles = useStyles2(getBadgeColor);\n return <Badge text=\"Installed\" color=\"orange\" className={customBadgeStyles} />;\n}\n","import React from 'react';\n\nimport { featureEnabled } from '@grafana/runtime';\nimport { Badge, Button, HorizontalGroup, PluginSignatureBadge, useStyles2 } from '@grafana/ui';\n\nimport { CatalogPlugin } from '../../types';\n\nimport { getBadgeColor } from './sharedStyles';\n\ntype Props = { plugin: CatalogPlugin };\n\nexport function PluginEnterpriseBadge({ plugin }: Props): React.ReactElement {\n const customBadgeStyles = useStyles2(getBadgeColor);\n const onClick = (ev: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n ev.preventDefault();\n window.open(\n `https://grafana.com/grafana/plugins/${plugin.id}?utm_source=grafana_catalog_learn_more`,\n '_blank',\n 'noopener,noreferrer'\n );\n };\n\n if (featureEnabled('enterprise.plugins')) {\n return <Badge text=\"Enterprise\" color=\"blue\" />;\n }\n\n return (\n <HorizontalGroup>\n <PluginSignatureBadge status={plugin.signature} />\n <Badge icon=\"lock\" aria-label=\"lock icon\" text=\"Enterprise\" color=\"blue\" className={customBadgeStyles} />\n <Button size=\"sm\" fill=\"text\" icon=\"external-link-alt\" onClick={onClick}>\n Learn more\n </Button>\n </HorizontalGroup>\n );\n}\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2, PluginType } from '@grafana/data';\nimport { useStyles2 } from '@grafana/ui';\n\nimport { CatalogPlugin } from '../../types';\n\ntype Props = {\n plugin: CatalogPlugin;\n};\n\nexport function PluginUpdateAvailableBadge({ plugin }: Props): React.ReactElement | null {\n const styles = useStyles2(getStyles);\n\n // Currently renderer plugins are not supported by the catalog due to complications related to installation / update / uninstall.\n if (plugin.hasUpdate && !plugin.isCore && plugin.type !== PluginType.renderer) {\n return <p className={styles.hasUpdate}>Update available!</p>;\n }\n\n return null;\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n hasUpdate: css`\n color: ${theme.colors.text.secondary};\n font-size: ${theme.typography.bodySmall.fontSize};\n margin-bottom: 0;\n `,\n };\n};\n","import React from 'react';\n\ntype PluginLogoProps = {\n alt: string;\n className?: string;\n src: string;\n height?: string | number;\n};\n\nexport function PluginLogo({ alt, className, src, height }: PluginLogoProps): React.ReactElement {\n // @ts-ignore - react doesn't know about loading attr.\n return <img src={src} className={className} alt={alt} loading=\"lazy\" height={height} />;\n}\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { dateTimeFormatTimeAgo, GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2 } from '@grafana/ui';\n\nimport { getLatestCompatibleVersion } from '../helpers';\nimport { Version } from '../types';\n\ninterface Props {\n versions?: Version[];\n installedVersion?: string;\n}\n\nexport const VersionList = ({ versions = [], installedVersion }: Props) => {\n const styles = useStyles2(getStyles);\n const latestCompatibleVersion = getLatestCompatibleVersion(versions);\n\n if (versions.length === 0) {\n return <p>No version history was found.</p>;\n }\n\n return (\n <table className={styles.table}>\n <thead>\n <tr>\n <th>Version</th>\n <th>Last updated</th>\n </tr>\n </thead>\n <tbody>\n {versions.map((version) => {\n const isInstalledVersion = installedVersion === version.version;\n return (\n <tr key={version.version}>\n {/* Version number */}\n {isInstalledVersion ? (\n <td className={styles.currentVersion}>{version.version} (installed version)</td>\n ) : version.version === latestCompatibleVersion?.version ? (\n <td>{version.version} (latest compatible version)</td>\n ) : (\n <td>{version.version}</td>\n )}\n\n {/* Last updated */}\n <td className={isInstalledVersion ? styles.currentVersion : ''}>\n {dateTimeFormatTimeAgo(version.createdAt)}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n container: css`\n padding: ${theme.spacing(2, 4, 3)};\n `,\n table: css`\n table-layout: fixed;\n width: 100%;\n td,\n th {\n padding: ${theme.spacing()} 0;\n }\n th {\n font-size: ${theme.typography.h5.fontSize};\n }\n `,\n currentVersion: css`\n font-weight: ${theme.typography.fontWeightBold};\n `,\n});\n","import { useAsync } from 'react-use';\n\nimport { loadPlugin } from '../../utils';\nimport { CatalogPlugin } from '../types';\n\nexport const usePluginConfig = (plugin?: CatalogPlugin) => {\n return useAsync(async () => {\n if (!plugin) {\n return null;\n }\n\n if (plugin.isInstalled && !plugin.isDisabled) {\n return loadPlugin(plugin.id);\n }\n return null;\n }, [plugin?.id, plugin?.isInstalled, plugin?.isDisabled]);\n};\n","import { GrafanaPlugin, PanelPluginMeta, PluginType } from '@grafana/data';\n\nimport { importPanelPluginFromMeta } from './importPanelPlugin';\nimport { getPluginSettings } from './pluginSettings';\nimport { importAppPlugin, importDataSourcePlugin } from './plugin_loader';\n\nexport async function loadPlugin(pluginId: string): Promise<GrafanaPlugin> {\n const info = await getPluginSettings(pluginId);\n let result: GrafanaPlugin | undefined;\n\n if (info.type === PluginType.app) {\n result = await importAppPlugin(info);\n }\n if (info.type === PluginType.datasource) {\n result = await importDataSourcePlugin(info);\n }\n if (info.type === PluginType.panel) {\n const panelPlugin = await importPanelPluginFromMeta(info as PanelPluginMeta);\n result = panelPlugin as unknown as GrafanaPlugin;\n }\n if (info.type === PluginType.renderer) {\n result = { meta: info } as GrafanaPlugin;\n }\n\n if (!result) {\n throw new Error('Unknown Plugin type: ' + info.type);\n }\n\n return result;\n}\n","// Libraries\nimport { css } from '@emotion/css';\nimport { cloneDeep, extend } from 'lodash';\nimport React, { PureComponent } from 'react';\n\nimport { PluginMeta, AppPlugin, deprecationWarning } from '@grafana/data';\nimport { AngularComponent, getAngularLoader, getBackendSrv } from '@grafana/runtime';\nimport { Button } from '@grafana/ui';\n\ninterface Props {\n app: AppPlugin;\n}\n\ninterface State {\n angularCtrl: AngularComponent | null;\n refresh: number;\n}\n\nexport class AppConfigCtrlWrapper extends PureComponent<Props, State> {\n element: HTMLElement | null = null;\n //@ts-ignore\n model: PluginMeta;\n\n // Needed for angular scope\n preUpdateHook = () => Promise.resolve();\n postUpdateHook = () => Promise.resolve();\n\n constructor(props: Props) {\n super(props);\n this.state = {\n angularCtrl: null,\n refresh: 0,\n };\n }\n\n componentDidMount() {\n // Force a reload after the first mount -- is there a better way to do this?\n setTimeout(() => {\n this.setState({ refresh: this.state.refresh + 1 });\n }, 5);\n }\n\n componentDidUpdate(prevProps: Props) {\n if (!this.element || this.state.angularCtrl) {\n return;\n }\n\n // Set a copy of the meta\n this.model = cloneDeep(this.props.app.meta);\n\n const loader = getAngularLoader();\n const template = '<plugin-component type=\"app-config-ctrl\"></plugin-component>';\n const scopeProps = {\n ctrl: this,\n // used by angular injectorMonkeyPatch to detect this scenario\n isAppConfigCtrl: true,\n };\n const angularCtrl = loader.load(this.element, scopeProps, template);\n\n this.setState({ angularCtrl });\n }\n\n render() {\n const model = this.model;\n\n const withRightMargin = css({ marginRight: '8px' });\n\n return (\n <div>\n <div ref={(element) => (this.element = element)} />\n <br />\n <br />\n {model && (\n <div className=\"gf-form\">\n {!model.enabled && (\n <Button variant=\"primary\" onClick={this.enable} className={withRightMargin}>\n Enable\n </Button>\n )}\n {model.enabled && (\n <Button variant=\"primary\" onClick={this.update} className={withRightMargin}>\n Update\n </Button>\n )}\n {model.enabled && (\n <Button variant=\"destructive\" onClick={this.disable} className={withRightMargin}>\n Disable\n </Button>\n )}\n </div>\n )}\n </div>\n );\n }\n\n //-----------------------------------------------------------\n // Copied from plugin_edit_ctrl\n //-----------------------------------------------------------\n\n update = () => {\n const pluginId = this.model.id;\n\n this.preUpdateHook()\n .then(() => {\n const updateCmd = extend(\n {\n enabled: this.model.enabled,\n pinned: this.model.pinned,\n jsonData: this.model.jsonData,\n secureJsonData: this.model.secureJsonData,\n },\n {}\n );\n return getBackendSrv().post(`/api/plugins/${pluginId}/settings`, updateCmd);\n })\n .then(this.postUpdateHook)\n .then((res) => {\n window.location.href = window.location.href;\n });\n };\n\n setPreUpdateHook = (callback: () => any) => {\n this.preUpdateHook = callback;\n };\n\n setPostUpdateHook = (callback: () => any) => {\n this.postUpdateHook = callback;\n };\n\n // Stub to avoid unknown function in legacy code\n importDashboards = (): Promise<void> => {\n deprecationWarning('AppConfig', 'importDashboards()');\n return Promise.resolve();\n };\n\n enable = () => {\n this.model.enabled = true;\n this.model.pinned = true;\n this.update();\n };\n\n disable = () => {\n this.model.enabled = false;\n this.model.pinned = false;\n this.update();\n };\n}\n","import { extend } from 'lodash';\nimport React, { PureComponent } from 'react';\n\nimport { AppEvents, PluginMeta, DataSourceApi } from '@grafana/data';\nimport { getBackendSrv } from '@grafana/runtime';\nimport { appEvents } from 'app/core/core';\nimport DashboardsTable from 'app/features/datasources/DashboardsTable';\nimport { PluginDashboard } from 'app/types';\n\ninterface Props {\n plugin: PluginMeta;\n datasource?: DataSourceApi;\n}\n\ninterface State {\n dashboards: PluginDashboard[];\n loading: boolean;\n}\n\nexport class PluginDashboards extends PureComponent<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = {\n loading: true,\n dashboards: [],\n };\n }\n\n async componentDidMount() {\n const pluginId = this.props.plugin.id;\n getBackendSrv()\n .get(`/api/plugins/${pluginId}/dashboards`)\n .then((dashboards: any) => {\n this.setState({ dashboards, loading: false });\n });\n }\n\n importAll = () => {\n this.importNext(0);\n };\n\n private importNext = (index: number) => {\n const { dashboards } = this.state;\n return this.import(dashboards[index], true).then(() => {\n if (index + 1 < dashboards.length) {\n return new Promise<void>((resolve) => {\n setTimeout(() => {\n this.importNext(index + 1).then(() => {\n resolve();\n });\n }, 500);\n });\n } else {\n return Promise.resolve();\n }\n });\n };\n\n import = (dash: PluginDashboard, overwrite: boolean) => {\n const { plugin, datasource } = this.props;\n\n const installCmd: any = {\n pluginId: plugin.id,\n path: dash.path,\n overwrite: overwrite,\n inputs: [],\n };\n\n if (datasource) {\n installCmd.inputs.push({\n name: '*',\n type: 'datasource',\n pluginId: datasource.meta.id,\n value: datasource.name,\n });\n }\n\n return getBackendSrv()\n .post(`/api/dashboards/import`, installCmd)\n .then((res: PluginDashboard) => {\n appEvents.emit(AppEvents.alertSuccess, ['Dashboard Imported', dash.title]);\n extend(dash, res);\n this.setState({ dashboards: [...this.state.dashboards] });\n });\n };\n\n remove = (dash: PluginDashboard) => {\n getBackendSrv()\n .delete('/api/dashboards/uid/' + dash.uid)\n .then(() => {\n dash.imported = false;\n this.setState({ dashboards: [...this.state.dashboards] });\n });\n };\n\n render() {\n const { loading, dashboards } = this.state;\n if (loading) {\n return <div>loading...</div>;\n }\n if (!dashboards || !dashboards.length) {\n return <div>No dashboards are included with this plugin</div>;\n }\n\n return (\n <div className=\"gf-form-group\">\n <DashboardsTable dashboards={dashboards} onImport={this.import} onRemove={this.remove} />\n </div>\n );\n }\n}\n","import { css, cx } from '@emotion/css';\nimport React from 'react';\n\nimport { AppPlugin, GrafanaTheme2, UrlQueryMap } from '@grafana/data';\nimport { useStyles2 } from '@grafana/ui';\n\nimport { VersionList } from '../components/VersionList';\nimport { usePluginConfig } from '../hooks/usePluginConfig';\nimport { CatalogPlugin, PluginTabIds } from '../types';\n\nimport { AppConfigCtrlWrapper } from './AppConfigWrapper';\nimport { PluginDashboards } from './PluginDashboards';\n\ntype Props = {\n plugin: CatalogPlugin;\n queryParams: UrlQueryMap;\n pageId: string;\n};\n\nexport function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.Element {\n const styles = useStyles2(getStyles);\n const { value: pluginConfig } = usePluginConfig(plugin);\n\n if (pageId === PluginTabIds.OVERVIEW) {\n return (\n <div\n className={cx(styles.readme, styles.container)}\n dangerouslySetInnerHTML={{\n __html: plugin.details?.readme ?? 'No plugin help or readme markdown file was found',\n }}\n />\n );\n }\n\n if (pageId === PluginTabIds.VERSIONS) {\n return (\n <div className={styles.container}>\n <VersionList versions={plugin.details?.versions} installedVersion={plugin.installedVersion} />\n </div>\n );\n }\n\n if (pageId === PluginTabIds.CONFIG && pluginConfig?.angularConfigCtrl) {\n return (\n <div className={styles.container}>\n <AppConfigCtrlWrapper app={pluginConfig as AppPlugin} />\n </div>\n );\n }\n\n if (pluginConfig?.configPages) {\n for (const configPage of pluginConfig.configPages) {\n if (pageId === configPage.id) {\n return (\n <div className={styles.container}>\n <configPage.body plugin={pluginConfig} query={queryParams} />\n </div>\n );\n }\n }\n }\n\n if (pageId === PluginTabIds.DASHBOARDS && pluginConfig) {\n return (\n <div className={styles.container}>\n <PluginDashboards plugin={pluginConfig?.meta} />\n </div>\n );\n }\n\n return (\n <div className={styles.container}>\n <p>Page not found.</p>\n </div>\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => ({\n container: css`\n padding: ${theme.spacing(3, 4)};\n `,\n readme: css`\n & img {\n max-width: 100%;\n }\n\n h1,\n h2,\n h3 {\n margin-top: ${theme.spacing(3)};\n margin-bottom: ${theme.spacing(2)};\n }\n\n *:first-child {\n margin-top: 0;\n }\n\n li {\n margin-left: ${theme.spacing(2)};\n & > p {\n margin: ${theme.spacing()} 0;\n }\n }\n\n a {\n color: ${theme.colors.text.link};\n\n &:hover {\n color: ${theme.colors.text.link};\n text-decoration: underline;\n }\n }\n `,\n});\n","import React, { ReactElement } from 'react';\n\nimport { PluginErrorCode } from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\nimport { Alert } from '@grafana/ui';\n\nimport { CatalogPlugin } from '../types';\n\ntype Props = {\n className?: string;\n plugin: CatalogPlugin;\n};\n\nexport function PluginDetailsDisabledError({ className, plugin }: Props): ReactElement | null {\n if (!plugin.isDisabled) {\n return null;\n }\n\n return (\n <Alert\n severity=\"error\"\n title=\"Plugin disabled\"\n className={className}\n aria-label={selectors.pages.PluginPage.disabledInfo}\n >\n {renderDescriptionFromError(plugin.error)}\n <p>Please contact your server administrator to get this resolved.</p>\n <a\n href=\"https://grafana.com/docs/grafana/latest/administration/cli/#plugins-commands\"\n className=\"external-link\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Read more about managing plugins\n </a>\n </Alert>\n );\n}\n\nfunction renderDescriptionFromError(error?: PluginErrorCode): ReactElement {\n switch (error) {\n case PluginErrorCode.modifiedSignature:\n return (\n <p>\n Grafana Labs checks each plugin to verify that it has a valid digital signature. While doing this, we\n discovered that the content of this plugin does not match its signature. We can not guarantee the trustworthy\n of this plugin and have therefore disabled it. We recommend you to reinstall the plugin to make sure you are\n running a verified version of this plugin.\n </p>\n );\n case PluginErrorCode.invalidSignature:\n return (\n <p>\n Grafana Labs checks each plugin to verify that it has a valid digital signature. While doing this, we\n discovered that it was invalid. We can not guarantee the trustworthy of this plugin and have therefore\n disabled it. We recommend you to reinstall the plugin to make sure you are running a verified version of this\n plugin.\n </p>\n );\n case PluginErrorCode.missingSignature:\n return (\n <p>\n Grafana Labs checks each plugin to verify that it has a valid digital signature. While doing this, we\n discovered that there is no signature for this plugin. We can not guarantee the trustworthy of this plugin and\n have therefore disabled it. We recommend you to reinstall the plugin to make sure you are running a verified\n version of this plugin.\n </p>\n );\n default:\n return (\n <p>\n We failed to run this plugin due to an unkown reason and have therefor disabled it. We recommend you to\n reinstall the plugin to make sure you are running a working version of this plugin.\n </p>\n );\n }\n}\n","import React from 'react';\n\nimport { PluginMeta } from '@grafana/data';\nimport { Button } from '@grafana/ui';\n\nimport { updatePluginSettings } from '../../api';\nimport { usePluginConfig } from '../../hooks/usePluginConfig';\nimport { CatalogPlugin } from '../../types';\n\ntype Props = {\n plugin: CatalogPlugin;\n};\n\nexport function GetStartedWithApp({ plugin }: Props): React.ReactElement | null {\n const { value: pluginConfig } = usePluginConfig(plugin);\n\n if (!pluginConfig) {\n return null;\n }\n\n const { enabled, jsonData } = pluginConfig?.meta;\n\n const enable = () =>\n updatePluginSettingsAndReload(plugin.id, {\n enabled: true,\n pinned: true,\n jsonData,\n });\n\n const disable = () => {\n updatePluginSettingsAndReload(plugin.id, {\n enabled: false,\n pinned: false,\n jsonData,\n });\n };\n\n return (\n <>\n {!enabled && (\n <Button variant=\"primary\" onClick={enable}>\n Enable\n </Button>\n )}\n\n {enabled && (\n <Button variant=\"destructive\" onClick={disable}>\n Disable\n </Button>\n )}\n </>\n );\n}\n\nconst updatePluginSettingsAndReload = async (id: string, data: Partial<PluginMeta>) => {\n try {\n await updatePluginSettings(id, data);\n\n // Reloading the page as the plugin meta changes made here wouldn't be propagated throughout the app.\n window.location.reload();\n } catch (e) {\n console.error('Error while updating the plugin', e);\n }\n};\n","import React, { useCallback } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { DataSourcePluginMeta } from '@grafana/data';\nimport { Button } from '@grafana/ui';\nimport { addDataSource } from 'app/features/datasources/state/actions';\n\nimport { isDataSourceEditor } from '../../permissions';\nimport { CatalogPlugin } from '../../types';\n\ntype Props = {\n plugin: CatalogPlugin;\n};\n\nexport function GetStartedWithDataSource({ plugin }: Props): React.ReactElement | null {\n const dispatch = useDispatch();\n const onAddDataSource = useCallback(() => {\n const meta = {\n name: plugin.name,\n id: plugin.id,\n } as DataSourcePluginMeta;\n\n dispatch(addDataSource(meta));\n }, [dispatch, plugin]);\n\n if (!isDataSourceEditor()) {\n return null;\n }\n\n return (\n <Button variant=\"primary\" onClick={onAddDataSource}>\n Create a {plugin.name} data source\n </Button>\n );\n}\n","import React, { ReactElement } from 'react';\n\nimport { PluginType } from '@grafana/data';\n\nimport { CatalogPlugin } from '../../types';\n\nimport { GetStartedWithApp } from './GetStartedWithApp';\nimport { GetStartedWithDataSource } from './GetStartedWithDataSource';\n\ntype Props = {\n plugin: CatalogPlugin;\n};\n\nexport function GetStartedWithPlugin({ plugin }: Props): ReactElement | null {\n if (!plugin.isInstalled || plugin.isDisabled) {\n return null;\n }\n\n switch (plugin.type) {\n case PluginType.datasource:\n return <GetStartedWithDataSource plugin={plugin} />;\n case PluginType.app:\n return <GetStartedWithApp plugin={plugin} />;\n default:\n return null;\n }\n}\n","import React from 'react';\n\nimport { HorizontalGroup, LinkButton } from '@grafana/ui';\n\nimport { getExternalManageLink } from '../../helpers';\nimport { PluginStatus } from '../../types';\n\ntype ExternallyManagedButtonProps = {\n pluginId: string;\n pluginStatus: PluginStatus;\n};\n\nexport function ExternallyManagedButton({ pluginId, pluginStatus }: ExternallyManagedButtonProps) {\n const externalManageLink = `${getExternalManageLink(pluginId)}/?tab=installation`;\n\n if (pluginStatus === PluginStatus.UPDATE) {\n return (\n <HorizontalGroup height=\"auto\">\n <LinkButton href={externalManageLink} target=\"_blank\" rel=\"noopener noreferrer\">\n Update via grafana.com\n </LinkButton>\n <LinkButton variant=\"destructive\" href={externalManageLink} target=\"_blank\" rel=\"noopener noreferrer\">\n Uninstall via grafana.com\n </LinkButton>\n </HorizontalGroup>\n );\n }\n\n if (pluginStatus === PluginStatus.UNINSTALL) {\n return (\n <LinkButton variant=\"destructive\" href={externalManageLink} target=\"_blank\" rel=\"noopener noreferrer\">\n Uninstall via grafana.com\n </LinkButton>\n );\n }\n\n return (\n <LinkButton href={externalManageLink} target=\"_blank\" rel=\"noopener noreferrer\">\n Install via grafana.com\n </LinkButton>\n );\n}\n","import React, { useState } from 'react';\n\nimport { AppEvents } from '@grafana/data';\nimport { Button, HorizontalGroup, ConfirmModal } from '@grafana/ui';\nimport appEvents from 'app/core/app_events';\n\nimport { useInstallStatus, useUninstallStatus, useInstall, useUninstall } from '../../state/hooks';\nimport { CatalogPlugin, PluginStatus, Version } from '../../types';\n\ntype InstallControlsButtonProps = {\n plugin: CatalogPlugin;\n pluginStatus: PluginStatus;\n latestCompatibleVersion?: Version;\n};\n\nexport function InstallControlsButton({ plugin, pluginStatus, latestCompatibleVersion }: InstallControlsButtonProps) {\n const { isInstalling, error: errorInstalling } = useInstallStatus();\n const { isUninstalling, error: errorUninstalling } = useUninstallStatus();\n const install = useInstall();\n const uninstall = useUninstall();\n const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);\n const showConfirmModal = () => setIsConfirmModalVisible(true);\n const hideConfirmModal = () => setIsConfirmModalVisible(false);\n const uninstallBtnText = isUninstalling ? 'Uninstalling' : 'Uninstall';\n\n const onInstall = async () => {\n await install(plugin.id, latestCompatibleVersion?.version);\n if (!errorInstalling) {\n appEvents.emit(AppEvents.alertSuccess, [`Installed ${plugin.name}`]);\n }\n };\n\n const onUninstall = async () => {\n hideConfirmModal();\n await uninstall(plugin.id);\n if (!errorUninstalling) {\n appEvents.emit(AppEvents.alertSuccess, [`Uninstalled ${plugin.name}`]);\n }\n };\n\n const onUpdate = async () => {\n await install(plugin.id, latestCompatibleVersion?.version, true);\n if (!errorInstalling) {\n appEvents.emit(AppEvents.alertSuccess, [`Updated ${plugin.name}`]);\n }\n };\n\n if (pluginStatus === PluginStatus.UNINSTALL) {\n return (\n <>\n <ConfirmModal\n isOpen={isConfirmModalVisible}\n title={`Uninstall ${plugin.name}`}\n body=\"Are you sure you want to uninstall this plugin?\"\n confirmText=\"Confirm\"\n icon=\"exclamation-triangle\"\n onConfirm={onUninstall}\n onDismiss={hideConfirmModal}\n />\n <HorizontalGroup height=\"auto\">\n <Button variant=\"destructive\" disabled={isUninstalling} onClick={showConfirmModal}>\n {uninstallBtnText}\n </Button>\n </HorizontalGroup>\n </>\n );\n }\n\n if (pluginStatus === PluginStatus.UPDATE) {\n return (\n <HorizontalGroup height=\"auto\">\n <Button disabled={isInstalling} onClick={onUpdate}>\n {isInstalling ? 'Updating' : 'Update'}\n </Button>\n <Button variant=\"destructive\" disabled={isUninstalling} onClick={onUninstall}>\n {uninstallBtnText}\n </Button>\n </HorizontalGroup>\n );\n }\n\n return (\n <Button disabled={isInstalling} onClick={onInstall}>\n {isInstalling ? 'Installing' : 'Install'}\n </Button>\n );\n}\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2, PluginType } from '@grafana/data';\nimport { config, featureEnabled } from '@grafana/runtime';\nimport { HorizontalGroup, Icon, LinkButton, useStyles2 } from '@grafana/ui';\n\nimport { getExternalManageLink, isInstallControlsEnabled } from '../../helpers';\nimport { isGrafanaAdmin } from '../../permissions';\nimport { useIsRemotePluginsAvailable } from '../../state/hooks';\nimport { CatalogPlugin, PluginStatus, Version } from '../../types';\n\nimport { ExternallyManagedButton } from './ExternallyManagedButton';\nimport { InstallControlsButton } from './InstallControlsButton';\n\ninterface Props {\n plugin: CatalogPlugin;\n latestCompatibleVersion?: Version;\n}\n\nexport const InstallControls = ({ plugin, latestCompatibleVersion }: Props) => {\n const styles = useStyles2(getStyles);\n const isExternallyManaged = config.pluginAdminExternalManageEnabled;\n const hasPermission = isGrafanaAdmin();\n const isRemotePluginsAvailable = useIsRemotePluginsAvailable();\n const isCompatible = Boolean(latestCompatibleVersion);\n const isInstallControlsDisabled = plugin.isCore || plugin.isDisabled || !isInstallControlsEnabled();\n\n const pluginStatus = plugin.isInstalled\n ? plugin.hasUpdate\n ? PluginStatus.UPDATE\n : PluginStatus.UNINSTALL\n : PluginStatus.INSTALL;\n\n if (isInstallControlsDisabled) {\n return null;\n }\n\n if (plugin.type === PluginType.renderer) {\n return <div className={styles.message}>Renderer plugins cannot be managed by the Plugin Catalog.</div>;\n }\n\n if (plugin.isEnterprise && !featureEnabled('enterprise.plugins')) {\n return (\n <HorizontalGroup height=\"auto\" align=\"center\">\n <span className={styles.message}>No valid Grafana Enterprise license detected.</span>\n <LinkButton\n href={`${getExternalManageLink(plugin.id)}?utm_source=grafana_catalog_learn_more`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n size=\"sm\"\n fill=\"text\"\n icon=\"external-link-alt\"\n >\n Learn more\n </LinkButton>\n </HorizontalGroup>\n );\n }\n\n if (plugin.isDev) {\n return (\n <div className={styles.message}>This is a development build of the plugin and can't be uninstalled.</div>\n );\n }\n\n if (!hasPermission && !isExternallyManaged) {\n const message = `You do not have permission to ${pluginStatus} this plugin.`;\n return <div className={styles.message}>{message}</div>;\n }\n\n if (!plugin.isPublished) {\n return (\n <div className={styles.message}>\n <Icon name=\"exclamation-triangle\" /> This plugin is not published to{' '}\n <a href=\"https://www.grafana.com/plugins\" target=\"__blank\" rel=\"noreferrer\">\n grafana.com/plugins\n </a>{' '}\n and can't be managed via the catalog.\n </div>\n );\n }\n\n if (!isCompatible) {\n return (\n <div className={styles.message}>\n <Icon name=\"exclamation-triangle\" />\n This plugin doesn't support your version of Grafana.\n </div>\n );\n }\n\n if (isExternallyManaged) {\n return <ExternallyManagedButton pluginId={plugin.id} pluginStatus={pluginStatus} />;\n }\n\n if (!isRemotePluginsAvailable) {\n return (\n <div className={styles.message}>\n The install controls have been disabled because the Grafana server cannot access grafana.com.\n </div>\n );\n }\n\n return (\n <InstallControlsButton\n plugin={plugin}\n pluginStatus={pluginStatus}\n latestCompatibleVersion={latestCompatibleVersion}\n />\n );\n};\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n message: css`\n color: ${theme.colors.text.secondary};\n `,\n };\n};\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2, Icon } from '@grafana/ui';\n\nimport { Version, CatalogPlugin, PluginIconName } from '../types';\n\ntype Props = {\n plugin: CatalogPlugin;\n latestCompatibleVersion?: Version;\n className?: string;\n};\n\nexport function PluginDetailsHeaderDependencies({\n plugin,\n latestCompatibleVersion,\n className,\n}: Props): React.ReactElement | null {\n const styles = useStyles2(getStyles);\n const pluginDependencies = plugin.details?.pluginDependencies;\n const grafanaDependency = plugin.isInstalled\n ? plugin.details?.grafanaDependency\n : latestCompatibleVersion?.grafanaDependency || plugin.details?.grafanaDependency;\n const hasNoDependencyInfo = !grafanaDependency && (!pluginDependencies || !pluginDependencies.length);\n\n if (hasNoDependencyInfo) {\n return null;\n }\n\n return (\n <div className={className}>\n <div className={styles.dependencyTitle}>Dependencies:</div>\n\n {/* Grafana dependency */}\n {Boolean(grafanaDependency) && (\n <div>\n <Icon name=\"grafana\" className={styles.icon} />\n Grafana {grafanaDependency}\n </div>\n )}\n\n {/* Plugin dependencies */}\n {pluginDependencies && pluginDependencies.length > 0 && (\n <div>\n {pluginDependencies.map((p) => {\n return (\n <span key={p.name}>\n <Icon name={PluginIconName[p.type]} className={styles.icon} />\n {p.name} {p.version}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n dependencyTitle: css`\n font-weight: ${theme.typography.fontWeightBold};\n margin-right: ${theme.spacing(0.5)};\n\n &::after {\n content: '';\n padding: 0;\n }\n `,\n icon: css`\n color: ${theme.colors.text.secondary};\n margin-right: ${theme.spacing(0.5)};\n `,\n };\n};\n","import { css } from '@emotion/css';\nimport { capitalize } from 'lodash';\nimport React from 'react';\n\nimport { GrafanaTheme2, PluginSignatureType } from '@grafana/data';\nimport { useStyles2, Icon, Badge, IconName } from '@grafana/ui';\n\nconst SIGNATURE_ICONS: Record<string, IconName> = {\n [PluginSignatureType.grafana]: 'grafana',\n [PluginSignatureType.commercial]: 'shield',\n [PluginSignatureType.community]: 'shield',\n DEFAULT: 'shield-exclamation',\n};\n\ntype Props = {\n signatureType?: PluginSignatureType;\n signatureOrg?: string;\n};\n\n// Shows more information about a valid signature\nexport function PluginSignatureDetailsBadge({ signatureType, signatureOrg = '' }: Props): React.ReactElement | null {\n const styles = useStyles2(getStyles);\n\n if (!signatureType && !signatureOrg) {\n return null;\n }\n\n const signatureTypeText = signatureType === PluginSignatureType.grafana ? 'Grafana Labs' : capitalize(signatureType);\n const signatureIcon = SIGNATURE_ICONS[signatureType || ''] || SIGNATURE_ICONS.DEFAULT;\n\n return (\n <>\n <DetailsBadge>\n <strong className={styles.strong}>Level: </strong>\n <Icon size=\"xs\" name={signatureIcon} />\n \n {signatureTypeText}\n </DetailsBadge>\n\n <DetailsBadge>\n <strong className={styles.strong}>Signed by:</strong> {signatureOrg}\n </DetailsBadge>\n </>\n );\n}\n\nexport const DetailsBadge: React.FC = ({ children }) => {\n const styles = useStyles2(getStyles);\n\n return <Badge color=\"green\" className={styles.badge} text={<>{children}</>} />;\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n badge: css`\n background-color: ${theme.colors.background.canvas};\n border-color: ${theme.colors.border.strong};\n color: ${theme.colors.text.secondary};\n margin-left: ${theme.spacing()};\n `,\n strong: css`\n color: ${theme.colors.text.primary};\n `,\n icon: css`\n margin-right: ${theme.spacing(0.5)};\n `,\n});\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2, PluginSignatureStatus } from '@grafana/data';\nimport { PluginSignatureBadge, useStyles2 } from '@grafana/ui';\n\nimport { CatalogPlugin } from '../types';\n\nimport { PluginSignatureDetailsBadge } from './PluginSignatureDetailsBadge';\n\ntype Props = {\n plugin: CatalogPlugin;\n};\n\n// Designed to show plugin signature information in the header on the plugin's details page\nexport function PluginDetailsHeaderSignature({ plugin }: Props): React.ReactElement {\n const styles = useStyles2(getStyles);\n const isSignatureValid = plugin.signature === PluginSignatureStatus.valid;\n\n return (\n <div className={styles.container}>\n <a\n href=\"https://grafana.com/docs/grafana/latest/plugins/plugin-signatures/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n className={styles.link}\n >\n <PluginSignatureBadge status={plugin.signature} />\n </a>\n\n {isSignatureValid && (\n <PluginSignatureDetailsBadge signatureType={plugin.signatureType} signatureOrg={plugin.signatureOrg} />\n )}\n </div>\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n container: css`\n display: flex;\n `,\n link: css`\n display: inline-flex;\n align-items: center;\n `,\n };\n};\n","import { css, cx } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2, Icon, HorizontalGroup } from '@grafana/ui';\n\nimport { getLatestCompatibleVersion } from '../helpers';\nimport { CatalogPlugin } from '../types';\n\nimport { PluginDisabledBadge } from './Badges';\nimport { GetStartedWithPlugin } from './GetStartedWithPlugin';\nimport { InstallControls } from './InstallControls';\nimport { PluginDetailsHeaderDependencies } from './PluginDetailsHeaderDependencies';\nimport { PluginDetailsHeaderSignature } from './PluginDetailsHeaderSignature';\nimport { PluginLogo } from './PluginLogo';\n\ntype Props = {\n currentUrl: string;\n parentUrl: string;\n plugin: CatalogPlugin;\n};\n\nexport function PluginDetailsHeader({ plugin, currentUrl, parentUrl }: Props): React.ReactElement {\n const styles = useStyles2(getStyles);\n const latestCompatibleVersion = getLatestCompatibleVersion(plugin.details?.versions);\n const version = plugin.installedVersion || latestCompatibleVersion?.version;\n\n return (\n <div>\n <div className=\"page-container\">\n <div className={styles.headerContainer}>\n <PluginLogo\n alt={`${plugin.name} logo`}\n src={plugin.info.logos.small}\n className={css`\n object-fit: contain;\n width: 100%;\n height: 68px;\n max-width: 68px;\n `}\n />\n\n <div className={styles.headerWrapper}>\n {/* Title & navigation */}\n <nav className={styles.breadcrumb} aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a className={styles.textUnderline} href={parentUrl}>\n Plugins\n </a>\n </li>\n <li>\n <a href={currentUrl} aria-current=\"page\">\n {plugin.name}\n </a>\n </li>\n </ol>\n </nav>\n\n <div className={styles.headerInformationRow}>\n {/* Org name */}\n <span>{plugin.orgName}</span>\n\n {/* Links */}\n {plugin.details?.links.map((link: any) => (\n <a key={link.name} href={link.url}>\n {link.name}\n </a>\n ))}\n\n {/* Downloads */}\n {plugin.downloads > 0 && (\n <span>\n <Icon name=\"cloud-download\" />\n {` ${new Intl.NumberFormat().format(plugin.downloads)}`}{' '}\n </span>\n )}\n\n {/* Version */}\n {Boolean(version) && <span>{version}</span>}\n\n {/* Signature information */}\n <PluginDetailsHeaderSignature plugin={plugin} />\n\n {plugin.isDisabled && <PluginDisabledBadge error={plugin.error!} />}\n </div>\n\n <PluginDetailsHeaderDependencies\n plugin={plugin}\n latestCompatibleVersion={latestCompatibleVersion}\n className={cx(styles.headerInformationRow, styles.headerInformationRowSecondary)}\n />\n\n <p>{plugin.description}</p>\n\n <HorizontalGroup height=\"auto\">\n <InstallControls plugin={plugin} latestCompatibleVersion={latestCompatibleVersion} />\n <GetStartedWithPlugin plugin={plugin} />\n </HorizontalGroup>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n headerContainer: css`\n display: flex;\n margin-bottom: ${theme.spacing(3)};\n margin-top: ${theme.spacing(3)};\n min-height: 120px;\n `,\n headerWrapper: css`\n margin-left: ${theme.spacing(3)};\n `,\n breadcrumb: css`\n font-size: ${theme.typography.h2.fontSize};\n li {\n display: inline;\n list-style: none;\n &::after {\n content: '/';\n padding: 0 0.25ch;\n }\n &:last-child::after {\n content: '';\n }\n }\n `,\n headerInformationRow: css`\n display: flex;\n align-items: center;\n margin-top: ${theme.spacing()};\n margin-bottom: ${theme.spacing()};\n flex-flow: wrap;\n & > * {\n &::after {\n content: '|';\n padding: 0 ${theme.spacing()};\n }\n &:last-child::after {\n content: '';\n padding-right: 0;\n }\n }\n font-size: ${theme.typography.h4.fontSize};\n\n a {\n &:hover {\n text-decoration: underline;\n }\n }\n `,\n headerInformationRowSecondary: css`\n font-size: ${theme.typography.body.fontSize};\n `,\n headerOrgName: css`\n font-size: ${theme.typography.h4.fontSize};\n `,\n signature: css`\n margin: ${theme.spacing(3)};\n margin-bottom: 0;\n `,\n textUnderline: css`\n text-decoration: underline;\n `,\n };\n};\n","import React from 'react';\n\nimport { PluginErrorCode, PluginSignatureStatus } from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\nimport { Alert } from '@grafana/ui';\n\nimport { CatalogPlugin } from '../types';\n\ntype Props = {\n className?: string;\n plugin: CatalogPlugin;\n};\n\n// Designed to show signature information inside the active tab on the plugin's details page\nexport function PluginDetailsSignature({ className, plugin }: Props): React.ReactElement | null {\n const isSignatureValid = plugin.signature === PluginSignatureStatus.valid;\n const isCore = plugin.signature === PluginSignatureStatus.internal;\n const isDisabled = plugin.isDisabled && isDisabledDueTooSignatureError(plugin.error);\n\n // The basic information is already available in the header\n if (isSignatureValid || isCore || isDisabled) {\n return null;\n }\n\n return (\n <Alert\n severity=\"warning\"\n title=\"Invalid plugin signature\"\n aria-label={selectors.pages.PluginPage.signatureInfo}\n className={className}\n >\n <p>\n Grafana Labs checks each plugin to verify that it has a valid digital signature. Plugin signature verification\n is part of our security measures to ensure plugins are safe and trustworthy. Grafana Labs can’t guarantee the\n integrity of this unsigned plugin. Ask the plugin author to request it to be signed.\n </p>\n\n <a\n href=\"https://grafana.com/docs/grafana/latest/plugins/plugin-signatures/\"\n className=\"external-link\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Read more about plugins signing.\n </a>\n </Alert>\n );\n}\n\nfunction isDisabledDueTooSignatureError(error: PluginErrorCode | undefined) {\n // If the plugin is disabled due to signature error we rely on the disabled\n // error message instad of the warning about the signature.\n\n switch (error) {\n case PluginErrorCode.invalidSignature:\n case PluginErrorCode.missingSignature:\n case PluginErrorCode.modifiedSignature:\n return true;\n\n default:\n return false;\n }\n}\n","import { css } from '@emotion/css';\nimport React, { useEffect } from 'react';\nimport { usePrevious } from 'react-use';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { locationService } from '@grafana/runtime';\nimport { useStyles2, TabsBar, TabContent, Tab, Alert, IconName } from '@grafana/ui';\nimport { Layout } from '@grafana/ui/src/components/Layout/Layout';\nimport { Page } from 'app/core/components/Page/Page';\nimport { GrafanaRouteComponentProps } from 'app/core/navigation/types';\nimport { AppNotificationSeverity } from 'app/types';\n\nimport { Loader } from '../components/Loader';\nimport { PluginDetailsBody } from '../components/PluginDetailsBody';\nimport { PluginDetailsDisabledError } from '../components/PluginDetailsDisabledError';\nimport { PluginDetailsHeader } from '../components/PluginDetailsHeader';\nimport { PluginDetailsSignature } from '../components/PluginDetailsSignature';\nimport { usePluginDetailsTabs } from '../hooks/usePluginDetailsTabs';\nimport { useGetSingle, useFetchStatus, useFetchDetailsStatus } from '../state/hooks';\nimport { PluginTabLabels, PluginTabIds, PluginDetailsTab } from '../types';\n\ntype Props = GrafanaRouteComponentProps<{ pluginId?: string }>;\n\nexport default function PluginDetails({ match, queryParams }: Props): JSX.Element | null {\n const {\n params: { pluginId = '' },\n url,\n } = match;\n const parentUrl = url.substring(0, url.lastIndexOf('/'));\n const defaultTabs: PluginDetailsTab[] = [\n {\n label: PluginTabLabels.OVERVIEW,\n icon: 'file-alt',\n id: PluginTabIds.OVERVIEW,\n href: `${url}?page=${PluginTabIds.OVERVIEW}`,\n },\n ];\n const plugin = useGetSingle(pluginId); // fetches the localplugin settings\n const { tabs, defaultTab } = usePluginDetailsTabs(plugin, defaultTabs);\n const { isLoading: isFetchLoading } = useFetchStatus();\n const { isLoading: isFetchDetailsLoading } = useFetchDetailsStatus();\n const styles = useStyles2(getStyles);\n const prevTabs = usePrevious(tabs);\n const pageId = (queryParams.page as PluginTabIds) || defaultTab;\n\n // If an app plugin is uninstalled we need to reset the active tab when the config / dashboards tabs are removed.\n useEffect(() => {\n const hasUninstalledWithConfigPages = prevTabs && prevTabs.length > tabs.length;\n const isViewingAConfigPage = pageId !== PluginTabIds.OVERVIEW && pageId !== PluginTabIds.VERSIONS;\n\n if (hasUninstalledWithConfigPages && isViewingAConfigPage) {\n locationService.replace(`${url}?page=${PluginTabIds.OVERVIEW}`);\n }\n }, [pageId, url, tabs, prevTabs]);\n\n if (isFetchLoading || isFetchDetailsLoading) {\n return (\n <Page>\n <Loader />\n </Page>\n );\n }\n\n if (!plugin) {\n return (\n <Layout justify=\"center\" align=\"center\">\n <Alert severity={AppNotificationSeverity.Warning} title=\"Plugin not found\">\n That plugin cannot be found. Please check the url is correct or <br />\n go to the <a href={parentUrl}>plugin catalog</a>.\n </Alert>\n </Layout>\n );\n }\n\n return (\n <Page>\n <PluginDetailsHeader currentUrl={`${url}?page=${pageId}`} parentUrl={parentUrl} plugin={plugin} />\n {/* Tab navigation */}\n <div>\n <div className=\"page-container\">\n <TabsBar hideBorder>\n {tabs.map((tab: PluginDetailsTab) => {\n return (\n <Tab\n key={tab.label}\n label={tab.label}\n href={tab.href}\n icon={tab.icon as IconName}\n active={tab.id === pageId}\n />\n );\n })}\n </TabsBar>\n </div>\n </div>\n <Page.Contents>\n {/* Active tab */}\n <TabContent className={styles.tabContent}>\n <PluginDetailsSignature plugin={plugin} className={styles.alert} />\n <PluginDetailsDisabledError plugin={plugin} className={styles.alert} />\n <PluginDetailsBody queryParams={queryParams} plugin={plugin} pageId={pageId} />\n </TabContent>\n </Page.Contents>\n </Page>\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => {\n return {\n alert: css`\n margin: ${theme.spacing(3)};\n margin-bottom: 0;\n `,\n // Needed due to block formatting context\n tabContent: css`\n overflow: auto;\n `,\n };\n};\n","import { useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\n\nimport { PluginIncludeType, PluginType } from '@grafana/data';\n\nimport { usePluginConfig } from '../hooks/usePluginConfig';\nimport { isOrgAdmin } from '../permissions';\nimport { CatalogPlugin, PluginDetailsTab, PluginTabIds, PluginTabLabels } from '../types';\n\ntype ReturnType = {\n error: Error | undefined;\n loading: boolean;\n tabs: PluginDetailsTab[];\n defaultTab: string;\n};\n\nexport const usePluginDetailsTabs = (plugin?: CatalogPlugin, defaultTabs: PluginDetailsTab[] = []): ReturnType => {\n const { loading, error, value: pluginConfig } = usePluginConfig(plugin);\n const isPublished = Boolean(plugin?.isPublished);\n const { pathname } = useLocation();\n\n const [tabs, defaultTab] = useMemo(() => {\n const canConfigurePlugins = isOrgAdmin();\n const tabs: PluginDetailsTab[] = [...defaultTabs];\n let defaultTab;\n\n if (isPublished) {\n tabs.push({\n label: PluginTabLabels.VERSIONS,\n icon: 'history',\n id: PluginTabIds.VERSIONS,\n href: `${pathname}?page=${PluginTabIds.VERSIONS}`,\n });\n }\n\n // Not extending the tabs with the config pages if the plugin is not installed\n if (!pluginConfig) {\n defaultTab = PluginTabIds.OVERVIEW;\n return [tabs, defaultTab];\n }\n\n if (canConfigurePlugins) {\n if (pluginConfig.meta.type === PluginType.app) {\n if (pluginConfig.angularConfigCtrl) {\n tabs.push({\n label: 'Config',\n icon: 'cog',\n id: PluginTabIds.CONFIG,\n href: `${pathname}?page=${PluginTabIds.CONFIG}`,\n });\n defaultTab = PluginTabIds.CONFIG;\n }\n\n if (pluginConfig.configPages) {\n for (const page of pluginConfig.configPages) {\n tabs.push({\n label: page.title,\n icon: page.icon,\n id: page.id,\n href: `${pathname}?page=${page.id}`,\n });\n if (!defaultTab) {\n defaultTab = page.id;\n }\n }\n }\n\n if (pluginConfig.meta.includes?.find((include) => include.type === PluginIncludeType.dashboard)) {\n tabs.push({\n label: 'Dashboards',\n icon: 'apps',\n id: PluginTabIds.DASHBOARDS,\n href: `${pathname}?page=${PluginTabIds.DASHBOARDS}`,\n });\n }\n }\n }\n\n if (!defaultTab) {\n defaultTab = PluginTabIds.OVERVIEW;\n }\n\n return [tabs, defaultTab];\n }, [pluginConfig, defaultTabs, pathname, isPublished]);\n\n return {\n error,\n loading,\n tabs,\n defaultTab,\n };\n};\n","import { createSelector } from '@reduxjs/toolkit';\n\nimport { PluginError, PluginErrorCode } from '@grafana/data';\n\nimport { RequestStatus, PluginCatalogStoreState } from '../types';\n\nimport { pluginsAdapter } from './reducer';\n\nexport const selectRoot = (state: PluginCatalogStoreState) => state.plugins;\n\nexport const selectItems = createSelector(selectRoot, ({ items }) => items);\n\nexport const selectDisplayMode = createSelector(selectRoot, ({ settings }) => settings.displayMode);\n\nexport const { selectAll, selectById } = pluginsAdapter.getSelectors(selectItems);\n\nconst selectInstalled = (filterBy: string) =>\n createSelector(selectAll, (plugins) =>\n plugins.filter((plugin) => (filterBy === 'installed' ? plugin.isInstalled : !plugin.isCore))\n );\n\nconst findByInstallAndType = (filterBy: string, filterByType: string) =>\n createSelector(selectInstalled(filterBy), (plugins) =>\n plugins.filter((plugin) => filterByType === 'all' || plugin.type === filterByType)\n );\n\nconst findByKeyword = (searchBy: string) =>\n createSelector(selectAll, (plugins) => {\n if (searchBy === '') {\n return [];\n }\n\n return plugins.filter((plugin) => {\n const fields: String[] = [];\n if (plugin.name) {\n fields.push(plugin.name.toLowerCase());\n }\n\n if (plugin.orgName) {\n fields.push(plugin.orgName.toLowerCase());\n }\n\n return fields.some((f) => f.includes(searchBy.toLowerCase()));\n });\n });\n\nexport const find = (searchBy: string, filterBy: string, filterByType: string) =>\n createSelector(\n findByInstallAndType(filterBy, filterByType),\n findByKeyword(searchBy),\n (filteredPlugins, searchedPlugins) => {\n return searchBy === '' ? filteredPlugins : searchedPlugins;\n }\n );\n\nexport const selectPluginErrors = createSelector(selectAll, (plugins) =>\n plugins\n ? plugins\n .filter((p) => Boolean(p.error))\n .map(\n (p): PluginError => ({\n pluginId: p.id,\n errorCode: p!.error as PluginErrorCode,\n })\n )\n : []\n);\n\n// The following selectors are used to get information about the outstanding or completed plugins-related network requests.\nexport const selectRequest = (actionType: string) =>\n createSelector(selectRoot, ({ requests = {} }) => requests[actionType]);\n\nexport const selectIsRequestPending = (actionType: string) =>\n createSelector(selectRequest(actionType), (request) => request?.status === RequestStatus.Pending);\n\nexport const selectRequestError = (actionType: string) =>\n createSelector(selectRequest(actionType), (request) =>\n request?.status === RequestStatus.Rejected ? request?.error : null\n );\n\nexport const selectIsRequestNotFetched = (actionType: string) =>\n createSelector(selectRequest(actionType), (request) => request === undefined);\n","import { useEffect } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\n\nimport { PluginError } from '@grafana/data';\n\nimport { sortPlugins, Sorters } from '../helpers';\nimport { CatalogPlugin, PluginCatalogStoreState, PluginListDisplayMode } from '../types';\n\nimport { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall } from './actions';\nimport { setDisplayMode } from './reducer';\nimport {\n find,\n selectAll,\n selectById,\n selectIsRequestPending,\n selectRequestError,\n selectIsRequestNotFetched,\n selectDisplayMode,\n selectPluginErrors,\n} from './selectors';\n\ntype Filters = {\n query?: string;\n filterBy?: string;\n filterByType?: string;\n sortBy?: Sorters;\n};\n\nexport const useGetAllWithFilters = ({\n query = '',\n filterBy = 'installed',\n filterByType = 'all',\n sortBy = Sorters.nameAsc,\n}: Filters) => {\n useFetchAll();\n\n const filtered = useSelector(find(query, filterBy, filterByType));\n const { isLoading, error } = useFetchStatus();\n const sortedAndFiltered = sortPlugins(filtered, sortBy);\n\n return {\n isLoading,\n error,\n plugins: sortedAndFiltered,\n };\n};\n\nexport const useGetAll = (): CatalogPlugin[] => {\n useFetchAll();\n\n return useSelector(selectAll);\n};\n\nexport const useGetSingle = (id: string): CatalogPlugin | undefined => {\n useFetchAll();\n useFetchDetails(id);\n\n return useSelector((state: PluginCatalogStoreState) => selectById(state, id));\n};\n\nexport const useGetErrors = (): PluginError[] => {\n useFetchAll();\n\n return useSelector(selectPluginErrors);\n};\n\nexport const useInstall = () => {\n const dispatch = useDispatch();\n return (id: string, version?: string, isUpdating?: boolean) => dispatch(install({ id, version, isUpdating }));\n};\n\nexport const useUninstall = () => {\n const dispatch = useDispatch();\n\n return (id: string) => dispatch(uninstall(id));\n};\n\nexport const useIsRemotePluginsAvailable = () => {\n const error = useSelector(selectRequestError(fetchRemotePlugins.typePrefix));\n return error === null;\n};\n\nexport const useFetchStatus = () => {\n const isLoading = useSelector(selectIsRequestPending(fetchAll.typePrefix));\n const error = useSelector(selectRequestError(fetchAll.typePrefix));\n\n return { isLoading, error };\n};\n\nexport const useFetchDetailsStatus = () => {\n const isLoading = useSelector(selectIsRequestPending(fetchDetails.typePrefix));\n const error = useSelector(selectRequestError(fetchDetails.typePrefix));\n\n return { isLoading, error };\n};\n\nexport const useInstallStatus = () => {\n const isInstalling = useSelector(selectIsRequestPending(install.typePrefix));\n const error = useSelector(selectRequestError(install.typePrefix));\n\n return { isInstalling, error };\n};\n\nexport const useUninstallStatus = () => {\n const isUninstalling = useSelector(selectIsRequestPending(uninstall.typePrefix));\n const error = useSelector(selectRequestError(uninstall.typePrefix));\n\n return { isUninstalling, error };\n};\n\n// Only fetches in case they were not fetched yet\nexport const useFetchAll = () => {\n const dispatch = useDispatch();\n const isNotFetched = useSelector(selectIsRequestNotFetched(fetchAll.typePrefix));\n\n useEffect(() => {\n isNotFetched && dispatch(fetchAll());\n }, []); // eslint-disable-line\n};\n\nexport const useFetchDetails = (id: string) => {\n const dispatch = useDispatch();\n const plugin = useSelector((state: PluginCatalogStoreState) => selectById(state, id));\n const isNotFetching = !useSelector(selectIsRequestPending(fetchDetails.typePrefix));\n const shouldFetch = isNotFetching && plugin && !plugin.details;\n\n useEffect(() => {\n shouldFetch && dispatch(fetchDetails(id));\n }, [plugin]); // eslint-disable-line\n};\n\nexport const useDisplayMode = () => {\n const dispatch = useDispatch();\n const displayMode = useSelector(selectDisplayMode);\n\n return {\n displayMode,\n setDisplayMode: (v: PluginListDisplayMode) => dispatch(setDisplayMode(v)),\n };\n};\n","import { useEffect, useRef } from 'react';\nexport default function usePrevious(state) {\n var ref = useRef();\n useEffect(function () {\n ref.current = state;\n });\n return ref.current;\n}\n"],"names":["dashboards","onImport","onRemove","buttonText","dashboard","revision","importedRevision","className","map","index","Icon","name","imported","href","importedUrl","title","style","textAlign","Button","variant","size","onClick","icon","dashboardId","PluginDisabledBadge","error","tooltip","PluginErrorCode","errorCodeToTooltip","Badge","text","color","getBadgeColor","theme","css","colors","background","primary","border","strong","secondary","PluginInstalledBadge","customBadgeStyles","useStyles2","PluginEnterpriseBadge","plugin","featureEnabled","HorizontalGroup","PluginSignatureBadge","status","signature","fill","ev","preventDefault","window","open","id","PluginUpdateAvailableBadge","styles","getStyles","hasUpdate","isCore","type","PluginType","typography","bodySmall","fontSize","PluginLogo","alt","src","height","loading","VersionList","versions","installedVersion","latestCompatibleVersion","getLatestCompatibleVersion","length","table","version","isInstalledVersion","currentVersion","dateTimeFormatTimeAgo","createdAt","container","spacing","h5","fontWeightBold","usePluginConfig","useAsync","async","isInstalled","isDisabled","pluginId","info","getPluginSettings","result","importAppPlugin","importDataSourcePlugin","importPanelPluginFromMeta","meta","Error","loadPlugin","AppConfigCtrlWrapper","PureComponent","constructor","props","super","Promise","resolve","this","model","preUpdateHook","then","updateCmd","extend","enabled","pinned","jsonData","secureJsonData","getBackendSrv","post","postUpdateHook","res","location","callback","deprecationWarning","update","state","angularCtrl","refresh","componentDidMount","setTimeout","setState","componentDidUpdate","prevProps","element","cloneDeep","app","scopeProps","ctrl","isAppConfigCtrl","getAngularLoader","load","render","withRightMargin","marginRight","ref","enable","disable","PluginDashboards","importNext","import","dash","overwrite","datasource","installCmd","path","inputs","push","value","appEvents","AppEvents","delete","uid","get","DashboardsTable","remove","PluginDetailsBody","queryParams","pageId","pluginConfig","PluginTabIds","cx","readme","dangerouslySetInnerHTML","__html","details","angularConfigCtrl","configPages","configPage","body","query","link","PluginDetailsDisabledError","Alert","severity","selectors","renderDescriptionFromError","target","rel","GetStartedWithApp","updatePluginSettingsAndReload","data","updatePluginSettings","reload","e","console","GetStartedWithDataSource","dispatch","useDispatch","onAddDataSource","useCallback","addDataSource","isDataSourceEditor","GetStartedWithPlugin","ExternallyManagedButton","pluginStatus","externalManageLink","getExternalManageLink","PluginStatus","LinkButton","InstallControlsButton","isInstalling","errorInstalling","useInstallStatus","isUninstalling","errorUninstalling","useUninstallStatus","install","useInstall","uninstall","useUninstall","isConfirmModalVisible","setIsConfirmModalVisible","useState","showConfirmModal","hideConfirmModal","uninstallBtnText","onUninstall","onUpdate","ConfirmModal","isOpen","confirmText","onConfirm","onDismiss","disabled","InstallControls","isExternallyManaged","config","hasPermission","isGrafanaAdmin","isRemotePluginsAvailable","useIsRemotePluginsAvailable","isCompatible","Boolean","isInstallControlsDisabled","isInstallControlsEnabled","message","isEnterprise","align","isDev","isPublished","PluginDetailsHeaderDependencies","pluginDependencies","grafanaDependency","dependencyTitle","p","PluginIconName","SIGNATURE_ICONS","PluginSignatureType","DEFAULT","PluginSignatureDetailsBadge","signatureType","signatureOrg","signatureTypeText","capitalize","signatureIcon","DetailsBadge","children","badge","canvas","PluginDetailsHeaderSignature","isSignatureValid","PluginSignatureStatus","PluginDetailsHeader","currentUrl","parentUrl","headerContainer","logos","small","headerWrapper","breadcrumb","textUnderline","headerInformationRow","orgName","links","url","downloads","Intl","NumberFormat","format","headerInformationRowSecondary","description","h2","h4","headerOrgName","PluginDetailsSignature","isDisabledDueTooSignatureError","PluginDetails","match","params","substring","lastIndexOf","defaultTabs","label","PluginTabLabels","useGetSingle","tabs","defaultTab","pathname","useLocation","useMemo","canConfigurePlugins","isOrgAdmin","page","includes","find","include","PluginIncludeType","usePluginDetailsTabs","isLoading","isFetchLoading","useFetchStatus","isFetchDetailsLoading","useFetchDetailsStatus","prevTabs","usePrevious","useEffect","hasUninstalledWithConfigPages","isViewingAConfigPage","locationService","Page","Loader","TabsBar","hideBorder","tab","Tab","active","TabContent","tabContent","alert","Layout","justify","AppNotificationSeverity","selectRoot","plugins","selectItems","createSelector","items","selectDisplayMode","settings","displayMode","selectAll","selectById","pluginsAdapter","findByInstallAndType","filterBy","filterByType","filter","selectInstalled","searchBy","fields","toLowerCase","some","f","findByKeyword","filteredPlugins","searchedPlugins","selectPluginErrors","errorCode","selectRequest","actionType","requests","selectIsRequestPending","request","RequestStatus","selectRequestError","useGetAllWithFilters","sortBy","Sorters","useFetchAll","filtered","useSelector","sortPlugins","useFetchDetails","useGetErrors","isUpdating","fetchRemotePlugins","fetchAll","fetchDetails","isNotFetched","undefined","shouldFetch","useDisplayMode","setDisplayMode","v","useRef","current"],"sourceRoot":""}
|