Skip to content

Commit

Permalink
Merge pull request #14109 from jmchilton/user_preferences_decompose
Browse files Browse the repository at this point in the history
Decompose UserPreferences for reuse.
  • Loading branch information
bgruening authored Jun 23, 2022
2 parents dbe645e + c530684 commit 4385cc1
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 85 deletions.
27 changes: 27 additions & 0 deletions client/src/components/User/UserDeletion.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { mount } from "@vue/test-utils";
import { getLocalVue } from "jest/helpers";
import UserDeletion from "./UserDeletion";

const localVue = getLocalVue(true);

const TEST_USER_ID = "myTestUserId";
const TEST_EMAIL = `${TEST_USER_ID}@test.com`;
const TEST_ROOT = "/";

function mountComponent() {
const wrapper = mount(UserDeletion, {
propsData: { userId: TEST_USER_ID, root: TEST_ROOT, email: TEST_EMAIL },
localVue,
});
return wrapper;
}

import { ROOT_COMPONENT } from "utils/navigation";

describe("UserDeletion.vue", () => {
it("contains a localized link", async () => {
const wrapper = mountComponent();
const el = await wrapper.find(ROOT_COMPONENT.preferences.delete_account.selector);
expect(el.text()).toBeLocalizationOf("Delete Account");
});
});
117 changes: 117 additions & 0 deletions client/src/components/User/UserDeletion.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<template>
<b-row class="ml-3 mb-1">
<i class="pref-icon pt-1 fa fa-lg fa-radiation" />
<div class="pref-content pr-1">
<a id="delete-account" href="javascript:void(0)"
><b v-b-modal.modal-prevent-closing v-localize>Delete Account</b></a
>
<div v-localize class="form-text text-muted">Delete your account on this Galaxy server.</div>
<b-modal
id="modal-prevent-closing"
ref="modal"
centered
title="Account Deletion"
title-tag="h2"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk">
<p>
<b-alert variant="danger" :show="showDeleteError">{{ deleteError }}</b-alert>
<b>
This action cannot be undone. Your account will be permanently deleted, along with the data
contained in it.
</b>
</p>
<b-form ref="form" @submit.prevent="handleSubmit">
<b-form-group
:state="nameState"
label="Enter your user email for this account as confirmation."
label-for="Email"
invalid-feedback="Incorrect email">
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
</b-form-group>
</b-form>
</b-modal>
</div>
</b-row>
</template>

<script>
import axios from "axios";
import Vue from "vue";
import BootstrapVue from "bootstrap-vue";
import { userLogoutClient } from "layout/menu";
Vue.use(BootstrapVue);
export default {
props: {
root: {
type: String,
required: true,
},
userId: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
},
data() {
return {
name: "",
nameState: null,
deleteError: "",
};
},
computed: {
showDeleteError() {
return this.deleteError !== "";
},
},
methods: {
checkFormValidity() {
const valid = this.$refs.form.checkValidity();
this.nameState = valid;
return valid;
},
resetModal() {
this.name = "";
this.nameState = null;
},
handleOk(bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault();
// Trigger submit handler
this.handleSubmit();
},
async handleSubmit() {
if (!this.checkFormValidity()) {
return false;
}
if (this.email === this.name) {
this.nameState = true;
try {
await axios.delete(`${this.root}api/users/${this.userId}`);
} catch (e) {
if (e.response.status === 403) {
this.deleteError =
"User deletion must be configured on this instance in order to allow user self-deletion. Please contact an administrator for assistance.";
return false;
}
}
userLogoutClient();
} else {
this.nameState = false;
return false;
}
},
},
};
</script>

