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