From 39ac3eeeac51c78bcd7ad289efccd326d081b24f Mon Sep 17 00:00:00 2001 From: Evangelos Skopelitis Date: Thu, 21 Nov 2024 14:36:47 -0500 Subject: [PATCH 1/2] frontend: PluginSettings: Use author for plugin origin This change makes the formatting of the plugin names consistent, using the plugin author for the origin value. When the author is not set, the default origin is "Unknown". Fixes: #2544 Signed-off-by: Evangelos Skopelitis --- e2e-tests/tests/pluginSetting.spec.ts | 2 +- .../App/PluginSettings/PluginSettings.tsx | 23 +++++++++++++++---- frontend/src/plugin/pluginsSlice.ts | 4 ++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/e2e-tests/tests/pluginSetting.spec.ts b/e2e-tests/tests/pluginSetting.spec.ts index 88609b210a..de63755adf 100644 --- a/e2e-tests/tests/pluginSetting.spec.ts +++ b/e2e-tests/tests/pluginSetting.spec.ts @@ -20,7 +20,7 @@ test('plugin settings page should have a table', async ({ page }) => { test('pod counter plugin should have setting option', async ({ page }) => { const headlampPage = new HeadlampPage(page); - const pluginName = '@kinvolk/headlamp-pod-counter'; + const pluginName = 'headlamp-pod-counter'; await headlampPage.authenticate(); await headlampPage.navigateTopage('/settings/plugins', /Plugin/); diff --git a/frontend/src/components/App/PluginSettings/PluginSettings.tsx b/frontend/src/components/App/PluginSettings/PluginSettings.tsx index 3135cb314c..c55060b610 100644 --- a/frontend/src/components/App/PluginSettings/PluginSettings.tsx +++ b/frontend/src/components/App/PluginSettings/PluginSettings.tsx @@ -100,8 +100,23 @@ export function PluginSettingsPure(props: PluginSettingsPureProps) { /** enableSave state enables the save button when changes are made to the plugin list */ const [enableSave, setEnableSave] = useState(false); - /** pluginChanges state is the array of plugin data and any current changes made by the user to a plugin's "Enable" field via toggler */ - const [pluginChanges, setPluginChanges] = useState(() => pluginArr.map((p: any) => p)); + /** + * pluginChanges state is the array of plugin data and any current changes made by the user to a plugin's "Enable" field via toggler. + * The name and origin fields are split for consistency. + */ + const [pluginChanges, setPluginChanges] = useState(() => + pluginArr.map((plugin: PluginInfo) => { + const [author, name] = plugin.name.includes('@') + ? plugin.name.split(/\/(.+)/) + : [null, plugin.name]; + + return { + ...plugin, + displayName: name ?? plugin.name, + origin: plugin.origin ?? author?.substring(1) ?? t('translation|Unknown'), + }; + }) + ); /** * useEffect to control the rendering of the save button. @@ -186,7 +201,7 @@ export function PluginSettingsPure(props: PluginSettingsPureProps) { params={{ name: plugin.name }} align="right" > - {plugin.name} + {plugin.displayName} {plugin.version} @@ -204,7 +219,7 @@ export function PluginSettingsPure(props: PluginSettingsPureProps) { const url = plugin?.homepage || plugin?.repository?.url; return plugin?.origin ? ( url ? ( - {plugin?.origin} + {plugin.origin} ) : ( plugin?.origin ) diff --git a/frontend/src/plugin/pluginsSlice.ts b/frontend/src/plugin/pluginsSlice.ts index 500e5b31ce..37e3277ac0 100644 --- a/frontend/src/plugin/pluginsSlice.ts +++ b/frontend/src/plugin/pluginsSlice.ts @@ -42,6 +42,10 @@ export type PluginInfo = { * @see https://docs.npmjs.com/cli/v9/configuring-npm/package-json?v=true#description */ description: string; + /** + * displayName is the name of the plugin without the author prefix. + */ + displayName?: string; /** * origin is the source of the plugin. */ From 97131b9c54a88413ba338d24e3feee84a0e5b4ba Mon Sep 17 00:00:00 2001 From: Evangelos Skopelitis Date: Thu, 21 Nov 2024 14:38:01 -0500 Subject: [PATCH 2/2] frontend: Add subtitle for plugin origin in details Signed-off-by: Evangelos Skopelitis --- .../PluginSettings/PluginSettingsDetails.tsx | 10 +- ...ttings.DefaultSaveEnable.stories.storyshot | 37 +++++- .../PluginSettings.Empty.stories.storyshot | 2 +- ...tings.EmptyHomepageItems.stories.storyshot | 37 +++++- .../PluginSettings.FewItems.stories.storyshot | 37 +++++- ...PluginSettings.ManyItems.stories.storyshot | 107 +++++++++++++++--- ...PluginSettings.MoreItems.stories.storyshot | 107 +++++++++++++++--- ...ingsDetails.WithAutoSave.stories.storyshot | 2 +- ...sDetails.WithoutAutoSave.stories.storyshot | 2 +- .../Settings.General.stories.storyshot | 2 +- .../Overview.Events.stories.storyshot | 4 +- .../MainInfoSection.Normal.stories.storyshot | 2 +- ...InfoSection.NullBacklink.stories.storyshot | 2 +- ...ListView.OneHiddenColumn.stories.storyshot | 2 +- frontend/src/components/common/SectionBox.tsx | 6 +- .../src/components/common/SectionHeader.tsx | 30 +++-- .../Table.LabelSearch.stories.storyshot | 2 +- .../Table.NameSearch.stories.storyshot | 2 +- .../Table.NamespaceSearch.stories.storyshot | 2 +- .../Table.NamespaceSelect.stories.storyshot | 2 +- .../Table.NotFoundMessage.stories.storyshot | 2 +- .../Table.NumberSearch.stories.storyshot | 2 +- .../Table.UIDSearch.stories.storyshot | 2 +- .../SectionBox.HeaderProps.stories.storyshot | 2 +- .../SectionBox.Titled.stories.storyshot | 2 +- ...ectionBox.TitledChildren.stories.storyshot | 2 +- .../SectionHeader.Actions.stories.storyshot | 2 +- .../SectionHeader.Main.stories.storyshot | 2 +- .../SectionHeader.Normal.stories.storyshot | 2 +- ...onHeader.NormalNoPadding.stories.storyshot | 2 +- ...SectionHeader.Subsection.stories.storyshot | 2 +- .../SimpleTable.LabelSearch.stories.storyshot | 2 +- .../SimpleTable.NameSearch.stories.storyshot | 2 +- ...pleTable.NamespaceSearch.stories.storyshot | 2 +- ...pleTable.NamespaceSelect.stories.storyshot | 2 +- ...pleTable.NotFoundMessage.stories.storyshot | 2 +- ...SimpleTable.NumberSearch.stories.storyshot | 2 +- .../SimpleTable.UIDSearch.stories.storyshot | 2 +- .../Details.Empty.stories.storyshot | 6 +- .../Details.WithBase.stories.storyshot | 6 +- .../List.Items.stories.storyshot | 2 +- ...sourceDefinition.Details.stories.storyshot | 12 +- ...mResourceDefinition.List.stories.storyshot | 2 +- ...mResourceDetails.NoError.stories.storyshot | 4 +- .../CustomResourceList.List.stories.storyshot | 2 +- .../CronJobDetails.EveryAst.stories.storyshot | 6 +- ...onJobDetails.EveryMinute.stories.storyshot | 6 +- .../List.DaemonSets.stories.storyshot | 2 +- .../EndpointDetails.Default.stories.storyshot | 10 +- .../EndpointDetails.Error.stories.storyshot | 2 +- .../EndpointList.Items.stories.storyshot | 2 +- .../HPADetails.Default.stories.storyshot | 6 +- .../HPAList.Items.stories.storyshot | 2 +- .../ClassDetails.Basic.stories.storyshot | 4 +- ...ClassDetails.WithDefault.stories.storyshot | 4 +- .../ClassList.Items.stories.storyshot | 2 +- .../Details.WithResource.stories.storyshot | 6 +- .../Details.WithTLS.stories.storyshot | 6 +- .../Details.WithWildcardTLS.stories.storyshot | 4 +- .../List.Items.stories.storyshot | 2 +- .../JobList.Items.stories.storyshot | 2 +- .../Details.LeaseDetail.stories.storyshot | 4 +- .../List.Items.stories.storyshot | 2 +- ...Details.LimitRangeDetail.stories.storyshot | 4 +- .../List.Items.stories.storyshot | 2 +- .../NamespaceDetails.Active.stories.storyshot | 10 +- .../NamespaceList.Regular.stories.storyshot | 2 +- .../List.Nodes.stories.storyshot | 2 +- .../PodDetails.Error.stories.storyshot | 10 +- .../PodDetails.Initializing.stories.storyshot | 12 +- ...odDetails.LivenessFailed.stories.storyshot | 10 +- .../PodDetails.PullBackOff.stories.storyshot | 10 +- .../PodDetails.Running.stories.storyshot | 10 +- .../PodDetails.Successful.stories.storyshot | 10 +- .../PodList.Items.stories.storyshot | 2 +- ...tailsVolumeSection.Empty.stories.storyshot | 2 +- ...tailsVolumeSection.Short.stories.storyshot | 2 +- ...VolumeSection.Successful.stories.storyshot | 2 +- .../pdbDetails.Default.stories.storyshot | 4 +- .../pdbList.Items.stories.storyshot | 2 +- ...rityClassDetails.Default.stories.storyshot | 4 +- .../priorityClassList.Items.stories.storyshot | 2 +- .../List.ReplicaSets.stories.storyshot | 2 +- ...urceQuotaDetails.Default.stories.storyshot | 4 +- .../resourceQuotaList.Items.stories.storyshot | 2 +- .../Details.Base.stories.storyshot | 4 +- .../List.Items.stories.storyshot | 2 +- .../Details.Empty.stories.storyshot | 6 +- .../Details.WithBase.stories.storyshot | 6 +- .../List.Items.stories.storyshot | 2 +- .../ClaimDetails.Base.stories.storyshot | 4 +- .../ClaimList.Items.stories.storyshot | 2 +- .../ClassDetails.Base.stories.storyshot | 4 +- .../ClassList.Items.stories.storyshot | 2 +- .../VolumeDetails.Base.stories.storyshot | 4 +- .../VolumeList.Items.stories.storyshot | 2 +- .../VPADetails.Default.stories.storyshot | 10 +- .../VPAList.List.stories.storyshot | 2 +- ...onfigDetails.WithService.stories.storyshot | 6 +- ...ookConfigDetails.WithURL.stories.storyshot | 6 +- ...gWebhookConfigList.Items.stories.storyshot | 2 +- ...onfigDetails.WithService.stories.storyshot | 6 +- ...ookConfigDetails.WithURL.stories.storyshot | 6 +- ...gWebhookConfigList.Items.stories.storyshot | 2 +- frontend/src/i18n/locales/de/translation.json | 3 +- frontend/src/i18n/locales/en/translation.json | 3 +- frontend/src/i18n/locales/es/translation.json | 3 +- frontend/src/i18n/locales/fr/translation.json | 3 +- frontend/src/i18n/locales/pt/translation.json | 3 +- 109 files changed, 496 insertions(+), 246 deletions(-) diff --git a/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx index 3b78df9fc8..776f916498 100644 --- a/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx +++ b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx @@ -107,6 +107,9 @@ export function PluginSettingsDetailsPure(props: PluginSettingsDetailsPureProps) const [enableSaveButton, setEnableSaveButton] = useState(false); const [openDeleteDialog, setOpenDeleteDialog] = useState(false); const history = useHistory(); + const [author, name] = plugin.name.includes('@') + ? plugin.name.substring(1).split(/\/(.+)/) + : [null, plugin.name]; useEffect(() => { if (!_.isEqual(config, data)) { @@ -156,7 +159,12 @@ export function PluginSettingsDetailsPure(props: PluginSettingsDetailsPureProps) return ( <> - + {plugin.description}

- Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown +

- Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown +

- Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown +

- Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown +

- Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown + - Unknown + + Unknown +

{ title?: React.ReactNode; + subtitle?: React.ReactNode; headerProps?: Omit; outterBoxProps?: Omit; //** The location to go back to. If provided as an empty string, the browser's history will be used. If not provided (default)), then no back button is used. */ @@ -14,6 +15,7 @@ export interface SectionBoxProps extends Omit { export function SectionBox(props: SectionBoxProps) { const { title, + subtitle, children, headerProps = { noPadding: false, headerStyle: 'subsection' }, outterBoxProps = {}, @@ -26,7 +28,9 @@ export function SectionBox(props: SectionBoxProps) { const actualBackLink = typeof backLink === 'boolean' ? (!!backLink ? '' : undefined) : backLink; if (typeof title === 'string') { - titleElem = ; + titleElem = ( + + ); } else { titleElem = title; } diff --git a/frontend/src/components/common/SectionHeader.tsx b/frontend/src/components/common/SectionHeader.tsx index 4f450c9bdd..1cd0a03506 100644 --- a/frontend/src/components/common/SectionHeader.tsx +++ b/frontend/src/components/common/SectionHeader.tsx @@ -8,6 +8,7 @@ export type HeaderStyle = 'main' | 'subsection' | 'normal' | 'label'; export interface SectionHeaderProps { title: string; + subtitle?: string | React.ReactNode; actions?: React.ReactNode[] | null; noPadding?: boolean; headerStyle?: HeaderStyle; @@ -38,18 +39,25 @@ export default function SectionHeader(props: SectionHeaderProps) { > {(!!props.title || titleSideActions.length > 0) && ( - + {!!props.title && ( - ({ - ...theme.palette.headerStyle[headerStyle || 'normal'], - whiteSpace: 'pre-wrap', - })} - > - {props.title} - + <> + ({ + ...theme.palette.headerStyle[headerStyle || 'normal'], + whiteSpace: 'pre-wrap', + })} + > + {props.title} + + {!!props.subtitle && ( + + {props.subtitle} + + )} + )} {!!titleSideActions && ( diff --git a/frontend/src/components/common/Table/__snapshots__/Table.LabelSearch.stories.storyshot b/frontend/src/components/common/Table/__snapshots__/Table.LabelSearch.stories.storyshot index 6796020c1b..c46fb4a72b 100644 --- a/frontend/src/components/common/Table/__snapshots__/Table.LabelSearch.stories.storyshot +++ b/frontend/src/components/common/Table/__snapshots__/Table.LabelSearch.stories.storyshot @@ -7,7 +7,7 @@ class="MuiGrid-root MuiGrid-item css-13i4rnv-MuiGrid-root" >