1
0
Fork 0
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:
itsconquest 2022-02-25 12:22:56 +13:00 committed by GitHub
parent ff7847aaa5
commit a894e3182a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 4773 additions and 5783 deletions

View 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>
);
}

View 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} />);
}

View 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>
);
}

View 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;
}

View file

@ -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);
}
}