1<template> 2 <b-modal id="modal-user" ref="modal" :title="modalTitle" @hidden="resetForm"> 3 <b-form id="form-user" novalidate @submit.prevent="handleSubmit"> 4 <b-container> 5 <!-- Manual unlock form control --> 6 <b-row v-if="!newUser && manualUnlockPolicy && user.Locked"> 7 <b-col sm="9"> 8 <alert :show="true" variant="warning" small> 9 <template v-if="!v$.form.manualUnlock.$dirty"> 10 {{ i18n.t('pageUserManagement.modal.accountLocked') }} 11 </template> 12 <template v-else> 13 {{ 14 i18n.t('pageUserManagement.modal.clickSaveToUnlockAccount') 15 }} 16 </template> 17 </alert> 18 </b-col> 19 <b-col sm="3"> 20 <input 21 v-model="form.manualUnlock" 22 data-test-id="userManagement-input-manualUnlock" 23 type="hidden" 24 /> 25 <b-button 26 variant="primary" 27 :disabled="v$.form.manualUnlock.$dirty" 28 data-test-id="userManagement-button-manualUnlock" 29 @click="v$.form.manualUnlock.$touch()" 30 > 31 {{ i18n.t('pageUserManagement.modal.unlock') }} 32 </b-button> 33 </b-col> 34 </b-row> 35 <b-row> 36 <b-col> 37 <b-form-group 38 :label="i18n.t('pageUserManagement.modal.accountStatus')" 39 > 40 <b-form-radio 41 v-model="form.status" 42 name="user-status" 43 :value="true" 44 data-test-id="userManagement-radioButton-statusEnabled" 45 @input="v$.form.status.$touch()" 46 > 47 {{ i18n.t('global.status.enabled') }} 48 </b-form-radio> 49 <b-form-radio 50 v-model="form.status" 51 name="user-status" 52 data-test-id="userManagement-radioButton-statusDisabled" 53 :value="false" 54 :disabled="!newUser && originalUsername === disabled" 55 @input="v$.form.status.$touch()" 56 > 57 {{ i18n.t('global.status.disabled') }} 58 </b-form-radio> 59 </b-form-group> 60 <b-form-group 61 :label="i18n.t('pageUserManagement.modal.username')" 62 label-for="username" 63 > 64 <b-form-text id="username-help-block"> 65 {{ i18n.t('pageUserManagement.modal.cannotStartWithANumber') }} 66 <br /> 67 {{ 68 i18n.t( 69 'pageUserManagement.modal.noSpecialCharactersExceptUnderscore', 70 ) 71 }} 72 </b-form-text> 73 <b-form-input 74 id="username" 75 v-model="form.username" 76 type="text" 77 aria-describedby="username-help-block" 78 data-test-id="userManagement-input-username" 79 :state="getValidationState(v$.form.username)" 80 :disabled="!newUser && originalUsername === disabled" 81 @input="v$.form.username.$touch()" 82 /> 83 <b-form-invalid-feedback role="alert"> 84 <template v-if="v$.form.username.required.$invalid"> 85 {{ i18n.t('global.form.fieldRequired') }} 86 </template> 87 <template v-else-if="v$.form.username.maxLength.$invalid"> 88 {{ 89 i18n.t('global.form.lengthMustBeBetween', { 90 min: 1, 91 max: 16, 92 }) 93 }} 94 </template> 95 <template v-else-if="v$.form.username.pattern.$invalid"> 96 {{ i18n.t('global.form.invalidFormat') }} 97 </template> 98 </b-form-invalid-feedback> 99 </b-form-group> 100 <b-form-group 101 :label="i18n.t('pageUserManagement.modal.privilege')" 102 label-for="privilege" 103 > 104 <b-form-select 105 id="privilege" 106 v-model="form.privilege" 107 :options="privilegeTypes" 108 data-test-id="userManagement-select-privilege" 109 :state="getValidationState(v$.form.privilege)" 110 :disabled="!newUser && originalUsername === 'root'" 111 @input="v$.form.privilege.$touch()" 112 > 113 <template #first> 114 <b-form-select-option :value="null" disabled> 115 {{ i18n.t('global.form.selectAnOption') }} 116 </b-form-select-option> 117 </template> 118 </b-form-select> 119 <b-form-invalid-feedback role="alert"> 120 <template v-if="v$.form.privilege.required.$invalid"> 121 {{ i18n.t('global.form.fieldRequired') }} 122 </template> 123 </b-form-invalid-feedback> 124 </b-form-group> 125 </b-col> 126 <b-col> 127 <b-form-group 128 :label="i18n.t('pageUserManagement.modal.userPassword')" 129 label-for="password" 130 > 131 <b-form-text id="password-help-block"> 132 {{ 133 i18n.t('pageUserManagement.modal.passwordMustBeBetween', { 134 min: passwordRequirements.minLength, 135 max: passwordRequirements.maxLength, 136 }) 137 }} 138 </b-form-text> 139 <input-password-toggle> 140 <b-form-input 141 id="password" 142 v-model="form.password" 143 type="password" 144 autocomplete="new-password" 145 data-test-id="userManagement-input-password" 146 aria-describedby="password-help-block" 147 :state="getValidationState(v$.form.password)" 148 class="form-control-with-button" 149 @input="v$.form.password.$touch()" 150 /> 151 <b-form-invalid-feedback role="alert"> 152 <template v-if="v$.form.password.required.$invalid"> 153 {{ i18n.t('global.form.fieldRequired') }} 154 </template> 155 <template 156 v-if=" 157 v$.form.password.minLength.$invalid || 158 v$.form.password.maxLength.$invalid 159 " 160 > 161 {{ 162 i18n.t('pageUserManagement.modal.passwordMustBeBetween', { 163 min: passwordRequirements.minLength, 164 max: passwordRequirements.maxLength, 165 }) 166 }} 167 </template> 168 </b-form-invalid-feedback> 169 </input-password-toggle> 170 </b-form-group> 171 <b-form-group 172 :label="i18n.t('pageUserManagement.modal.confirmUserPassword')" 173 label-for="password-confirmation" 174 > 175 <input-password-toggle> 176 <b-form-input 177 id="password-confirmation" 178 v-model="form.passwordConfirmation" 179 data-test-id="userManagement-input-passwordConfirmation" 180 type="password" 181 autocomplete="new-password" 182 :state="getValidationState(v$.form.passwordConfirmation)" 183 class="form-control-with-button" 184 @input="v$.form.passwordConfirmation.$touch()" 185 /> 186 <b-form-invalid-feedback role="alert"> 187 <template 188 v-if="v$.form.passwordConfirmation.required.$invalid" 189 > 190 {{ i18n.t('global.form.fieldRequired') }} 191 </template> 192 <template 193 v-else-if=" 194 v$.form.passwordConfirmation.sameAsPassword.$invalid 195 " 196 > 197 {{ i18n.t('pageUserManagement.modal.passwordsDoNotMatch') }} 198 </template> 199 </b-form-invalid-feedback> 200 </input-password-toggle> 201 </b-form-group> 202 </b-col> 203 </b-row> 204 </b-container> 205 </b-form> 206 <template #footer="{ cancel }"> 207 <b-button 208 variant="secondary" 209 data-test-id="userManagement-button-cancel" 210 @click="cancel()" 211 > 212 {{ i18n.t('global.action.cancel') }} 213 </b-button> 214 <b-button 215 form="form-user" 216 data-test-id="userManagement-button-submit" 217 type="submit" 218 variant="primary" 219 @click="onOk" 220 > 221 <template v-if="newUser"> 222 {{ i18n.t('pageUserManagement.addUser') }} 223 </template> 224 <template v-else> 225 {{ i18n.t('global.action.save') }} 226 </template> 227 </b-button> 228 </template> 229 </b-modal> 230</template> 231 232<script> 233import { 234 required, 235 maxLength, 236 minLength, 237 requiredIf, 238} from '@vuelidate/validators'; 239import { helpers, sameAs } from 'vuelidate/lib/validators'; 240import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js'; 241import { useVuelidate } from '@vuelidate/core'; 242 243import InputPasswordToggle from '@/components/Global/InputPasswordToggle'; 244import Alert from '@/components/Global/Alert'; 245import { useI18n } from 'vue-i18n'; 246 247export default { 248 components: { Alert, InputPasswordToggle }, 249 mixins: [VuelidateMixin], 250 props: { 251 user: { 252 type: Object, 253 default: null, 254 }, 255 passwordRequirements: { 256 type: Object, 257 required: true, 258 }, 259 }, 260 emits: ['ok', 'hidden'], 261 setup() { 262 const i18n = useI18n(); 263 return { 264 v$: useVuelidate(), 265 i18n, 266 }; 267 }, 268 data() { 269 return { 270 originalUsername: '', 271 form: { 272 status: true, 273 username: '', 274 privilege: null, 275 password: '', 276 passwordConfirmation: '', 277 manualUnlock: false, 278 }, 279 disabled: this.$store.getters['global/username'], 280 }; 281 }, 282 computed: { 283 modalTitle() { 284 return this.newUser 285 ? this.i18n.t('pageUserManagement.addUser') 286 : this.i18n.t('pageUserManagement.editUser'); 287 }, 288 newUser() { 289 return this.user ? false : true; 290 }, 291 accountSettings() { 292 return this.$store.getters['userManagement/accountSettings']; 293 }, 294 manualUnlockPolicy() { 295 return !this.accountSettings.accountLockoutDuration; 296 }, 297 privilegeTypes() { 298 return this.$store.getters['userManagement/accountRoles']; 299 }, 300 }, 301 watch: { 302 user: function (value) { 303 if (value === null) return; 304 this.originalUsername = value.username; 305 this.form.username = value.username; 306 this.form.status = value.Enabled; 307 this.form.privilege = value.privilege; 308 }, 309 }, 310 validations() { 311 return { 312 form: { 313 status: { 314 required, 315 }, 316 username: { 317 required, 318 maxLength: maxLength(16), 319 pattern: helpers.regex('pattern', /^([a-zA-Z_][a-zA-Z0-9_]*)/), 320 }, 321 privilege: { 322 required, 323 }, 324 password: { 325 required: requiredIf(function () { 326 return this.requirePassword(); 327 }), 328 minLength: minLength(this.passwordRequirements.minLength), 329 maxLength: maxLength(this.passwordRequirements.maxLength), 330 }, 331 passwordConfirmation: { 332 required: requiredIf(function () { 333 return this.requirePassword(); 334 }), 335 sameAsPassword: sameAs('password'), 336 }, 337 manualUnlock: {}, 338 }, 339 }; 340 }, 341 methods: { 342 handleSubmit() { 343 let userData = {}; 344 345 if (this.newUser) { 346 this.v$.$touch(); 347 if (this.v$.$invalid) return; 348 userData.username = this.form.username; 349 userData.status = this.form.status; 350 userData.privilege = this.form.privilege; 351 userData.password = this.form.password; 352 } else { 353 if (this.v$.$invalid) return; 354 userData.originalUsername = this.originalUsername; 355 if (this.v$.form.status.$dirty) { 356 userData.status = this.form.status; 357 } 358 if (this.v$.form.username.$dirty) { 359 userData.username = this.form.username; 360 } 361 if (this.v$.form.privilege.$dirty) { 362 userData.privilege = this.form.privilege; 363 } 364 if (this.v$.form.password.$dirty) { 365 userData.password = this.form.password; 366 } 367 if (this.v$.form.manualUnlock.$dirty) { 368 // If form manualUnlock control $dirty then 369 // set user Locked property to false 370 userData.locked = false; 371 } 372 if (Object.entries(userData).length === 1) { 373 this.closeModal(); 374 return; 375 } 376 } 377 378 this.$emit('ok', { isNewUser: this.newUser, userData }); 379 this.closeModal(); 380 }, 381 closeModal() { 382 this.$nextTick(() => { 383 this.$refs.modal.hide(); 384 }); 385 }, 386 resetForm() { 387 this.form.originalUsername = ''; 388 this.form.status = true; 389 this.form.username = ''; 390 this.form.privilege = null; 391 this.form.password = ''; 392 this.form.passwordConfirmation = ''; 393 this.v$.$reset(); 394 this.$emit('hidden'); 395 }, 396 requirePassword() { 397 if (this.newUser) return true; 398 if (this.v$.form.password.$dirty) return true; 399 if (this.v$.form.passwordConfirmation.$dirty) return true; 400 return false; 401 }, 402 onOk(bvModalEvt) { 403 // prevent modal close 404 bvModalEvt.preventDefault(); 405 this.handleSubmit(); 406 }, 407 }, 408}; 409</script> 410