diff --git a/client/src/api/index.js b/client/src/api/index.js index 9afd8b95c..5ef50e72b 100644 --- a/client/src/api/index.js +++ b/client/src/api/index.js @@ -437,6 +437,10 @@ export function activateCollaboration(collaborationId) { return postPutJson("/api/collaborations/activate", {collaboration_id: collaborationId}, "put"); } +export function hintShortName(name) { + return postPutJson("/api/collaborations/hint_short_name", {name: name}, "post"); +} + //Organisations export function myOrganisationsLite() { return fetchJson(`/api/organisations/mine_lite`); diff --git a/client/src/pages/CollaborationForm.jsx b/client/src/pages/CollaborationForm.jsx index d4c23e5fe..366f63821 100644 --- a/client/src/pages/CollaborationForm.jsx +++ b/client/src/pages/CollaborationForm.jsx @@ -7,7 +7,7 @@ import { collaborationNameExists, collaborationShortNameExists, createCollaboration, - deleteCollaboration, + deleteCollaboration, hintShortName, myOrganisationsLite, requestCollaboration, tagsByOrganisation, @@ -45,6 +45,7 @@ class CollaborationForm extends React.Component { name: "", logo: "", short_name: "", + shortNameEdited: false, description: "", website_url: "", administrators: [], @@ -218,12 +219,24 @@ class CollaborationForm extends React.Component { validateCollaborationName = e => collaborationNameExists(e.target.value, this.state.organisation.value, this.existingCollaborationName("name")) - .then(json => this.setState({alreadyExists: {...this.state.alreadyExists, name: json}})); + .then(json => { + this.setState({alreadyExists: {...this.state.alreadyExists, name: json}}); + if (!json && !isEmpty(e.target.value)) { + this.generateShortName(e.target.value); + } + }); validateCollaborationShortName = e => collaborationShortNameExists(sanitizeShortName(e.target.value), this.state.organisation.value, this.existingCollaborationName("short_name")) .then(json => this.setState({alreadyExists: {...this.state.alreadyExists, short_name: json}})); + generateShortName = name => { + const {short_name, shortNameEdited} = this.state; + if ((!shortNameEdited || isEmpty(short_name)) && !isEmpty(name)) { + hintShortName(name).then(res => this.setState({short_name: res.short_name})); + } + } + cancel = () => { this.setState({ confirmationDialogOpen: true, @@ -550,9 +563,12 @@ class CollaborationForm extends React.Component { includeLogoGallery={true} secondRow={true}/> + { + const shortNameEdited = this.state.short_name !== e.target.value; this.setState({ short_name: sanitizeShortName(e.target.value), + shortNameEdited: shortNameEdited, alreadyExists: {...this.state.alreadyExists, short_name: false} }) }} diff --git a/server/api/collaboration.py b/server/api/collaboration.py index 0758042db..e8eca3b4f 100644 --- a/server/api/collaboration.py +++ b/server/api/collaboration.py @@ -614,6 +614,14 @@ def save_collaboration_api(): return collaboration_json, 201 +@collaboration_api.route("/hint_short_name", methods=["POST"], strict_slashes=False) +@json_endpoint +def hint_short_name(): + data = current_request.get_json() + short_name_hint = generate_short_name(data["name"]) + return {"short_name": short_name_hint}, 200 + + def do_save_collaboration(data, organisation, user, current_user_admin=True, save_tags=True): _validate_collaboration(data, organisation) diff --git a/server/test/api/test_collaboration.py b/server/test/api/test_collaboration.py index 363d8751d..c6f516db8 100644 --- a/server/test/api/test_collaboration.py +++ b/server/test/api/test_collaboration.py @@ -706,8 +706,9 @@ def test_api_call_existing_name(self): content_type="application/json") self.assertEqual(400, response.status_code) data = response.json - self.assertIn(f"Collaboration with name '{co_ai_computing_name}' already exists within organisation '{unihard_name}'.", - data["message"]) + self.assertIn( + f"Collaboration with name '{co_ai_computing_name}' already exists within organisation '{unihard_name}'.", + data["message"]) def test_api_call_existing_short_name(self): response = self.client.post("/api/collaborations/v1", @@ -1036,3 +1037,11 @@ def test_generate_short_name(self): short_name = generate_short_name("Name !@#$ test qwerty long name") self.assertEqual("nametestqwertylo", short_name) + + def test_hint_short_name(self): + res = self.post("/api/collaborations/hint_short_name", body={"name": "monitor1"}, response_status_code=200) + self.assertEqual("monitor12", res["short_name"]) + + def test_empty_hint_short_name(self): + res = self.post("/api/collaborations/hint_short_name", body={"name": "*&^%$$@"}, response_status_code=200) + self.assertEqual("short_name", res["short_name"])