mirror of
https://github.com/portainer/portainer.git
synced 2025-08-08 23:35:31 +02:00
refactor(azure/aci): migrate dashboard view to react [EE-2189] (#6518)
* refactor(azure/aci): migrate dashboard view to react [EE-2189] * move aggregate function to azure utils file * fix type * introduce dashboard item component * add error notificatons * hide resource groups widget if failed to load * make dashboard a default export * revert mistake * refactor based on suggestions * use object for error data instead of array * return unused utils file * move length calculations out of return statement * only return first error of resource groups queries * refactor imports/exports, fix bug with errors & add test * WIP dashboard tests * allow mocking multiple resource groups * test for total number of resource groups * update lock file to fix lint action issue * finish dashboard tests * dashboarditem story * fix(auth): remove caching of user * add option for link to dashboard item * rename dashboard test case to match file * remove optional link and update storybook * create aria label based on already provided text * change param name to be clearer
This commit is contained in:
parent
ff7847aaa5
commit
a894e3182a
14 changed files with 4773 additions and 5783 deletions
36
app/portainer/components/Dashboard/DashboardItem.stories.tsx
Normal file
36
app/portainer/components/Dashboard/DashboardItem.stories.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { Meta, Story } from '@storybook/react';
|
||||
|
||||
import { Link } from '@/portainer/components/Link';
|
||||
|
||||
import { DashboardItem } from './DashboardItem';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'Components/DashboardItem',
|
||||
component: DashboardItem,
|
||||
};
|
||||
export default meta;
|
||||
|
||||
interface StoryProps {
|
||||
value: number;
|
||||
icon: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
function Template({ value, icon, type }: StoryProps) {
|
||||
return <DashboardItem value={value} icon={icon} type={type} />;
|
||||
}
|
||||
|
||||
export const Primary: Story<StoryProps> = Template.bind({});
|
||||
Primary.args = {
|
||||
value: 1,
|
||||
icon: 'fa fa-th-list',
|
||||
type: 'Example resource',
|
||||
};
|
||||
|
||||
export function WithLink() {
|
||||
return (
|
||||
<Link to="example.page">
|
||||
<DashboardItem value={1} icon="fa fa-th-list" type="Example resource" />
|
||||
</Link>
|
||||
);
|
||||
}
|
35
app/portainer/components/Dashboard/DashboardItem.test.tsx
Normal file
35
app/portainer/components/Dashboard/DashboardItem.test.tsx
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { render } from '@/react-tools/test-utils';
|
||||
|
||||
import { DashboardItem } from './DashboardItem';
|
||||
|
||||
test('should show provided resource value', async () => {
|
||||
const { getByLabelText } = renderComponent(1);
|
||||
const value = getByLabelText('value');
|
||||
|
||||
expect(value).toBeVisible();
|
||||
expect(value).toHaveTextContent('1');
|
||||
});
|
||||
|
||||
test('should show provided icon', async () => {
|
||||
const { getByLabelText } = renderComponent(0, 'fa fa-th-list');
|
||||
const icon = getByLabelText('icon');
|
||||
expect(icon).toHaveClass('fa-th-list');
|
||||
});
|
||||
|
||||
test('should show provided resource type', async () => {
|
||||
const { getByLabelText } = renderComponent(0, '', 'Test');
|
||||
const title = getByLabelText('resourceType');
|
||||
|
||||
expect(title).toBeVisible();
|
||||
expect(title).toHaveTextContent('Test');
|
||||
});
|
||||
|
||||
test('should have accessibility label created from the provided resource type', async () => {
|
||||
const { getByLabelText } = renderComponent(0, '', 'testLabel');
|
||||
|
||||
expect(getByLabelText('testLabel')).toBeTruthy();
|
||||
});
|
||||
|
||||
function renderComponent(value = 0, icon = '', type = '') {
|
||||
return render(<DashboardItem value={value} icon={icon} type={type} />);
|
||||
}
|
27
app/portainer/components/Dashboard/DashboardItem.tsx
Normal file
27
app/portainer/components/Dashboard/DashboardItem.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Widget, WidgetBody } from '@/portainer/components/widget';
|
||||
|
||||
interface Props {
|
||||
value: number;
|
||||
icon: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export function DashboardItem({ value, icon, type }: Props) {
|
||||
return (
|
||||
<div className="col-sm-12 col-md-6" aria-label={type}>
|
||||
<Widget>
|
||||
<WidgetBody>
|
||||
<div className="widget-icon blue pull-left">
|
||||
<i className={icon} aria-hidden="true" aria-label="icon" />
|
||||
</div>
|
||||
<div className="title" aria-label="value">
|
||||
{value}
|
||||
</div>
|
||||
<div className="comment" aria-label="resourceType">
|
||||
{type}
|
||||
</div>
|
||||
</WidgetBody>
|
||||
</Widget>
|
||||
</div>
|
||||
);
|
||||
}
|
13
app/portainer/hooks/useEnvironmentId.ts
Normal file
13
app/portainer/hooks/useEnvironmentId.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { useCurrentStateAndParams } from '@uirouter/react';
|
||||
|
||||
export function useEnvironmentId() {
|
||||
const {
|
||||
params: { endpointId: environmentId },
|
||||
} = useCurrentStateAndParams();
|
||||
|
||||
if (!environmentId) {
|
||||
throw new Error('endpointId url param is required');
|
||||
}
|
||||
|
||||
return environmentId;
|
||||
}
|
|
@ -19,8 +19,6 @@ interface State {
|
|||
user?: UserViewModel | null;
|
||||
}
|
||||
|
||||
const state: State = {};
|
||||
|
||||
export const UserContext = createContext<State | null>(null);
|
||||
|
||||
export function useUser() {
|
||||
|
@ -93,9 +91,7 @@ export function UserProvider({ children }: UserProviderProps) {
|
|||
const [user, setUser] = useState<UserViewModel | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.user) {
|
||||
setUser(state.user);
|
||||
} else if (jwt !== '') {
|
||||
if (jwt !== '') {
|
||||
const tokenPayload = jwtDecode(jwt) as { id: number };
|
||||
|
||||
loadUser(tokenPayload.id);
|
||||
|
@ -120,7 +116,6 @@ export function UserProvider({ children }: UserProviderProps) {
|
|||
|
||||
async function loadUser(id: number) {
|
||||
const user = await getUser(id);
|
||||
state.user = user;
|
||||
setUser(user);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue