Skip to content

Commit

Permalink
PR change requests
Browse files Browse the repository at this point in the history
  • Loading branch information
mgunnerud committed Dec 18, 2024
1 parent 87ba20a commit efbdf77
Show file tree
Hide file tree
Showing 22 changed files with 350 additions and 269 deletions.
2 changes: 1 addition & 1 deletion frontend/packages/policy-editor/src/PolicyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
PolicySubject,
RequiredAuthLevel,
PolicyEditorUsage,
PolicyAccessPackageAreaGroup,
} from './types';
import {
mapPolicyRulesBackendObjectToPolicyRuleCard,
Expand All @@ -21,6 +20,7 @@ import { useTranslation } from 'react-i18next';
import { SecurityLevelSelect } from './components/SecurityLevelSelect';
import { PolicyEditorContextProvider } from './contexts/PolicyEditorContext';
import { PolicyCardRules } from './components/PolicyCardRules';
import type { PolicyAccessPackageAreaGroup } from 'app-shared/types/PolicyAccessPackages';

export type PolicyEditorProps = {
policy: Policy;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { type ReactElement } from 'react';
import { PolicyAccessPackageAccordion } from './PolicyAccessPackageAccordion';
import { PolicyAccordion } from './PolicyAccordion';
import { isAccessPackageSelected } from './policyAccessPackageUtils';
import type { PolicyAccessPackageArea } from 'app-shared/types/PolicyAccessPackages';

type AllAccessPackagesProps = {
chosenAccessPackages: string[];
accessPackagesToRender: PolicyAccessPackageArea[];
searchValue: string;
handleSelectAccessPackage: (accessPackageUrn: string) => void;
};
export const AllAccessPackages = ({
chosenAccessPackages,
accessPackagesToRender,
searchValue,
handleSelectAccessPackage,
}: AllAccessPackagesProps): ReactElement[] => {
return accessPackagesToRender.map((area) => (
<PolicyAccordion
key={`${searchValue}-${area.id}`}
icon={area.icon || 'PackageIcon'}
title={area.name}
subTitle={area.description}
defaultOpen={!!searchValue}
>
{area.packages.map((accessPackage) => (
<PolicyAccessPackageAccordion
key={accessPackage.urn}
accessPackage={accessPackage}
isChecked={isAccessPackageSelected(accessPackage.urn, chosenAccessPackages)}
handleSelectChange={handleSelectAccessPackage}
/>
))}
</PolicyAccordion>
));
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { type ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { StudioLabelAsParagraph } from '@studio/components';
import { PolicyAccessPackageAccordion } from './PolicyAccessPackageAccordion';
import { filterAccessPackagesById, flatMapAreaPackageList } from './policyAccessPackageUtils';
import type {
PolicyAccessPackage,
PolicyAccessPackageArea,
} from 'app-shared/types/PolicyAccessPackages';

type ChosenAccessPackagesProps = {
chosenAccessPackages: string[];
groupedAccessPackagesByArea: PolicyAccessPackageArea[];
handleSelectAccessPackage: (accessPackageUrn: string) => void;
};
export const ChosenAccessPackages = ({
chosenAccessPackages,
groupedAccessPackagesByArea,
handleSelectAccessPackage,
}: ChosenAccessPackagesProps): ReactElement => {
const { t } = useTranslation();

const flatMappedAreaList: PolicyAccessPackage[] = flatMapAreaPackageList(
groupedAccessPackagesByArea,
);
const selectedAccessPackageList: PolicyAccessPackage[] = filterAccessPackagesById(
flatMappedAreaList,
chosenAccessPackages,
);

if (chosenAccessPackages.length > 0) {
return (
<>
<StudioLabelAsParagraph size='xs' spacing>
{t('policy_editor.access_package_chosen_packages')}
</StudioLabelAsParagraph>
{selectedAccessPackageList.map((accessPackage: PolicyAccessPackage) => {
return (
<PolicyAccessPackageAccordion
key={accessPackage.urn}
accessPackage={accessPackage}
isChecked={true}
handleSelectChange={handleSelectAccessPackage}
/>
);
})}
</>
);
}
return null;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
:root {
--logo-size: 20px;
--logo-size: var(--fds-sizing-5);
}

.accessPackageAccordion {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,8 @@ const renderPolicyAccessPackageAccordion = (queries: Partial<ServicesContextProp
<PolicyAccessPackageAccordion
accessPackage={defaultAccessPackageProp}
isChecked={false}
handleSelectChange={() => {
/** */
}}
handleSelectChange={jest.fn()}
/>
,
</ServicesContextProvider>,
);
};
Original file line number Diff line number Diff line change
@@ -1,136 +1,36 @@
import React, { type ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import classes from './PolicyAccessPackageAccordion.module.css';
import type { AccessPackageResource, PolicyAccessPackage } from '@altinn/policy-editor';
import { PolicyAccordion } from '../PolicyAccordion';
import { useResourceAccessPackageServicesQuery } from 'app-shared/hooks/queries/useResourceAccessPackageServicesQuery';
import { StudioCheckbox, StudioParagraph, StudioSpinner } from '@studio/components';
import { PolicyAccessPackageAccordionContent } from './PolicyAccessPackageAccordionContent';
import { PolicyAccessPackageAccordionCheckBox } from './PolicyAccessPackageAccordionCheckbox';
import type { PolicyAccessPackage } from 'app-shared/types/PolicyAccessPackages';

const selectedLanguage = 'nb';

interface PolicyAccessPackageAccordionProps {
type PolicyAccessPackageAccordionProps = {
accessPackage: PolicyAccessPackage;
isChecked: boolean;
handleSelectChange: (accessPackageUrn: string) => void;
}
};

export const PolicyAccessPackageAccordion = ({
accessPackage,
isChecked,
handleSelectChange,
}: PolicyAccessPackageAccordionProps): React.ReactElement => {
}: PolicyAccessPackageAccordionProps): ReactElement => {
return (
<div className={classes.accessPackageAccordion}>
<PolicyAccordion
title={accessPackage.name}
subTitle={accessPackage.description}
extraHeaderContent={
<PolicyAccordionCheckBox
<PolicyAccessPackageAccordionCheckBox
isChecked={isChecked}
handleSelectChange={handleSelectChange}
accessPackage={accessPackage}
/>
}
>
<AccordionContent accessPackageUrn={accessPackage.urn} />
<PolicyAccessPackageAccordionContent accessPackageUrn={accessPackage.urn} />
</PolicyAccordion>
</div>
);
};

type AccordionContentProps = { accessPackageUrn: string };
const AccordionContent = ({ accessPackageUrn }: AccordionContentProps): ReactElement => {
const { t } = useTranslation();
// Determine enviroment to load resources/apps connected to each access packages from. Option to override this
// value with a localStorage setting is for testing. Valid options are 'at22', 'at23', 'at24', 'tt02'
const accessPackageResourcesEnv = localStorage.getItem('accessPackageResourcesEnv') || 'prod';

const { data: services, isLoading } = useResourceAccessPackageServicesQuery(
accessPackageUrn,
accessPackageResourcesEnv,
);

const hasServices: boolean = services?.length > 0;
const serviceListIsEmpty: boolean = services?.length === 0;
return (
<>
{isLoading && (
<StudioSpinner spinnerTitle={t('policy_editor.access_package_loading_services')} />
)}
{hasServices && <Services services={services} />}
{serviceListIsEmpty && (
<StudioParagraph size='xs'>{t('policy_editor.access_package_no_services')}</StudioParagraph>
)}
</>
);
};

type ServicesProps = {
services: AccessPackageResource[];
};
const Services = ({ services }: ServicesProps): ReactElement => {
const { t } = useTranslation();

return (
<>
<StudioParagraph className={classes.serviceContainerHeader}>
{t('policy_editor.access_package_services')}
</StudioParagraph>
{services.map((resource) => (
<div key={resource.identifier} className={classes.serviceContainer}>
<ResourceImage resource={resource} />
<div className={classes.serviceLabel}>{resource.title[selectedLanguage]}</div>
<div>{resource.hasCompetentAuthority.name[selectedLanguage]}</div>
</div>
))}
</>
);
};

type ResourceImageProps = {
resource: AccessPackageResource;
};
const ResourceImage = ({ resource }: ResourceImageProps): ReactElement => {
if (resource.logoUrl) {
return (
<img
className={classes.logo}
src={resource.logoUrl}
alt={resource.hasCompetentAuthority.name[selectedLanguage]}
title={resource.hasCompetentAuthority.name[selectedLanguage]}
/>
);
}
return <div className={classes.emptyLogo} />;
};

type PolicyAccordionCheckBoxProps = Pick<
PolicyAccessPackageAccordionProps,
'accessPackage' | 'isChecked' | 'handleSelectChange'
>;
const PolicyAccordionCheckBox = ({
accessPackage,
isChecked,
handleSelectChange,
}: PolicyAccordionCheckBoxProps): ReactElement => {
const { t } = useTranslation();
const CHECKED_VALUE = 'on';

const checkboxLabel = t(
isChecked ? 'policy_editor.access_package_remove' : 'policy_editor.access_package_add',
{
packageName: accessPackage.name,
},
);

return (
<StudioCheckbox.Group
legend=''
className={classes.accordionCheckbox}
value={isChecked ? [CHECKED_VALUE] : []}
onChange={() => handleSelectChange(accessPackage.urn)}
>
<StudioCheckbox value={CHECKED_VALUE} aria-label={checkboxLabel} />
</StudioCheckbox.Group>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { type ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import classes from './PolicyAccessPackageAccordion.module.css';
import { StudioCheckbox } from '@studio/components';
import type { PolicyAccessPackage } from 'app-shared/types/PolicyAccessPackages';

type PolicyAccessPackageAccordionCheckBoxProps = {
accessPackage: PolicyAccessPackage;
isChecked: boolean;
handleSelectChange: (accessPackageUrn: string) => void;
};
export const PolicyAccessPackageAccordionCheckBox = ({
accessPackage,
isChecked,
handleSelectChange,
}: PolicyAccessPackageAccordionCheckBoxProps): ReactElement => {
const { t } = useTranslation();
const CHECKED_VALUE = 'on';

const checkboxLabel = t(
isChecked ? 'policy_editor.access_package_remove' : 'policy_editor.access_package_add',
{
packageName: accessPackage.name,
},
);

return (
<StudioCheckbox.Group
legend=''
className={classes.accordionCheckbox}
value={isChecked ? [CHECKED_VALUE] : []}
onChange={() => handleSelectChange(accessPackage.urn)}
>
<StudioCheckbox value={CHECKED_VALUE} aria-label={checkboxLabel} />
</StudioCheckbox.Group>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { type ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { useResourceAccessPackageServicesQuery } from 'app-shared/hooks/queries/useResourceAccessPackageServicesQuery';
import { StudioParagraph, StudioSpinner } from '@studio/components';
import { PolicyAccessPackageServices } from './PolicyAccessPackageServices';

type PolicyAccessPackageAccordionContentProps = { accessPackageUrn: string };
export const PolicyAccessPackageAccordionContent = ({
accessPackageUrn,
}: PolicyAccessPackageAccordionContentProps): ReactElement => {
const { t } = useTranslation();
// Determine enviroment to load resources/apps connected to each access packages from. Option to override this
// value with a localStorage setting is for testing. Valid options are 'at22', 'at23', 'at24', 'tt02'
const accessPackageResourcesEnv = localStorage.getItem('accessPackageResourcesEnv') || 'prod';

const { data: services, isLoading } = useResourceAccessPackageServicesQuery(
accessPackageUrn,
accessPackageResourcesEnv,
);

const hasServices: boolean = services?.length > 0;
const serviceListIsEmpty: boolean = services?.length === 0;
return (
<>
{isLoading && (
<StudioSpinner spinnerTitle={t('policy_editor.access_package_loading_services')} />
)}
{hasServices && <PolicyAccessPackageServices services={services} />}
{serviceListIsEmpty && (
<StudioParagraph size='xs'>{t('policy_editor.access_package_no_services')}</StudioParagraph>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { type ReactElement } from 'react';
import classes from './PolicyAccessPackageAccordion.module.css';
import type { AccessPackageResource } from 'app-shared/types/PolicyAccessPackages';

type PolicyAccessPackageServiceLogoProps = {
resource: AccessPackageResource;
selectedLanguage: string;
};
export const PolicyAccessPackageServiceLogo = ({
resource,
selectedLanguage,
}: PolicyAccessPackageServiceLogoProps): ReactElement => {
if (resource.logoUrl) {
return (
<img
className={classes.logo}
src={resource.logoUrl}
alt={resource.hasCompetentAuthority.name[selectedLanguage]}
title={resource.hasCompetentAuthority.name[selectedLanguage]}
/>
);
}
return <div className={classes.emptyLogo} />;
};
Loading

0 comments on commit efbdf77

Please sign in to comment.