Skip to content
Snippets Groups Projects
Unverified Commit b2151b82 authored by Julie Huang's avatar Julie Huang Committed by GitLab
Browse files

Make styling updates to self-hosted models empty state

parent 3e19ed08
No related branches found
No related tags found
No related merge requests found
<script>
import { GlTableLite, GlDisclosureDropdown, GlDisclosureDropdownItem, GlIcon } from '@gitlab/ui';
import {
GlTable,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlIcon,
GlLink,
GlSprintf,
} from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __, s__ } from '~/locale';
import DeleteSelfHostedModelDisclosureItem from './delete_self_hosted_model_disclosure_item.vue';
Loading
Loading
@@ -7,19 +14,26 @@ import DeleteSelfHostedModelDisclosureItem from './delete_self_hosted_model_disc
export default {
name: 'SelfHostedModelsTable',
components: {
GlTableLite,
GlTable,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlIcon,
GlLink,
GlSprintf,
DeleteSelfHostedModelDisclosureItem,
},
inject: ['basePath'],
inject: ['basePath', 'newSelfHostedModelPath'],
props: {
models: {
type: Array,
required: true,
},
},
i18n: {
emptyStateText: s__(
'AdminSelfHostedModels|You do not currently have any self-hosted models. %{linkStart}Add a self-hosted model%{linkEnd} to get started.',
),
},
fields: [
{
key: 'name',
Loading
Loading
@@ -69,14 +83,24 @@ export default {
};
</script>
<template>
<gl-table-lite
<gl-table
data-testid="self-hosted-model-table"
:fields="$options.fields"
:items="models"
stacked="md"
:hover="true"
:selectable="false"
:show-empty="true"
>
<template #empty>
<p class="gl-m-0 gl-py-4">
<gl-sprintf :message="$options.i18n.emptyStateText">
<template #link="{ content }">
<gl-link :href="newSelfHostedModelPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
</template>
<template #cell(has_api_key)="{ item }">
<gl-icon
v-if="item.hasApiToken"
Loading
Loading
@@ -96,5 +120,5 @@ export default {
<delete-self-hosted-model-disclosure-item :model="item" />
</gl-disclosure-dropdown>
</template>
</gl-table-lite>
</gl-table>
</template>
- page_title s_('AdminSelfHostedModels|Self-hosted models')
- terms_link_start = '<a href="https://about.gitlab.com/handbook/legal/testing-agreement/" target="_blank" rel="noopener noreferrer">'.html_safe
 
%h4
= s_('AdminSelfHostedModels|Self-hosted models')
%p.gl-text-secondary
= s_('AdminSelfHostedModels|Self-hosted models are an experimental feature.')
= link_to _('Learn more.'), help_page_path('administration/self_hosted_models/install_infrastructure.md')
= render Pajamas::ButtonComponent.new(variant: :confirm, href: admin_ai_terms_and_conditions_url, method: :post) do
= s_('AdminSelfHostedModels|Enable self-hosted models')
%p.gl-text-secondary.gl-mt-4
= s_('AdminSelfHostedModels|By enabling self-hosted models, you accept the %{link_start}GitLab Testing Agreement%{link_end}.').html_safe % { link_start: terms_link_start, link_end: '</a>'.html_safe }
.gl-flex.gl-flex-col.gl-items-center
= render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-state/empty-environment-md',
title: s_('AdminSelfHostedModels|Get started with self-hosted models')) do |c|
- c.with_description do
- terms_link_start = '<a href="https://about.gitlab.com/handbook/legal/testing-agreement/" target="_blank" rel="noopener noreferrer">'.html_safe
= s_('AdminSelfHostedModels|Configure GitLab Duo by adding and managing your own self-hosted models.')
= link_to _('Learn more.'), help_page_path('administration/self_hosted_models/install_infrastructure.md'), target: '_blank', rel: 'noopener noreferrer'
= s_('AdminSelfHostedModels|By enabling self-hosted models, you accept the %{link_start}GitLab Testing Agreement%{link_end}.').html_safe % { link_start: terms_link_start, link_end: '</a>'.html_safe }
= render Pajamas::ButtonComponent.new(variant: :confirm, href: admin_ai_terms_and_conditions_url, method: :post) do
= s_('AdminSelfHostedModels|Enable self-hosted models')
import { GlTableLite, GlDisclosureDropdown } from '@gitlab/ui';
import { GlTable, GlDisclosureDropdown, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import SelfHostedModelsTable from 'ee/pages/admin/ai/self_hosted_models/components/self_hosted_models_table.vue';
Loading
Loading
@@ -8,10 +8,11 @@ import { mockSelfHostedModelsList } from './mock_data';
describe('SelfHostedModelsTable', () => {
let wrapper;
 
const createComponent = ({ props }) => {
const basePath = '/admin/ai/self_hosted_models';
const aiFeatureSettingsPath = '/admin/ai/feature_settings';
const basePath = '/admin/ai/self_hosted_models';
const aiFeatureSettingsPath = '/admin/ai/feature_settings';
const newSelfHostedModelPath = 'admin/ai/self_hosted_models/new';
 
const createComponent = ({ props }) => {
wrapper = extendedWrapper(
mount(SelfHostedModelsTable, {
propsData: {
Loading
Loading
@@ -20,29 +21,31 @@ describe('SelfHostedModelsTable', () => {
provide: {
basePath,
aiFeatureSettingsPath,
newSelfHostedModelPath,
},
}),
);
};
 
beforeEach(() => {
createComponent({ props: { models: mockSelfHostedModelsList } });
});
const findTable = () => wrapper.findComponent(GlTableLite);
const findTable = () => wrapper.findComponent(GlTable);
const findTableHeaders = () => findTable().findAllComponents('th');
const findTableRows = () => findTable().findAllComponents('tbody > tr');
const findNthTableRow = (idx) => findTableRows().at(idx);
const findDisclosureDropdowns = () => wrapper.findAllComponents(GlDisclosureDropdown);
const findEditButtons = () => wrapper.findAllByTestId('model-edit-button');
const findEmptyStateLink = () => wrapper.findComponent(GlLink);
const findDeleteDisclosureItems = () =>
wrapper.findAllComponents(DeleteSelfHostedModelDisclosureItem);
 
it('renders the table component', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
expect(findTable().exists()).toBe(true);
});
 
it('renders table headers <th>', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
const expectedTableHeaderNames = [
'Name',
'Model',
Loading
Loading
@@ -56,6 +59,8 @@ describe('SelfHostedModelsTable', () => {
});
 
it('renders self-hosted model entries', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
expect(findTableRows().length).toEqual(2);
 
const firstModel = findNthTableRow(0);
Loading
Loading
@@ -68,11 +73,31 @@ describe('SelfHostedModelsTable', () => {
});
 
it('renders a disclosure dropdown for each self-hosted model entry', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
expect(findDisclosureDropdowns().length).toBe(2);
});
 
describe('when there are no self-hosted models', () => {
it('renders empty state text', () => {
createComponent({ props: { models: [] } });
expect(findTable().text()).toMatch(
'You do not currently have any self-hosted models. Add a self-hosted model to get started.',
);
});
it('renders a link to create a new self-hosted model', () => {
createComponent({ props: { models: [] } });
expect(findEmptyStateLink().attributes('href')).toBe(newSelfHostedModelPath);
});
});
describe('Editing a model', () => {
it('renders an edit button for each model', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
expect(findEditButtons().length).toBe(2);
 
findEditButtons().wrappers.forEach((button) => {
Loading
Loading
@@ -81,6 +106,8 @@ describe('SelfHostedModelsTable', () => {
});
 
it('routes to the correct path', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
findEditButtons().wrappers.forEach((button, idx) => {
expect(button.html()).toContain(`href="/admin/ai/self_hosted_models/${idx + 1}/edit"`);
});
Loading
Loading
@@ -89,6 +116,8 @@ describe('SelfHostedModelsTable', () => {
 
describe('Deleting a model', () => {
it('renders a delete button for each model', () => {
createComponent({ props: { models: mockSelfHostedModelsList } });
expect(findDeleteDisclosureItems().length).toBe(2);
 
findDeleteDisclosureItems().wrappers.forEach((button) => {
Loading
Loading
Loading
Loading
@@ -3888,6 +3888,9 @@ msgstr ""
msgid "AdminSelfHostedModels|Configure AI Features"
msgstr ""
 
msgid "AdminSelfHostedModels|Configure GitLab Duo by adding and managing your own self-hosted models."
msgstr ""
msgid "AdminSelfHostedModels|Create model"
msgstr ""
 
Loading
Loading
@@ -3918,6 +3921,9 @@ msgstr ""
msgid "AdminSelfHostedModels|Get started with Self‑hosted models"
msgstr ""
 
msgid "AdminSelfHostedModels|Get started with self-hosted models"
msgstr ""
msgid "AdminSelfHostedModels|If necessary, provide the model identifier in the form of provider/model-name"
msgstr ""
 
Loading
Loading
@@ -3981,9 +3987,6 @@ msgstr ""
msgid "AdminSelfHostedModels|Self-hosted models"
msgstr ""
 
msgid "AdminSelfHostedModels|Self-hosted models are an experimental feature."
msgstr ""
msgid "AdminSelfHostedModels|Specify the URL endpoint where your self-hosted model is accessible"
msgstr ""
 
Loading
Loading
@@ -4005,6 +4008,9 @@ msgstr ""
msgid "AdminSelfHostedModels|You are about to delete the %{boldStart}%{modelName}%{boldEnd} self-hosted model. This action cannot be undone."
msgstr ""
 
msgid "AdminSelfHostedModels|You do not currently have any self-hosted models. %{linkStart}Add a self-hosted model%{linkEnd} to get started."
msgstr ""
msgid "AdminSelfHostedModels|Your self-hosted model was successfully deleted."
msgstr ""
 
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