gitlab-ce/app/assets/javascripts/ml/model_registry/components/model_edit.vue

190 lines
5.6 KiB
Vue

<script>
import { GlAlert, GlButton, GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import PageHeading from '~/vue_shared/components/page_heading.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
import { noSpacesRegex } from '~/lib/utils/regexp';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import editModelMutation from '../graphql/mutations/edit_model.mutation.graphql';
export default {
name: 'ModelEdit',
components: {
PageHeading,
MarkdownEditor,
GlAlert,
GlButton,
GlForm,
GlFormGroup,
GlFormInput,
},
props: {
model: {
type: Object,
required: true,
},
disableAttachments: {
type: Boolean,
required: false,
default: false,
},
projectPath: {
type: String,
required: true,
},
markdownPreviewPath: {
type: String,
required: true,
},
modelPath: {
type: String,
required: true,
},
},
data() {
return {
errorMessage: null,
modelData: null,
markdownDocPath: helpPagePath('user/markdown'),
markdownEditorRestrictedToolBarItems: ['full-screen'],
description: this.model.description,
};
},
computed: {
autocompleteDataSources() {
return gl.GfmAutoComplete?.dataSources;
},
modelNameIsValid() {
return this.model.name && noSpacesRegex.test(this.model.name);
},
modelNameDescription() {
return !this.model.name || this.modelNameIsValid ? this.$options.i18n.nameDescription : '';
},
},
methods: {
async edit() {
this.errorMessage = '';
try {
const { data } = await this.$apollo.mutate({
mutation: editModelMutation,
variables: {
projectPath: this.projectPath,
modelId: getIdFromGraphQLId(this.model.id),
name: this.model.name,
description: this.description,
},
});
const modelErrors = data?.mlModelEdit?.errors || [];
if (modelErrors.length) {
this.errorMessage = modelErrors.join(', ');
} else {
const { showPath } = data.mlModelEdit.model._links;
visitUrl(showPath);
}
} catch (error) {
Sentry.captureException(error);
this.errorMessage = error;
}
},
hideAlert() {
this.errorMessage = null;
},
setDescription(newText) {
if (!this.isSubmitting) {
this.description = newText;
}
},
},
descriptionFormFieldProps: {
placeholder: s__('MlModelRegistry|Enter a model description'),
id: 'model-description',
name: 'model-description',
},
i18n: {
actionSecondaryText: __('Cancel'),
actionPrimaryText: s__('MlModelRegistry|Save changes'),
nameDescriptionLabel: s__('MlModelRegistry|Must be unique. May not contain spaces.'),
nameDescription: s__('MlModelRegistry|Example: my-model'),
nameInvalid: s__('MlModelRegistry|May not contain spaces.'),
nameDescriptionPlaceholder: s__('MlModelRegistry|Enter a model description'),
title: s__('MlModelRegistry|Edit model'),
modelName: s__('MlModelRegistry|Model name'),
modelDescription: __('Model description'),
optionalText: s__('MlModelRegistry|(Optional)'),
},
};
</script>
<template>
<div>
<gl-alert
v-if="errorMessage"
data-testid="edit-alert"
variant="danger"
class="gl-mt-5"
@dismiss="hideAlert"
>{{ errorMessage }}
</gl-alert>
<page-heading :heading="$options.i18n.title" />
<gl-form>
<gl-form-group
:label="$options.i18n.modelName"
:label-description="$options.i18n.nameDescriptionLabel"
label-for="nameId"
data-testid="nameGroupId"
:state="modelNameIsValid"
:invalid-feedback="$options.i18n.nameInvalid"
:description="modelNameDescription"
>
<gl-form-input
id="nameId"
:value="model.name"
data-testid="nameId"
type="text"
required
:disabled="true"
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.modelDescription"
data-testid="descriptionGroupId"
label-for="descriptionId"
optional
:optional-text="$options.i18n.optionalText"
class="common-note-form gfm-form js-main-target-form new-note gl-grow"
>
<markdown-editor
ref="markdownEditor"
data-testid="descriptionId"
:value="model.description"
enable-autocomplete
:autocomplete-data-sources="autocompleteDataSources"
:enable-content-editor="true"
:form-field-props="$options.descriptionFormFieldProps"
:render-markdown-path="markdownPreviewPath"
:markdown-docs-path="markdownDocPath"
:disable-attachments="disableAttachments"
:placeholder="$options.i18n.nameDescriptionPlaceholder"
:restricted-tool-bar-items="markdownEditorRestrictedToolBarItems"
@input="setDescription"
/>
</gl-form-group>
<div class="gl-flex gl-gap-3">
<gl-button data-testid="primary-button" variant="confirm" @click="edit"
>{{ $options.i18n.actionPrimaryText }}
</gl-button>
<gl-button data-testid="secondary-button" variant="default" :href="modelPath"
>{{ $options.i18n.actionSecondaryText }}
</gl-button>
</div>
</gl-form>
</div>
</template>