Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/homepage/.changeset/nasty-goats-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-dynamic-home-page': patch
---

Fix issue that defaul widget props are ignored when customization is enabled.
5 changes: 5 additions & 0 deletions workspaces/homepage/.changeset/thirty-spies-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-homepage-backend': patch
---

Fix conditional permission checks.
3 changes: 2 additions & 1 deletion workspaces/homepage/app-config-admin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ permission:
users:
- name: user:default/admin-user
superUsers:
- name: user:default/admin-user
[]
# - name: user:default/admin-user
3 changes: 2 additions & 1 deletion workspaces/homepage/app-config-developer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ permission:
users:
- name: user:default/developer-user
superUsers:
- name: user:default/developer-user
[]
# - name: user:default/developer-user
96 changes: 91 additions & 5 deletions workspaces/homepage/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,85 @@ homepage:
# For 1.x this references a mount point (`config.id`).
# For 2.x this references a homepage widget extension (name).
defaultWidgets:
- id: test-no-if
ref: headline
props:
title: 'This widget has no "if" condition and should always render'
layout:
xl: { w: 12, h: 1 }

- id: test-if-user
ref: headline
if:
users: [user:development/guest]
props:
title: 'This widget has an "if" condition that allows only the guest user to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-another-user
ref: headline
if:
users: [user:development/another-user]
props:
title: 'This widget has an "if" condition that allows only another user to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-group
ref: headline
if:
groups: [group:development/guests]
props:
title: 'This widget has an "if" condition that allows only the guests group to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-another-group
ref: headline
if:
groups: [group:development/another-group]
props:
title: 'This widget has an "if" condition that allows only another group to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-user-can-read-catalog-entities
ref: headline
if:
permissions: [catalog.entity.read]
props:
title: 'This widget has an "if" condition that allows only users with catalog read permissions to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-user-can-create-catalog-entities
ref: headline
if:
permissions: [catalog.entity.create]
props:
title: 'This widget has an "if" condition that allows only users with catalog create permissions to see it'
layout:
xl: { w: 12, h: 1 }

- id: test-if-user-can-read-this-widget
ref: headline
if:
permissions: [homepage.default-widgets.read, catalog.entity.read]
props:
title: 'This widget has an "if" condition that allows only users with access to read default widgets to see it (id: test-if-user-can-read-this-widget)'
layout:
xl: { w: 12, h: 1 }

- id: test-if-user-can-read-another-widget
ref: headline
if:
permissions: [homepage.default-widgets.read]
props:
title: 'This widget has an "if" condition that allows only users with access to read default widgets to see it (id: test-if-user-can-read-another-widget)'
layout:
xl: { w: 12, h: 1 }

- id: onboarding
ref: 'rhdh-onboarding-section'
layout:
Expand Down Expand Up @@ -230,9 +309,7 @@ auth:
# see https://backstage.io/docs/auth/ to learn about auth providers
providers:
# See https://backstage.io/docs/auth/guest/provider
guest:
userEntityRef: user:default/guest-user
ownershipEntityRefs: []
guest: {}

scaffolder:
# see https://backstage.io/docs/features/software-templates/configuration for software template options
Expand Down Expand Up @@ -279,6 +356,15 @@ permission:
- homepage
admin:
users:
- name: user:default/guest-user
- name: user:development/guest

# if you make the guest user super admin here you might see "unexpected" default widgets
# on the homepage, as some widgets are only visible to users with access to read default widgets,
# which the guest user has then by default.
# You can either remove the guest user from the admin users or configure the superUsers instead.
superUsers:
- name: user:default/guest-user
[]
# - name: user:development/guest
policyFileReload: true
policies-csv-file: ../../rbac-policy.csv
conditionalPoliciesFile: ../../conditional-policies.yaml
13 changes: 13 additions & 0 deletions workspaces/homepage/conditional-policies.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
result: CONDITIONAL
roleEntityRef: role:default/test-if-user-can-read-this-widget
pluginId: homepage
resourceType: homepage-default-widget
permissionMapping:
- read
conditions:
rule: HAS_WIDGET_ID
resourceType: homepage-default-widget
params:
widgetIds:
- test-if-user-can-read-this-widget
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ test.describe.serial('Dynamic Home Page Customization', () => {
sharedPage.getByText(/Good (morning|afternoon|evening)/),
).toBeVisible();

await homePageCustomization.addWidget('Access');
await homePageCustomization.addWidget('Quick Access Card');
await expect(sharedPage.getByText('Quick Access')).toBeVisible();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export class HomePageCustomization {

// Locators
private readonly editButton = () => this.page.getByText('Edit');
private readonly saveButton = () => this.page.getByText('Save');
private readonly saveButton = () =>
this.page.getByText('Save', { exact: true });
private readonly clearAllButton = () => this.page.getByText('Clear all');
private readonly restoreDefaultsButton = () =>
this.page.getByText('Restore defaults');
Expand Down
14 changes: 11 additions & 3 deletions workspaces/homepage/packages/app-legacy/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { searchPage } from './components/search/SearchPage';
import { Root } from './components/Root';
import { DebugHomepageAvailableWidgets } from './components/homepage/DebugHomepageAvailableWidgets';
import { DebugHomepageDefaultWidgets } from './components/homepage/DebugHomepageDefaultWidgets';
import { DebugHomepageSavedWidgets } from './components/homepage/DebugHomepageSavedWidgets';

import {
AlertDisplay,
Expand Down Expand Up @@ -170,9 +171,9 @@ const createHeadline = ({
priority,
}: {
id: string;
title: string;
align: string;
priority: number;
title?: string;
align?: string;
priority?: number;
}): HomePageCardMountPoint => ({
Component: Headline,
config: {
Expand Down Expand Up @@ -243,6 +244,9 @@ const cardMountPoints: HomePageCardMountPoint[] = [
},
},
// Add extra mount points to verify same components can mount multiple times
createHeadline({
id: 'headline',
}),
createHeadline({
id: 'headline-left',
title: 'Left title',
Expand Down Expand Up @@ -454,6 +458,10 @@ const routes = (
path="/debug-default-widgets"
element={<DebugHomepageDefaultWidgets />}
/>
<Route
path="/debug-saved-widgets"
element={<DebugHomepageSavedWidgets />}
/>
</FlatRoutes>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
to="debug-default-widgets"
text="Default Widgets"
/>
<SidebarItem
icon={HomeIcon}
to="debug-saved-widgets"
text="Saved Widgets"
/>
<SidebarDivider />
<SidebarItem icon={CatalogIcon} to="catalog" text="Catalog" />
<SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CodeSnippet, Content, Header, Page } from '@backstage/core-components';

import { stringify } from 'yaml';

export const DebugHomepageSavedWidgets = () => {
const savedWidgetString = localStorage.getItem('/home.customHomepage/home');
const savedWidgets = savedWidgetString
? JSON.parse(JSON.parse(savedWidgetString))
: [];

return (
<Page themeId="home">
<Header
title="Homepage Saved Widgets (local storage)"
subtitle="List of all saved widgets for the Customizable page"
/>
<Content>
<CodeSnippet
language="yaml"
text={stringify(savedWidgets)}
showCopyCodeButton
/>
</Content>
</Page>
);
};
Loading
Loading