diff --git a/ee/app/assets/javascripts/workspaces/admin_settings/components/availability_popover.vue b/ee/app/assets/javascripts/workspaces/admin_settings/components/availability_popover.vue new file mode 100644 index 0000000000000000000000000000000000000000..572d4a56a1c12998b65d208ced6633bd16bdb126 --- /dev/null +++ b/ee/app/assets/javascripts/workspaces/admin_settings/components/availability_popover.vue @@ -0,0 +1,27 @@ + + + + + + {{ $options.AGENT_CONFIG_NOTE_POPOVER_CONTENT }} + {{ $options.BLOCKING_AGENT_POPOVER_CONTENT }} + + + diff --git a/ee/app/assets/javascripts/workspaces/admin_settings/init_admin_settings_app.js b/ee/app/assets/javascripts/workspaces/admin_settings/init_admin_settings_app.js index 54e81abaa3c02ebe1a05ecd0b45093511db20f8f..b340f8711455d3852d4405aabc9e810c972a8a7c 100644 --- a/ee/app/assets/javascripts/workspaces/admin_settings/init_admin_settings_app.js +++ b/ee/app/assets/javascripts/workspaces/admin_settings/init_admin_settings_app.js @@ -1,16 +1,26 @@ import Vue from 'vue'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; +import { TYPE_ORGANIZATION } from '~/graphql_shared/constants'; +import { parseBoolean } from '~/lib/utils/common_utils'; + import WorkspacesAgentAvailabilityApp from './pages/app.vue'; const initWorkspacesAgentAvailabilityApp = () => { - const el = document.getElementById('js-workspaces-agent-availability-settings-body'); + const el = document.getElementById('js-workspaces-agent-availability-settings'); + + if (!el?.dataset) return null; - if (!el) return null; + const { organizationId, defaultExpanded } = el.dataset; return new Vue({ el, components: { WorkspacesAgentAvailabilityApp, }, + provide: { + organizationId: convertToGraphQLId(TYPE_ORGANIZATION, organizationId), + defaultExpanded: parseBoolean(defaultExpanded), + }, render(createElement) { return createElement(WorkspacesAgentAvailabilityApp); }, diff --git a/ee/app/assets/javascripts/workspaces/admin_settings/pages/app.vue b/ee/app/assets/javascripts/workspaces/admin_settings/pages/app.vue index f50a6239cf206ff580ecaded26236a33eb56b318..0e083f8d9ce32c37803f08c15ebcfabd961a30d8 100644 --- a/ee/app/assets/javascripts/workspaces/admin_settings/pages/app.vue +++ b/ee/app/assets/javascripts/workspaces/admin_settings/pages/app.vue @@ -1,15 +1,30 @@ - - - - {{ - getStatusText(item.status) - }} - - - - - {{ getAvailabilityText(item.availability) }} + + + {{ $options.SETTINGS_DESCRIPTION }} + + + + + + + {{ label }} + + + + + {{ item.name }} + + + {{ + getStatusText(item.status) + }} + + + + + {{ getAvailabilityText(item.availability) }} + + + + + {{ s__('Workspaces|No agents available') }} - - - - {{ s__('Workspaces|No agents available') }} - - + + + diff --git a/ee/app/views/admin/application_settings/workspaces/_agent_availability.html.haml b/ee/app/views/admin/application_settings/workspaces/_agent_availability.html.haml index 3a41cf7eda62b1ae9b58741ac84a38601968a9e2..7e7d9fd1448d54020ab3dbee17257937c3a93ab1 100644 --- a/ee/app/views/admin/application_settings/workspaces/_agent_availability.html.haml +++ b/ee/app/views/admin/application_settings/workspaces/_agent_availability.html.haml @@ -1,9 +1,3 @@ - return unless ::License.feature_available?(:remote_development) && ::Feature.enabled?(:workspaces_agents_availability_admin, current_user) -= render ::Layouts::SettingsBlockComponent.new(s_('Workspaces|Workspaces Agent Availability'), - id: 'js-workspaces-agent-availability-settings', - expanded: expanded_by_default?) do |setting| - - setting.with_description do - = s_('Workspaces|Configure which Kubernetes agents are available for new workspaces. These settings do not affect existing workspaces.') - - setting.with_body do - #js-workspaces-agent-availability-settings-body +#js-workspaces-agent-availability-settings{ data: { organization_id: Current.organization.id, default_expanded: expanded_by_default?.to_s } } diff --git a/ee/spec/features/admin/admin_settings_spec.rb b/ee/spec/features/admin/admin_settings_spec.rb index e5261eefcad9e40fa147785a1dff0e64e48e82ff..8185d5d906571e18d1e1b7f4371e0605c542009a 100644 --- a/ee/spec/features/admin/admin_settings_spec.rb +++ b/ee/spec/features/admin/admin_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin updates EE-only settings', feature_category: :shared do +RSpec.describe 'Admin updates EE-only settings', :with_current_organization, feature_category: :shared do include StubENV include Spec::Support::Helpers::ModalHelpers include ListboxHelpers diff --git a/ee/spec/frontend/workspaces/admin_settings/pages/app_spec.js b/ee/spec/frontend/workspaces/admin_settings/pages/app_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..aed43d2677fda154e70556f76827000cc2a8cad1 --- /dev/null +++ b/ee/spec/frontend/workspaces/admin_settings/pages/app_spec.js @@ -0,0 +1,44 @@ +import { nextTick } from 'vue'; +import { GlTableLite, GlLink } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import WorkspacesAgentAvailabilityApp from 'ee_component/workspaces/admin_settings/pages/app.vue'; +import AvailabilityPopover from 'ee_component/workspaces/admin_settings/components/availability_popover.vue'; + +const MOCK_ORG_ID = 'gid://gitlab/Organizations::Organization/1'; + +describe('workspaces/admin_settings/pages/app.vue', () => { + let wrapper; + + const buildWrapper = () => { + wrapper = mountExtended(WorkspacesAgentAvailabilityApp, { + provide: { + organizationId: MOCK_ORG_ID, + defaultExpanded: true, + }, + }); + }; + const findAgentsTable = () => wrapper.findComponent(GlTableLite); + const findAvailabilityPopover = () => wrapper.findComponent(AvailabilityPopover); + + describe('default', () => { + beforeEach(async () => { + buildWrapper(); + await nextTick(); + }); + + it('renders agents table', () => { + expect(findAgentsTable().exists()).toBe(true); + }); + + it('renders popover in availability header column', () => { + expect(findAvailabilityPopover().exists()).toBe(true); + }); + + it('renders agent name with link to the agent page', () => { + const nameElement = wrapper.findComponent(GlLink); + expect(nameElement.exists()).toBe(true); + // TODO: update once we implement query: https://gitlab.com/gitlab-org/gitlab/-/issues/513370 + expect(nameElement.attributes('href')).toBe('#'); + }); + }); +}); diff --git a/ee/spec/views/admin/application_settings/workspaces/_agent_availability.html.haml_spec.rb b/ee/spec/views/admin/application_settings/workspaces/_agent_availability.html.haml_spec.rb index 2cf14d3ae22c9e64361c65c51c9722ad198462bb..f61bea144ac50f074ceee4dfcd584b5611cb8192 100644 --- a/ee/spec/views/admin/application_settings/workspaces/_agent_availability.html.haml_spec.rb +++ b/ee/spec/views/admin/application_settings/workspaces/_agent_availability.html.haml_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' RSpec.describe 'admin/application_settings/_workspaces_agent_availability', feature_category: :workspaces do + let_it_be(:organization) { build_stubbed(:organization) } let_it_be(:user) { build_stubbed(:admin) } let_it_be(:app_settings) { build(:application_setting) } @@ -12,7 +13,11 @@ before do assign(:application_setting, app_settings) - allow(view).to receive(:current_user).and_return(user) + allow(view).to receive_messages( + current_user: user, + expanded_by_default?: true + ) + ::Current.organization = organization end [true, false].each do |license_enabled| @@ -34,4 +39,14 @@ end end end + + context 'when settings is rendered' do + before do + stub_licensed_features(remote_development: true) + stub_feature_flags(workspaces_agents_availability_admin: true) + end + + it { is_expected.to have_selector("[data-organization-id='#{organization.id}']") } + it { is_expected.to have_selector("[data-default-expanded='true']") } + end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 361752fcf7ccaed6bc4938f94634e4eae1829fed..540cb18f2b61dbbf1bec73c79c8abaf09aadacbe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -70304,6 +70304,9 @@ msgstr "" msgid "Workspaces|Blocking an agent doesn't delete it. Agents can only be deleted in the project where they were created." msgstr "" +msgid "Workspaces|Blocking an agent doesn't delete it. Agents can only be deleted in the project where they were created. In addition, existing workspaces using a blocked agent will continue to run." +msgstr "" + msgid "Workspaces|Cancel" msgstr "" @@ -70388,6 +70391,9 @@ msgstr "" msgid "Workspaces|If your devfile is not in the root directory of your project, specify a relative path." msgstr "" +msgid "Workspaces|In order to make an agent available/blocked, workspaces must be enabled in the agent's configuration." +msgstr "" + msgid "Workspaces|Instant development environments" msgstr ""
{{ $options.AGENT_CONFIG_NOTE_POPOVER_CONTENT }}
{{ $options.BLOCKING_AGENT_POPOVER_CONTENT }}
{{ getAvailabilityText(item.availability) }}