Skip to content
Snippets Groups Projects
Unverified Commit 48415d85 authored by Tristan Read's avatar Tristan Read Committed by GitLab
Browse files

Merge branch 'jh/fix-self-hosted-models-data-refreshes' into 'master'

[FIX] Refresh self-hosted models and feature settings data upon feature setting update

See merge request https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169387



Merged-by: default avatarTristan Read <tread@gitlab.com>
Approved-by: default avatarJack Chapman <jachapman@gitlab.com>
Approved-by: default avatarTristan Read <tread@gitlab.com>
Reviewed-by: default avatarJack Chapman <jachapman@gitlab.com>
Reviewed-by: default avatarJulie Huang <julhuang@gitlab.com>
Co-authored-by: default avatarJulie Huang <julhuang@gitlab.com>
parents d511368b afc895b6
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -3,6 +3,8 @@ import { GlCollapsibleListbox, GlButton } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import { createAlert } from '~/alert';
import updateAiFeatureSetting from '../graphql/mutations/update_ai_feature_setting.mutation.graphql';
import getAiFeatureSettingsQuery from '../graphql/queries/get_ai_feature_settings.query.graphql';
import getSelfHostedModelsQuery from '../../self_hosted_models/graphql/queries/get_self_hosted_models.query.graphql';
 
const PROVIDERS = {
DISABLED: 'disabled',
Loading
Loading
@@ -63,14 +65,14 @@ export default {
return this.compatibleModels.find((m) => m.id === this.selfHostedModelId);
},
dropdownToggleText() {
if (this.provider === PROVIDERS.VENDORED) {
return s__('AdminAIPoweredFeatures|Select a self-hosted model');
}
if (this.provider === PROVIDERS.DISABLED) {
return s__('AdminAIPoweredFeatures|Disabled');
}
if (this.selectedModel) {
return `${this.selectedModel?.name} (${this.selectedModel?.model})`;
}
 
return `${this.selectedModel.name} (${this.selectedModel.model})`;
return s__('AdminAIPoweredFeatures|Select a self-hosted model');
},
},
methods: {
Loading
Loading
@@ -93,6 +95,10 @@ export default {
aiSelfHostedModelId: selectedOption.selfHostedModelId,
},
},
refetchQueries: [
{ query: getSelfHostedModelsQuery },
{ query: getAiFeatureSettingsQuery },
],
});
 
if (data) {
Loading
Loading
Loading
Loading
@@ -6,6 +6,8 @@ import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import ModelSelectDropdown from 'ee/pages/admin/ai/feature_settings/components/model_select_dropdown.vue';
import updateAiFeatureSetting from 'ee/pages/admin/ai/feature_settings/graphql/mutations/update_ai_feature_setting.mutation.graphql';
import getAiFeatureSettingsQuery from 'ee/pages/admin/ai/feature_settings/graphql/queries/get_ai_feature_settings.query.graphql';
import getSelfHostedModelsQuery from 'ee/pages/admin/ai/self_hosted_models/graphql/queries/get_self_hosted_models.query.graphql';
import { createAlert } from '~/alert';
import { mockSelfHostedModels, mockAiFeatureSettings } from './mock_data';
 
Loading
Loading
@@ -20,7 +22,23 @@ describe('ModelSelectDropdown', () => {
const newSelfHostedModelPath = '/admin/ai/self_hosted_models/new';
const mockAiFeatureSetting = mockAiFeatureSettings[0];
 
const updateMutationSuccessHandler = jest.fn().mockResolvedValue({
const updateFeatureSettingsSuccessHandler = jest.fn().mockResolvedValue({
data: {
aiFeatureSettingUpdate: {
errors: [],
},
},
});
const getFeatureSettingsSuccessHandler = jest.fn().mockResolvedValue({
data: {
aiFeatureSettings: {
errors: [],
},
},
});
const getSelfHostedModelsSuccessHandler = jest.fn().mockResolvedValue({
data: {
aiFeatureSettingUpdate: {
errors: [],
Loading
Loading
@@ -29,7 +47,11 @@ describe('ModelSelectDropdown', () => {
});
 
const createComponent = ({
apolloHandlers = [[updateAiFeatureSetting, updateMutationSuccessHandler]],
apolloHandlers = [
[updateAiFeatureSetting, updateFeatureSettingsSuccessHandler],
[getAiFeatureSettingsQuery, getFeatureSettingsSuccessHandler],
[getSelfHostedModelsQuery, getSelfHostedModelsSuccessHandler],
],
props = {},
} = {}) => {
const mockApollo = createMockApollo([...apolloHandlers]);
Loading
Loading
@@ -51,19 +73,19 @@ describe('ModelSelectDropdown', () => {
});
};
 
beforeEach(() => {
createComponent();
});
const findSelectDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const findSelectDropdownButtonText = () => wrapper.find('[class="gl-new-dropdown-button-text"]');
const findButton = () => wrapper.find('[data-testid="add-self-hosted-model-button"]');
 
it('renders the dropdown component', () => {
createComponent();
expect(findSelectDropdown().exists()).toBe(true);
});
 
it('renders a list of select options', () => {
createComponent();
const modelOptions = findSelectDropdown().props('items');
 
expect(modelOptions.map((model) => model.text)).toEqual([
Loading
Loading
@@ -75,17 +97,23 @@ describe('ModelSelectDropdown', () => {
});
 
it('renders a button to add a self-hosted model', () => {
createComponent();
expect(findButton().text()).toBe('Add self-hosted model');
});
 
describe('when no model is selected and the feature is not disabled', () => {
it('displays the correct text on the dropdown button', () => {
createComponent();
expect(findSelectDropdownButtonText().text()).toBe('Select a self-hosted model');
});
});
 
describe('when an update is saving', () => {
it('renders the loading state', async () => {
createComponent();
await findSelectDropdownButtonText().trigger('click');
await findSelectDropdown().vm.$emit('select', 'DISABLED');
 
Loading
Loading
@@ -94,9 +122,13 @@ describe('ModelSelectDropdown', () => {
});
 
describe('when an update succeeds', () => {
beforeEach(() => {
createComponent();
});
it('displays a success toast', async () => {
await findSelectDropdownButtonText().trigger('click');
await findSelectDropdown().vm.$emit('select', 'DISABLED');
await findSelectDropdown().vm.$emit('select', 1);
 
await waitForPromises();
 
Loading
Loading
@@ -105,6 +137,16 @@ describe('ModelSelectDropdown', () => {
);
});
 
it('refreshes self-hosted models and feature settings data', async () => {
await findSelectDropdownButtonText().trigger('click');
await findSelectDropdown().vm.$emit('select', 1);
await waitForPromises();
expect(getSelfHostedModelsSuccessHandler).toHaveBeenCalled();
expect(getFeatureSettingsSuccessHandler).toHaveBeenCalled();
});
describe('when the feature has been disabled', () => {
it('displays the correct text on the dropdown button', async () => {
await findSelectDropdownButtonText().trigger('click');
Loading
Loading
@@ -134,7 +176,7 @@ describe('ModelSelectDropdown', () => {
 
describe('when an update fails', () => {
const selectedModel = mockSelfHostedModels[0];
const updateMutationErrorHandler = jest.fn().mockResolvedValue({
const updateFeatureSettingsErrorHandler = jest.fn().mockResolvedValue({
data: {
aiFeatureSettingUpdate: {
aiFeatureSetting: null,
Loading
Loading
@@ -145,7 +187,11 @@ describe('ModelSelectDropdown', () => {
 
beforeEach(async () => {
createComponent({
apolloHandlers: [[updateAiFeatureSetting, updateMutationErrorHandler]],
apolloHandlers: [
[updateAiFeatureSetting, updateFeatureSettingsErrorHandler],
[getAiFeatureSettingsQuery, getFeatureSettingsSuccessHandler],
[getSelfHostedModelsQuery, getSelfHostedModelsSuccessHandler],
],
});
 
await findSelectDropdownButtonText().trigger('click');
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment