Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5978314
ChangeInvestigationStatusDialog.vue
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
ChangeInvestigationStatusDialog.vue
View Options
<template>
<cdx-dialog
v-model:open="open"
:title="$i18n( 'checkuser-suggestedinvestigations-change-status-dialog-title' ).text()"
:close-button-label="$i18n(
'checkuser-suggestedinvestigations-change-status-dialog-close-label'
).text()"
:use-close-button="true"
class="ext-checkuser-suggestedinvestigations-change-status-dialog"
>
<cdx-message
v-if="statusUpdateErrorMessage !== ''"
class="ext-checkuser-suggestedinvestigations-change-status-dialog-error-message"
type="error"
>
{{ statusUpdateErrorMessage }}
</cdx-message>
<p class="ext-checkuser-suggestedinvestigations-change-status-dialog-description">
{{ $i18n( 'checkuser-suggestedinvestigations-change-status-dialog-text' ).text() }}
</p>
<cdx-field
:is-fieldset="true"
class="ext-checkuser-suggestedinvestigations-change-status-dialog-status-radio"
>
<template #label>
{{ $i18n(
'checkuser-suggestedinvestigations-change-status-dialog-status-list-header'
).text() }}
</template>
<cdx-radio
v-for="radio in statusRadioOptions"
:key="'radio-' + radio.value"
v-model="selectedStatus"
name="checkuser-suggestedinvestigations-change-status-dialog-status-option"
:input-value="radio.value"
@change="onFormFieldChange"
>
{{ radio.label }}
<p
v-if="radio.description !== null"
class="cdx-label__description"
>
{{ radio.description }}
</p>
</cdx-radio>
</cdx-field>
<cdx-field
v-if="showStatusReasonField"
class="ext-checkuser-suggestedinvestigations-change-status-dialog-status-reason"
:optional="true"
>
<template #label>
{{ $i18n(
'checkuser-suggestedinvestigations-change-status-dialog-status-reason-header'
).text() }}
</template>
<p
v-if="statusReasonSubtitle.value !== null"
class="
ext-checkuser-suggestedinvestigations-change-status-dialog-reason-description
"
>
{{ statusReasonSubtitle }}
</p>
<character-limited-text-input
v-model:text-content="statusReason"
:byte-limit="255"
class="
ext-checkuser-suggestedinvestigations-change-status-dialog-status-reason__input
"
:placeholder="statusReasonPlaceholder"
@change="onFormFieldChange"
>
</character-limited-text-input>
</cdx-field>
<div class="ext-checkuser-suggestedinvestigations-change-status-dialog-footer">
<cdx-button
class="
ext-checkuser-suggestedinvestigations-change-status-dialog-footer__cancel-btn
"
@click="onCancelButtonClick"
>
{{ $i18n(
'checkuser-suggestedinvestigations-change-status-dialog-cancel-btn'
).text() }}
</cdx-button>
<cdx-button
class="
ext-checkuser-suggestedinvestigations-change-status-dialog-footer__submit-btn
"
weight="primary"
action="progressive"
@click="onSubmitButtonClick"
>
{{ $i18n(
'checkuser-suggestedinvestigations-change-status-dialog-submit-btn'
).text() }}
</cdx-button>
</div>
</cdx-dialog>
</template>
<script>
const { ref, watch, computed } = require( 'vue' ),
{ CdxButton, CdxDialog, CdxField, CdxRadio, CdxMessage } = require( '@wikimedia/codex' ),
Constants = require( '../Constants.js' ),
{ setCaseStatus } = require( '../rest.js' ),
{ updateCaseStatusOnPage } = require( '../utils.js' ),
CharacterLimitedTextInput = require( './CharacterLimitedTextInput.vue' );
// @vue/component
module.exports = exports = {
name: 'ChangeInvestigationStatusDialog',
components: {
CdxButton,
CdxDialog,
CdxField,
CdxRadio,
CdxMessage,
CharacterLimitedTextInput
},
props: {
/**
* The case ID of the suggested investigations case that we are changing the status of.
*/
caseId: {
type: Number,
required: true
},
/**
* The selected status for the case being updated vid the dialog.
* This should be set to the current status when creating the component.
*/
initialStatus: {
type: String,
required: true
},
/**
* The reason given for the status of the case
* This should be set to the current reason when creating the component.
*/
initialStatusReason: {
type: String,
required: true
}
},
setup( props ) {
const open = ref( true );
const formSubmissionInProgress = ref( false );
const statusUpdateErrorMessage = ref( '' );
const selectedStatus = ref( props.initialStatus );
const statusReason = ref( props.initialStatusReason );
const statusRadioOptions = ref( Constants.caseStatuses.map( ( status ) => {
const statusOptions = {
value: status,
// Uses:
// * checkuser-suggestedinvestigations-status-open
// * checkuser-suggestedinvestigations-status-resolved
// * checkuser-suggestedinvestigations-status-invalid
label: mw.msg( 'checkuser-suggestedinvestigations-status-' + status ),
description: null
};
if ( status === 'invalid' ) {
statusOptions.description = mw.msg(
'checkuser-suggestedinvestigations-status-description-invalid'
);
}
return statusOptions;
} ) );
const statusReasonSubtitle = computed( () => {
if ( selectedStatus.value === 'open' ) {
return '';
}
// Uses:
// * checkuser-suggestedinvestigations-change-status-dialog-reason-description-resolved
// * checkuser-suggestedinvestigations-change-status-dialog-reason-description-invalid
return mw.msg( 'checkuser-suggestedinvestigations-change-status-dialog-reason-description-' + selectedStatus.value );
} );
const statusReasonPlaceholder = computed( () => {
if ( selectedStatus.value === 'open' ) {
return '';
}
// Uses:
// * checkuser-suggestedinvestigations-change-status-dialog-reason-placeholder-resolved
// * checkuser-suggestedinvestigations-change-status-dialog-reason-placeholder-invalid
return mw.msg( 'checkuser-suggestedinvestigations-change-status-dialog-reason-placeholder-' + selectedStatus.value );
} );
// Don't hide the reason field if the field has ever been non-empty.
// This is so that a user can modify a reason that was already set before
// and avoids the field disappearing unexpectedly if the user clears the input.
const hasStatusReasonHadText = ref( statusReason.value !== '' );
if ( !hasStatusReasonHadText.value ) {
const unwatch = watch( statusReason, ( newStatusReason ) => {
if ( newStatusReason !== '' ) {
hasStatusReasonHadText.value = true;
unwatch();
}
} );
}
const showStatusReasonField = computed( () => selectedStatus.value !== 'open' || hasStatusReasonHadText.value );
/**
* Fired when any form fields have their value changed.
* Used to clear any error message set in the form.
*/
function onFormFieldChange() {
statusUpdateErrorMessage.value = '';
}
function onCancelButtonClick() {
open.value = false;
}
/**
* Handles a click of the submit button which includes making a REST API request
* to update the status of the investigation and displaying any errors if they occur.
*/
function onSubmitButtonClick() {
// Ignore duplicate attempts to press the submit button to avoid race conditions
if ( formSubmissionInProgress.value ) {
return;
}
formSubmissionInProgress.value = true;
statusUpdateErrorMessage.value = '';
setCaseStatus( props.caseId, selectedStatus.value, statusReason.value )
.then( ( data ) => {
updateCaseStatusOnPage( props.caseId, data.status, data.reason );
open.value = false;
formSubmissionInProgress.value = false;
} )
.catch( ( err, errObject ) => {
formSubmissionInProgress.value = false;
let errMessage = errObject.exception;
if (
errObject.xhr &&
errObject.xhr.responseJSON &&
errObject.xhr.responseJSON.messageTranslations
) {
// If we have translated messages for this error, then try to find a
// translation to display to the user using the language fallback chain
// to find the most appropriate language that is defined
const messageTranslations = errObject.xhr.responseJSON.messageTranslations;
const fallbackChain = mw.language.getFallbackLanguageChain();
for ( const language of fallbackChain ) {
if ( messageTranslations[ language ] ) {
errMessage = messageTranslations[ language ];
break;
}
}
}
statusUpdateErrorMessage.value = errMessage;
} );
}
return {
open,
selectedStatus,
showStatusReasonField,
statusReason,
statusReasonSubtitle,
statusReasonPlaceholder,
statusRadioOptions,
statusUpdateErrorMessage,
onFormFieldChange,
onCancelButtonClick,
onSubmitButtonClick
};
}
};
</script>
<style lang="less">
@import ( reference ) 'mediawiki.skin.variables.less';
.ext-checkuser-suggestedinvestigations-change-status-dialog {
.ext-checkuser-suggestedinvestigations-change-status-dialog-footer {
float: right;
.ext-checkuser-suggestedinvestigations-change-status-dialog-footer__cancel-btn {
margin-right: @spacing-50;
}
}
.ext-checkuser-suggestedinvestigations-change-status-dialog-reason-description,
.ext-checkuser-suggestedinvestigations-change-status-description {
margin-top: 0;
color: @color-subtle;
}
.ext-checkuser-suggestedinvestigations-change-status-dialog-status-reason {
margin-bottom: @spacing-150;
}
.ext-checkuser-suggestedinvestigations-change-status-dialog-error-message {
padding-top: @spacing-75;
}
}
</style>
File Metadata
Details
Attached
Mime Type
text/html
Expires
Sat, Oct 3, 20:21 (3 d, 14 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ec/c6/f707fddb9e7b647b63394a451402
Default Alt Text
ChangeInvestigationStatusDialog.vue (9 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment