Skip to content
Merged
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
33 changes: 33 additions & 0 deletions src/common/api/profiles.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
PREFERRED_PROFILE_SETTINGS_PATH,
PROFILE_API_ENDPOINT,
PROFILE_METADATA_API_ENDPOINT,
PROFILE_PREFERRED_API_ENDPOINT,
Expand Down Expand Up @@ -99,3 +100,35 @@ export const saveProfileSettings = (
},
});
};

export const fetchPreferredProfileSettings = (profileId: string | number) =>
baseApi.getJson({
url: `${PROFILE_API_ENDPOINT}/${profileId}/${PREFERRED_PROFILE_SETTINGS_PATH}`,
}) as Promise<ProfileSettingsMetaList>;

export const savePreferredProfileSettings = (profileId: string | number, profileSettingsId: number) => {
const url = `${PROFILE_API_ENDPOINT}/${profileId}/${PREFERRED_PROFILE_SETTINGS_PATH}`;
const body = JSON.stringify({ profileSettingsId });

return baseApi.request({
url,
requestParams: {
method: 'POST',
body,
headers: {
'content-type': 'application/json',
},
},
});
};

export const deletePreferredProfileSettings = (profileId: string | number) => {
const url = `${PROFILE_API_ENDPOINT}/${profileId}/${PREFERRED_PROFILE_SETTINGS_PATH}`;

return baseApi.request({
url,
requestParams: {
method: 'DELETE',
},
});
};
1 change: 1 addition & 0 deletions src/common/constants/api.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const PROFILE_API_ENDPOINT = '/linked-data/profile';
export const PROFILE_METADATA_API_ENDPOINT = '/linked-data/profile/metadata';
export const PROFILE_PREFERRED_API_ENDPOINT = '/linked-data/profile/preferred';
export const PROFILE_SETTINGS_PATH = 'settings';
export const PREFERRED_PROFILE_SETTINGS_PATH = `preferred`;
export const AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT = '/linked-data/authority-assignment-check';
export const IMPORT_JSON_FILE_API_ENDPOINT = '/linked-data/import/file';
export const IMPORT_JSON_URL_API_ENDPOINT = '/linked-data/import/url';
Expand Down
6 changes: 0 additions & 6 deletions src/common/helpers/navigation.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ export const generatePageURL = ({
url,
queryParams,
profileId,
profileSettingsId,
}: {
url: string;
queryParams: Record<QueryParams, string>;
profileId: string | number;
profileSettingsId?: string | number;
}) => {
const urlParams = new URLSearchParams();

Expand All @@ -62,10 +60,6 @@ export const generatePageURL = ({
urlParams.set(QueryParams.ProfileId, profileId.toString());
}

if (profileSettingsId) {
urlParams.set(QueryParams.ProfileSettingsId, profileSettingsId.toString());
}

const paramString = urlParams.toString();

return paramString ? `${url}?${paramString}` : url;
Expand Down
15 changes: 15 additions & 0 deletions src/features/edit/components/EditSection/EditSection.scss
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@
padding-bottom: 5px;
}

.setting-current {
font-weight: 700;
}

.setting-default {
font-style: italic;
}

.setting-preferred {
span {
text-transform: uppercase;
font-size: 90%;
}
}

&-menu {
position: absolute;
list-style: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ describe('ProfileSettingsSelector', () => {
const mockProfileId = 'profile-id';
const mockSetSelectedProfileSettingsId = jest.fn();

const renderComponent = () => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});

const renderComponent = (withOptions: boolean) => {
setInitialGlobalState([
{
store: useProfileStore,
Expand All @@ -30,23 +34,24 @@ describe('ProfileSettingsSelector', () => {
},
]);

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
queryClient.setQueryData(
['profileSettingsMeta', mockProfileId],
[
{
id: 15,
name: 'fifteen',
},
{
id: 32,
name: 'thirty-two',
},
],
withOptions
? [
{
id: 15,
name: 'fifteen',
},
{
id: 32,
name: 'thirty-two',
},
]
: [],
);

queryClient.setQueryData(['preferredProfileSettings', mockProfileId], [{ profileId: mockProfileId, id: 15 }]);

return render(
<QueryClientProvider client={queryClient}>
<MemoryRouter>
Expand All @@ -56,14 +61,30 @@ describe('ProfileSettingsSelector', () => {
);
};

afterEach(() => {
queryClient?.clear();
});

it('renders the component', () => {
renderComponent();
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent(true);

expect(screen.getByTestId('profile-settings-selector-button')).toBeInTheDocument();
});

it('does not render the component when no options', () => {
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent(false);

expect(screen.queryByTestId('profile-settings-selector-button')).not.toBeInTheDocument();
});

it('clicking button shows menu', () => {
renderComponent();
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent(true);

fireEvent.click(screen.getByTestId('profile-settings-selector-button'));

Expand All @@ -73,7 +94,7 @@ describe('ProfileSettingsSelector', () => {
it('profile setting currently in use is disabled', async () => {
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent();
renderComponent(true);

fireEvent.click(screen.getByTestId('profile-settings-selector-button'));

Expand All @@ -82,10 +103,22 @@ describe('ProfileSettingsSelector', () => {
});
});

it('preferred profile setting shows a label', async () => {
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent(true);

fireEvent.click(screen.getByTestId('profile-settings-selector-button'));

await waitFor(() => {
expect(screen.getByText('ld.preferred')).toBeInTheDocument();
});
});

it('clicking a setting selects it', async () => {
mockGetRecordProfileId.mockReturnValue(mockProfileId);

renderComponent();
renderComponent(true);

fireEvent.click(screen.getByTestId('profile-settings-selector-button'));
fireEvent.click(screen.getByText('fifteen'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getRecordProfileId } from '@/common/helpers/record.helper';
import { useDismissMenu } from '@/common/hooks/useDismissMenu';
import { Button, ButtonType } from '@/components/Button';

import { useLoadProfileSettingsMeta } from '@/features/profiles';
import { useLoadProfileSettingsMeta, usePreferredProfileSettings } from '@/features/profiles';

import { useInputsState, useProfileState } from '@/store';

Expand All @@ -33,18 +33,57 @@ export const ProfileSettingsSelector = () => {
},
] as ProfileSettingsMetaList;
const { data: profileSettings } = useLoadProfileSettingsMeta(selectedProfileId);
const { data: preferredProfileSettings } = usePreferredProfileSettings(selectedProfileId);

const profileSettingsOptions = useMemo(() => {
return profileSettings ? basicOption.concat(profileSettings) : basicOption;
}, [basicOption, profileSettings]);

const hasOptions = useMemo(() => {
return (profileSettings?.length ?? 0) > 0;
}, [profileSettings]);

const { isOpen: isMenuEnabled, setIsOpen: setIsMenuEnabled, toggle: toggleIsMenuEnabled } = useDismissMenu(ref);

const handleSettingClick = async (profileSettingsId: string | number) => {
setIsMenuEnabled(false);
setSelectedProfileSettingsId(profileSettingsId.toString());
};

return (
const isPreferred = (profileSetting: ProfileSettingsMeta) => {
return preferredProfileSettings?.some(p => p.id === profileSetting.id);
};

const getClassNames = (profileSetting: ProfileSettingsMeta) => {
const classNames = [];
if (profileSetting.id === PROFILE_SETTINGS_DEFAULT_OPTION) {
classNames.push('setting-default');
}
if (profileSetting.id === selectedProfileSettingsId) {
classNames.push('setting-current');
}
if (isPreferred(profileSetting)) {
classNames.push('setting-preferred');
}
return classNames.join(' ');
};

const getLabel = (profileSetting: ProfileSettingsMeta) => {
return (
<>
{profileSetting.name}
{isPreferred(profileSetting) ? (
<span>
<FormattedMessage id="ld.preferred" />
</span>
) : (
''
)}
</>
);
};

return hasOptions ? (
<div className="profile-settings-selector" ref={ref}>
<Button
data-testid="profile-settings-selector-button"
Expand All @@ -69,17 +108,21 @@ export const ProfileSettingsSelector = () => {
<li key={profileSetting.id} role="none">
<Button
type={ButtonType.Text}
label={profileSetting.name}
role="menuitem"
disabled={profileSetting.id.toString() === selectedProfileSettingsId}
onClick={() => handleSettingClick(profileSetting.id)}
tabbable={isMenuEnabled}
/>
className={getClassNames(profileSetting)}
>
{getLabel(profileSetting)}
</Button>
</li>
);
})}
</ul>
)}
</div>
) : (
<></>
);
};
2 changes: 2 additions & 0 deletions src/features/edit/hooks/useEditPage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jest.mock('@/common/hooks/useSchemaPipeline', () => ({

const mockSetIsLoading = jest.fn();
const mockSetSelectedProfile = jest.fn();
const mockSetSelectedProfileSettingsId = jest.fn();
const mockSetInitialSchemaKey = jest.fn();
const mockSetSchema = jest.fn();
const mockSetUserValues = jest.fn();
Expand All @@ -86,6 +87,7 @@ const setupStores = () => {
store: useProfileStore,
state: {
setSelectedProfile: mockSetSelectedProfile,
setSelectedProfileSettingsId: mockSetSelectedProfileSettingsId,
setInitialSchemaKey: mockSetInitialSchemaKey,
setSchema: mockSetSchema,
},
Expand Down
4 changes: 3 additions & 1 deletion src/features/edit/hooks/useEditPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ export const useEditPage = () => {
const { selectedEntriesService } = useSchemaPipeline();

const { setIsLoading } = useLoadingState(['setIsLoading']);
const { setSelectedProfile, setInitialSchemaKey, setSchema } = useProfileState([
const { setSelectedProfile, setSelectedProfileSettingsId, setInitialSchemaKey, setSchema } = useProfileState([
'setSelectedProfile',
'setSelectedProfileSettingsId',
'setInitialSchemaKey',
'setSchema',
]);
Expand Down Expand Up @@ -110,6 +111,7 @@ export const useEditPage = () => {
const applyToProfileAndInputStores = useCallback(
({ result }: ApplyToProfileAndInputStoresProps) => {
setSelectedProfile(result.selectedProfile ?? null);
setSelectedProfileSettingsId(result.selectedProfileSettingsId?.toString() ?? null);
setSchema(result.schema);
setInitialSchemaKey(result.initKey);
setUserValues(result.userValues);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.default-profile-settings {
padding: 3px 15px 15px;
display: flex;
flex-direction: row;
align-items: center;
gap: 0.25rem;
}
Loading
Loading