Skip to content

Commit 2a3baa2

Browse files
authored
Merge pull request #845 from fractal-analytics-platform/dev
Resources and profiles management (fractal-server 2.17)
2 parents 7b85b97 + 8d90c2c commit 2a3baa2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+2581
-840
lines changed

.github/workflows/end_to_end_tests.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ jobs:
1313
timeout-minutes: 20
1414

1515
env:
16-
OAUTH_DEXIDP_CLIENT_ID: client_test_web_id
17-
OAUTH_DEXIDP_CLIENT_SECRET: client_test_web_secret
18-
OAUTH_DEXIDP_REDIRECT_URL: "http://localhost:5173/auth/login/oauth2/"
19-
OAUTH_DEXIDP_OIDC_CONFIGURATION_ENDPOINT: "http://127.0.0.1:5556/dex/.well-known/openid-configuration"
16+
OAUTH_CLIENT_NAME: dexidp
17+
OAUTH_CLIENT_ID: client_test_web_id
18+
OAUTH_CLIENT_SECRET: client_test_web_secret
19+
OAUTH_REDIRECT_URL: "http://localhost:5173/auth/login/oauth2/"
20+
OAUTH_OIDC_CONFIG_ENDPOINT: "http://127.0.0.1:5556/dex/.well-known/openid-configuration"
2021
PUBLIC_OAUTH_CLIENT_NAME: dexidp
2122
PUBLIC_FRACTAL_DATA_URL: http://localhost:3000/data
2223
PUBLIC_FRACTAL_VIZARR_VIEWER_URL: http://localhost:3000/data/vizarr

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
* Added more keywords to match SLURM errors (\#843).
66
* Fixed bug in sandbox pages (\#839);
77
* Displayed all kinds of recent task activities in tasks management page. (\#835);
8+
* Managed resources and profiles (\#845):
9+
* Added new admin pages for resources and profiles;
10+
* Updated admin user pages to associate users with profiles;
11+
* Updated admin settings page;
12+
* Merged "My Profile" and "My settings" pages;
813

914
# 1.20.0
1015

__tests__/errors.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,26 @@ describe('Error utility functions', () => {
5454
expect(errors[2]).toBeUndefined();
5555
expect(errors[3]).toEqual("Value error, String must be an absolute path (given 'foobar').");
5656
});
57+
58+
it('strip custom loc', () => {
59+
const errorMap = getValidationMessagesMap(
60+
{
61+
detail: [
62+
{
63+
type: 'string_type',
64+
loc: ['body', 'local', 'name'],
65+
msg: 'Input should be a valid string',
66+
input: null
67+
}
68+
]
69+
},
70+
422,
71+
['body', 'local']
72+
);
73+
74+
/** @type {string} */
75+
const error = /** @type {string} */ (errorMap && errorMap['name']);
76+
77+
expect(error).toEqual('Input should be a valid string');
78+
});
5779
});

__tests__/mock/mock-types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export function mockUser(fields = {}) {
99
is_superuser: false,
1010
is_active: true,
1111
is_verified: true,
12-
username: null,
1312
group_ids_names: [],
1413
oauth_accounts: [],
14+
profile_id: 1,
1515
...fields
1616
};
1717
}

__tests__/v2/ProfileEditor.test.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import { render, screen } from '@testing-library/svelte';
3+
import userEvent from '@testing-library/user-event';
4+
5+
// The component to be tested must be imported after the mock setup
6+
import ProfileEditor from '../../src/lib/components/v2/admin/ProfileEditor.svelte';
7+
8+
describe('ProfileEditor', () => {
9+
const mockedResource = /** @type {import('fractal-components/types/api').Resource} */ ({
10+
id: 1,
11+
type: 'slurm_ssh'
12+
});
13+
14+
it('Edit SLURM SSH profile - success', async () => {
15+
/**
16+
* @type {(profile: any) => Promise<Response>}
17+
*/
18+
const mockSaveProfile = vi.fn(
19+
async () =>
20+
/** @type {Response} */ ({
21+
ok: true,
22+
status: 200,
23+
json: () => new Promise((resolve) => resolve({ id: 1 }))
24+
})
25+
);
26+
27+
const user = userEvent.setup();
28+
render(ProfileEditor, {
29+
props: {
30+
resource: mockedResource,
31+
profile: /** @type {import('fractal-components/types/api').Profile} */ ({
32+
id: 1,
33+
resource_id: 1,
34+
resource_type: 'slurm_ssh'
35+
}),
36+
saveProfile: mockSaveProfile
37+
}
38+
});
39+
40+
await user.type(screen.getByRole('textbox', { name: 'Profile name' }), 'profile name');
41+
await user.type(screen.getByRole('textbox', { name: 'Username' }), 'foo');
42+
await user.type(screen.getByRole('textbox', { name: 'SSH key path' }), '/path/to/key');
43+
await user.type(screen.getByRole('textbox', { name: 'Jobs remote dir' }), '/path/to/jobs');
44+
await user.type(screen.getByRole('textbox', { name: 'Tasks remote dir' }), '/path/to/tasks');
45+
46+
await user.click(screen.getByRole('button', { name: 'Save' }));
47+
48+
await screen.findByText('Profile successfully updated');
49+
50+
expect(mockSaveProfile).toHaveBeenCalledWith({
51+
id: 1,
52+
name: 'profile name',
53+
username: 'foo',
54+
ssh_key_path: '/path/to/key',
55+
jobs_remote_dir: '/path/to/jobs',
56+
tasks_remote_dir: '/path/to/tasks',
57+
resource_id: 1,
58+
resource_type: 'slurm_ssh'
59+
});
60+
});
61+
62+
it('Edit SLURM SSH profile - validation error', async () => {
63+
/**
64+
* @type {(profile: any) => Promise<Response>}
65+
*/
66+
const mockSaveProfile = vi.fn(
67+
async () =>
68+
/** @type {Response} */ ({
69+
ok: false,
70+
status: 422,
71+
json: () =>
72+
new Promise((resolve) =>
73+
resolve({
74+
detail: [
75+
{
76+
loc: ['body', 'slurm_ssh', 'name'],
77+
msg: 'mocked_error_name',
78+
type: 'value_error'
79+
},
80+
{
81+
loc: ['body', 'slurm_ssh', 'username'],
82+
msg: 'mocked_error_username',
83+
type: 'value_error'
84+
},
85+
{
86+
loc: ['body', 'slurm_ssh', 'ssh_key_path'],
87+
msg: 'mocked_error_ssh_key_path',
88+
type: 'value_error'
89+
},
90+
{
91+
loc: ['body', 'slurm_ssh', 'jobs_remote_dir'],
92+
msg: 'mocked_error_jobs_remote_dir',
93+
type: 'value_error'
94+
},
95+
{
96+
loc: ['body', 'slurm_ssh', 'tasks_remote_dir'],
97+
msg: 'mocked_error_tasks_remote_dir',
98+
type: 'value_error'
99+
}
100+
]
101+
})
102+
)
103+
})
104+
);
105+
106+
const user = userEvent.setup();
107+
render(ProfileEditor, {
108+
props: {
109+
resource: mockedResource,
110+
profile: {
111+
id: 1,
112+
resource_id: 1,
113+
name: 'profile name',
114+
resource_type: 'slurm_ssh',
115+
username: 'foo',
116+
ssh_key_path: '/path/to/key',
117+
jobs_remote_dir: '/path/to/jobs',
118+
tasks_remote_dir: '/path/to/tasks'
119+
},
120+
saveProfile: mockSaveProfile
121+
}
122+
});
123+
124+
await user.clear(screen.getByRole('textbox', { name: 'Profile name' }));
125+
await user.clear(screen.getByRole('textbox', { name: 'Username' }));
126+
await user.clear(screen.getByRole('textbox', { name: 'SSH key path' }));
127+
await user.clear(screen.getByRole('textbox', { name: 'Jobs remote dir' }));
128+
await user.clear(screen.getByRole('textbox', { name: 'Tasks remote dir' }));
129+
130+
await user.click(screen.getByRole('button', { name: 'Save' }));
131+
132+
await screen.findByText('mocked_error_name');
133+
await screen.findByText('mocked_error_username');
134+
await screen.findByText('mocked_error_ssh_key_path');
135+
await screen.findByText('mocked_error_jobs_remote_dir');
136+
await screen.findByText('mocked_error_tasks_remote_dir');
137+
138+
expect(mockSaveProfile).toHaveBeenCalledWith({
139+
id: 1,
140+
name: '',
141+
username: '',
142+
ssh_key_path: '',
143+
jobs_remote_dir: '',
144+
tasks_remote_dir: '',
145+
resource_id: 1,
146+
resource_type: 'slurm_ssh'
147+
});
148+
});
149+
});

__tests__/v2/TaskGroupActivities.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ describe('TaskGroupActivities', () => {
9696
{
9797
id: 1,
9898
99-
username: 'admin',
10099
is_active: true,
101100
is_superuser: true,
102101
is_verified: true,
103102
group_ids_names: [],
104-
oauth_accounts: []
103+
oauth_accounts: [],
104+
profile_id: 1,
105105
}
106106
]
107107
}

0 commit comments

Comments
 (0)