<style scoped>
@import "user-styles.scss";
</style>
100 changes: 15 additions & 85 deletions client/src/components/User/UserPreferences.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,12 @@
</div>
</b-row>
<ConfigProvider v-slot="{ config }">
<b-row v-if="config && !config.single_user && config.enable_account_interface" class="ml-3 mb-1">
<i class="pref-icon pt-1 fa fa-lg fa-radiation" />
<div class="pref-content pr-1">
<a id="delete-account" href="javascript:void(0)"
><b v-b-modal.modal-prevent-closing v-localize>Delete Account</b></a
>
<div v-localize class="form-text text-muted">Delete your account on this Galaxy server.</div>
<b-modal
id="modal-prevent-closing"
ref="modal"
centered
title="Account Deletion"
title-tag="h2"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk">
<p>
<b-alert variant="danger" :show="showDeleteError">{{ deleteError }}</b-alert>
<b>
This action cannot be undone. Your account will be permanently deleted, along with the
data contained in it.
</b>
</p>
<b-form ref="form" @submit.prevent="handleSubmit">
<b-form-group
:state="nameState"
label="Enter your user email for this account as confirmation."
label-for="Email"
invalid-feedback="Incorrect email">
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
</b-form-group>
</b-form>
</b-modal>
</div>
</b-row>
<UserDeletion
v-if="config && !config.single_user && config.enable_account_interface"
:email="email"
:root="root"
:user-id="userId">
</UserDeletion>
</ConfigProvider>
<p class="mt-2">
{{ titleYouAreUsing }} <strong>{{ diskUsage }}</strong> {{ titleOfDiskSpace }}
Expand All @@ -91,14 +62,17 @@ import axios from "axios";
import QueryStringParsing from "utils/query-string-parsing";
import { getUserPreferencesModel } from "components/User/UserPreferencesModel";
import ConfigProvider from "components/providers/ConfigProvider";
import { userLogoutAll, userLogoutClient } from "layout/menu";
import { userLogoutAll } from "layout/menu";
import UserDeletion from "./UserDeletion";
import "@fortawesome/fontawesome-svg-core";
Vue.use(BootstrapVue);
export default {
components: {
ConfigProvider,
UserDeletion,
},
props: {
userId: {
Expand All @@ -115,12 +89,9 @@ export default {
email: "",
diskUsage: "",
quotaUsageString: "",
baseUrl: `${getAppRoot()}user`,
root: getAppRoot(),
messageVariant: null,
message: null,
name: "",
nameState: null,
deleteError: "",
submittedNames: [],
titleYouAreUsing: _l("You are using"),
titleOfDiskSpace: _l("of disk space in this Galaxy instance."),
Expand All @@ -130,6 +101,9 @@ export default {
};
},
computed: {
baseUrl() {
return `${this.root}user`;
},
activeLinks() {
const activeLinks = {};
const UserPreferencesModel = getUserPreferencesModel();
Expand All @@ -156,9 +130,6 @@ export default {
return activeLinks;
},
showDeleteError() {
return this.deleteError !== "";
},
},
created() {
const message = QueryStringParsing.get("message");
Expand Down Expand Up @@ -237,50 +208,9 @@ export default {
},
});
},
checkFormValidity() {
const valid = this.$refs.form.checkValidity();
this.nameState = valid;
return valid;
},
resetModal() {
this.name = "";
this.nameState = null;
},
handleOk(bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault();
// Trigger submit handler
this.handleSubmit();
},
async handleSubmit() {
if (!this.checkFormValidity()) {
return false;
}
if (this.email === this.name) {
this.nameState = true;
try {
await axios.delete(`${getAppRoot()}api/users/${this.userId}`);
} catch (e) {
if (e.response.status === 403) {
this.deleteError =
"User deletion must be configured on this instance in order to allow user self-deletion. Please contact an administrator for assistance.";
return false;
}
}
userLogoutClient();
} else {
this.nameState = false;
return false;
}
},
},
};
</script>
<style scoped>
.pref-content {
width: calc(100% - 3rem);
}
.pref-icon {
width: 3rem;
}
@import "user-styles.scss";
</style>
6 changes: 6 additions & 0 deletions client/src/components/User/user-styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.pref-content {
width: calc(100% - 3rem);
}
.pref-icon {
width: 3rem;
}

0 comments on commit 4385cc1

Please sign in to comment.