diff --git a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-list.hbs b/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-list.hbs deleted file mode 100644 index 3ac4ac8d9ba..00000000000 --- a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-list.hbs +++ /dev/null @@ -1,25 +0,0 @@ -
- {{#if @apiKeys}} - - - - - - - - - - {{#each @apiKeys as |apiKey|}} - - {{/each}} - -
{{i18n "admin.api.key"}}{{i18n "admin.api.description"}}{{i18n "admin.api.user"}}{{i18n "admin.api.created"}}{{i18n "admin.api.last_used"}}
- {{else}} - - {{/if}} -
\ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-new.gjs b/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-new.gjs deleted file mode 100644 index 923c97e5ee6..00000000000 --- a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-new.gjs +++ /dev/null @@ -1,318 +0,0 @@ -import Component from "@glimmer/component"; -import { cached, tracked } from "@glimmer/tracking"; -import { concat, fn, hash } from "@ember/helper"; -import { action } from "@ember/object"; -import { service } from "@ember/service"; -import { eq } from "truth-helpers"; -import BackButton from "discourse/components/back-button"; -import ConditionalLoadingSection from "discourse/components/conditional-loading-section"; -import DButton from "discourse/components/d-button"; -import Form from "discourse/components/form"; -import { ajax } from "discourse/lib/ajax"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import { i18n } from "discourse-i18n"; -import ApiKeyUrlsModal from "admin/components/modal/api-key-urls"; -import EmailGroupUserChooser from "select-kit/components/email-group-user-chooser"; -import DTooltip from "float-kit/components/d-tooltip"; - -export default class AdminConfigAreasApiKeysNew extends Component { - @service router; - @service modal; - @service store; - - @tracked username; - @tracked loadingScopes = false; - @tracked scopes = null; - - userModes = [ - { id: "all", name: i18n("admin.api.all_users") }, - { id: "single", name: i18n("admin.api.single_user") }, - ]; - - scopeModes = [ - { id: "global", name: i18n("admin.api.scopes.global") }, - { id: "read_only", name: i18n("admin.api.scopes.read_only") }, - { id: "granular", name: i18n("admin.api.scopes.granular") }, - ]; - - globalScopes = null; - - constructor() { - super(...arguments); - this.#loadScopes(); - } - - @cached - get formData() { - let scopes = Object.keys(this.scopes).reduce((result, resource) => { - result[resource] = this.scopes[resource].map((scope) => { - const params = scope.params - ? scope.params.reduce((acc, param) => { - acc[param] = undefined; - return acc; - }, {}) - : {}; - - return { - key: scope.key, - enabled: undefined, - urls: scope.urls, - ...(params && { params }), - }; - }); - return result; - }, {}); - - return { - user_mode: "all", - scope_mode: "global", - scopes, - }; - } - - @action - updateUsername(field, selected) { - this.username = selected[0]; - field.set(this.username); - } - - @action - async save(data) { - const payload = { description: data.description }; - - if (data.user_mode === "single") { - payload.username = data.user; - } - - if (data.scope_mode === "granular") { - payload.scopes = this.#selectedScopes(data.scopes); - } else if (data.scope_mode === "read_only") { - payload.scopes = this.globalScopes.filter( - (scope) => scope.key === "read" - ); - } - - try { - await this.store.createRecord("api-key").save(payload); - this.router.transitionTo("adminApiKeys"); - } catch (error) { - popupAjaxError(error); - } - } - - #selectedScopes(scopes) { - const enabledScopes = []; - - for (const [resource, resourceScopes] of Object.entries(scopes)) { - enabledScopes.push( - resourceScopes - .filter((s) => s.enabled) - .map((s) => { - return { - scope_id: `${resource}:${s.key}`, - key: s.key, - name: s.key, - params: Object.keys(s.params), - ...s.params, - }; - }) - ); - } - - return enabledScopes.flat(); - } - - @action - async showURLs(urls) { - await this.modal.show(ApiKeyUrlsModal, { - model: { urls }, - }); - } - - async #loadScopes() { - try { - this.loadingScopes = true; - const data = await ajax("/admin/api/keys/scopes.json"); - - this.globalScopes = data.scopes.global; - delete data.scopes.global; - - this.scopes = data.scopes; - } catch (error) { - popupAjaxError(error); - } finally { - this.loadingScopes = false; - } - } - - -} diff --git a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-show.gjs b/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-show.gjs deleted file mode 100644 index 6c94f4a2ec7..00000000000 --- a/app/assets/javascripts/admin/addon/components/admin-config-areas/api-keys-show.gjs +++ /dev/null @@ -1,241 +0,0 @@ -import Component from "@glimmer/component"; -import { tracked } from "@glimmer/tracking"; -import { Input } from "@ember/component"; -import { concat, fn } from "@ember/helper"; -import { on } from "@ember/modifier"; -import { action, get } from "@ember/object"; -import { LinkTo } from "@ember/routing"; -import { service } from "@ember/service"; -import BackButton from "discourse/components/back-button"; -import DButton from "discourse/components/d-button"; -import avatar from "discourse/helpers/avatar"; -import formatDate from "discourse/helpers/format-date"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import { i18n } from "discourse-i18n"; -import AdminFormRow from "admin/components/admin-form-row"; -import ApiKeyUrlsModal from "admin/components/modal/api-key-urls"; -import DTooltip from "float-kit/components/d-tooltip"; - -export default class AdminConfigAreasApiKeysShow extends Component { - @service modal; - @service router; - - @tracked editingDescription = false; - @tracked scopes = this.args.apiKey.api_key_scopes; - newDescription = ""; - - @action - async revokeKey(key) { - try { - await key.revoke(); - } catch (error) { - popupAjaxError(error); - } - } - - @action - async undoRevokeKey(key) { - try { - await key.undoRevoke(); - } catch (error) { - popupAjaxError(error); - } - } - - @action - async deleteKey(key) { - try { - await key.destroyRecord(); - this.router.transitionTo("adminApiKeys.index"); - } catch (error) { - popupAjaxError(error); - } - } - - @action - async showURLs(urls) { - await this.modal.show(ApiKeyUrlsModal, { - model: { urls }, - }); - } - - @action - toggleEditDescription() { - this.editingDescription = !this.editingDescription; - this.newDescription = this.args.apiKey.description; - } - - @action - async saveDescription() { - try { - await this.args.apiKey.save({ description: this.newDescription }); - this.editingDescription = false; - } catch (error) { - popupAjaxError(error); - } - } - - @action - setNewDescription(event) { - this.newDescription = event.currentTarget.value; - } - - -} diff --git a/app/assets/javascripts/admin/addon/components/api-key-item.gjs b/app/assets/javascripts/admin/addon/components/api-key-item.gjs deleted file mode 100644 index 9407dade744..00000000000 --- a/app/assets/javascripts/admin/addon/components/api-key-item.gjs +++ /dev/null @@ -1,137 +0,0 @@ -import Component from "@glimmer/component"; -import { tracked } from "@glimmer/tracking"; -import { fn } from "@ember/helper"; -import { action } from "@ember/object"; -import { LinkTo } from "@ember/routing"; -import { service } from "@ember/service"; -import DButton from "discourse/components/d-button"; -import DropdownMenu from "discourse/components/dropdown-menu"; -import avatar from "discourse/helpers/avatar"; -import formatDate from "discourse/helpers/format-date"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import { i18n } from "discourse-i18n"; -import DMenu from "float-kit/components/d-menu"; - -export default class ApiKeysList extends Component { - @service router; - - @tracked apiKey = this.args.apiKey; - - @action - onRegisterApi(api) { - this.dMenu = api; - } - - @action - async revokeKey(key) { - try { - await key.revoke(); - await this.dMenu.close(); - } catch (error) { - popupAjaxError(error); - } - } - - @action - async undoRevokeKey(key) { - try { - await key.undoRevoke(); - await this.dMenu.close(); - } catch (error) { - popupAjaxError(error); - } - } - - @action - edit() { - this.router.transitionTo("adminApiKeys.show", this.apiKey); - } - - -} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-api-keys-show.js b/app/assets/javascripts/admin/addon/controllers/admin-api-keys-show.js new file mode 100644 index 00000000000..bcfcc4117fd --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-api-keys-show.js @@ -0,0 +1,77 @@ +import Controller from "@ember/controller"; +import { action } from "@ember/object"; +import { empty } from "@ember/object/computed"; +import { service } from "@ember/service"; +import { isEmpty } from "@ember/utils"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import ApiKeyUrlsModal from "../components/modal/api-key-urls"; + +export default class AdminApiKeysShowController extends Controller.extend( + bufferedProperty("model") +) { + @service router; + @service modal; + + @empty("model.id") isNew; + + @action + saveDescription() { + const buffered = this.buffered; + const attrs = buffered.getProperties("description"); + + this.model + .save(attrs) + .then(() => { + this.set("editingDescription", false); + this.rollbackBuffer(); + }) + .catch(popupAjaxError); + } + + @action + cancel() { + const id = this.get("userField.id"); + if (isEmpty(id)) { + this.destroyAction(this.userField); + } else { + this.rollbackBuffer(); + this.set("editing", false); + } + } + + @action + editDescription() { + this.toggleProperty("editingDescription"); + if (!this.editingDescription) { + this.rollbackBuffer(); + } + } + + @action + revokeKey(key) { + key.revoke().catch(popupAjaxError); + } + + @action + deleteKey(key) { + key + .destroyRecord() + .then(() => this.router.transitionTo("adminApiKeys.index")) + .catch(popupAjaxError); + } + + @action + undoRevokeKey(key) { + key.undoRevoke().catch(popupAjaxError); + } + + @action + showURLs(urls) { + this.modal.show(ApiKeyUrlsModal, { + model: { + urls, + }, + }); + } +} diff --git a/app/assets/javascripts/admin/addon/models/api-key.js b/app/assets/javascripts/admin/addon/models/api-key.js index 228682544fd..fb82d7873f3 100644 --- a/app/assets/javascripts/admin/addon/models/api-key.js +++ b/app/assets/javascripts/admin/addon/models/api-key.js @@ -6,7 +6,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import AdminUser from "admin/models/admin-user"; export default class ApiKey extends RestModel { - @fmt("truncated_key", "%@ ...") truncatedKey; + @fmt("truncated_key", "%@...") truncatedKey; @computed("_user") get user() { @@ -21,19 +21,6 @@ export default class ApiKey extends RestModel { } } - @computed("_created_by") - get createdBy() { - return this._created_by; - } - - set created_by(value) { - if (value && !(value instanceof AdminUser)) { - this.set("_created_by", AdminUser.create(value)); - } else { - this.set("_created_by", value); - } - } - @discourseComputed("description") shortDescription(description) { if (!description || description.length < 40) { diff --git a/app/assets/javascripts/admin/addon/routes/admin-api-keys-new.js b/app/assets/javascripts/admin/addon/routes/admin-api-keys-new.js index 86aaabcecab..44ebc9066b5 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-api-keys-new.js +++ b/app/assets/javascripts/admin/addon/routes/admin-api-keys-new.js @@ -1,3 +1,7 @@ import Route from "@ember/routing/route"; -export default class AdminApiKeysNewRoute extends Route {} +export default class AdminApiKeysNewRoute extends Route { + model() { + return this.store.createRecord("api-key"); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-api-keys.js b/app/assets/javascripts/admin/addon/routes/admin-api-keys.js index 56618863d6d..4467bca5c1a 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-api-keys.js +++ b/app/assets/javascripts/admin/addon/routes/admin-api-keys.js @@ -1,3 +1,17 @@ +import { action } from "@ember/object"; import Route from "@ember/routing/route"; +import { service } from "@ember/service"; -export default class AdminApiKeysRoute extends Route {} +export default class AdminApiKeysRoute extends Route { + @service router; + + @action + show(apiKey) { + this.router.transitionTo("adminApiKeys.show", apiKey.id); + } + + @action + new() { + this.router.transitionTo("adminApiKeys.new"); + } +} diff --git a/app/assets/javascripts/admin/addon/templates/api-keys-index.hbs b/app/assets/javascripts/admin/addon/templates/api-keys-index.hbs index a6c7054b341..169bf25277a 100644 --- a/app/assets/javascripts/admin/addon/templates/api-keys-index.hbs +++ b/app/assets/javascripts/admin/addon/templates/api-keys-index.hbs @@ -1 +1,104 @@ - \ No newline at end of file + + +{{#if this.model}} + + + + + + + + + + + + + {{#each this.model as |k|}} + + + + + + + + + + {{/each}} + +
{{i18n "admin.api.key"}}{{i18n "admin.api.description"}}{{i18n "admin.api.user"}}{{i18n "admin.api.created"}}{{i18n "admin.api.last_used"}}{{i18n "admin.site_settings.table_column_heading.status"}} 
+ {{k.truncatedKey}} + +
{{i18n + "admin.api.description" + }}
+ {{k.shortDescription}} +
+
{{i18n + "admin.api.user" + }}
+ {{#if k.user}} + + {{avatar k.user imageSize="small"}} + + {{else}} + {{i18n "admin.api.all_users"}} + {{/if}} +
+
{{i18n + "admin.api.created" + }}
+ {{format-date k.created_at}} +
+
{{i18n + "admin.api.last_used" + }}
+ {{#if k.last_used_at}} + {{format-date k.last_used_at}} + {{else}} + {{i18n "admin.api.never_used"}} + {{/if}} +
+
{{i18n + "admin.site_settings.table_column_heading.status" + }}
+ {{#if k.revoked_at}} +
+
+
+
+ {{i18n "admin.api.revoked"}} +
+
+ {{/if}} +
+ + {{#if k.revoked_at}} + + {{else}} + + {{/if}} +
+
+ + +{{else}} +

{{i18n "admin.api.none"}}

+{{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/api-keys-new.hbs b/app/assets/javascripts/admin/addon/templates/api-keys-new.hbs index d910ce0ca18..f5176a87d01 100644 --- a/app/assets/javascripts/admin/addon/templates/api-keys-new.hbs +++ b/app/assets/javascripts/admin/addon/templates/api-keys-new.hbs @@ -1 +1,132 @@ - \ No newline at end of file + + {{d-icon "arrow-left"}} + {{i18n "admin.api.all_api_keys"}} + + +
+ {{#if this.model.id}} + +
{{this.model.key}}
+
+ + {{i18n "admin.api.not_shown_again"}} + + + + + {{else}} + + + + + + + + + {{#if this.showUserSelector}} + + + + {{/if}} + + + + + {{#if (eq this.scopeMode "read_only")}} +

{{i18n "admin.api.scopes.descriptions.global.read"}}

+ {{else if (eq this.scopeMode "global")}} +

{{i18n "admin.api.scopes.global_description"}}

+ {{/if}} +
+ + {{#if (eq this.scopeMode "granular")}} +

{{i18n "admin.api.scopes.title"}}

+

{{i18n "admin.api.scopes.description"}}

+ + + + + + + + + + + {{#each-in this.scopes as |resource actions|}} + + + + + + + {{#each actions as |act|}} + + + + + + + {{/each}} + {{/each-in}} + +
{{i18n "admin.api.scopes.allowed_urls"}}{{i18n "admin.api.scopes.optional_allowed_parameters"}}
{{resource}}
+
{{act.name}}
+ +
+ + + {{#each act.params as |p|}} + + {{/each}} +
+ {{/if}} + + + {{/if}} +
\ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/api-keys-show.hbs b/app/assets/javascripts/admin/addon/templates/api-keys-show.hbs index 1b141dd3301..342e8f1d729 100644 --- a/app/assets/javascripts/admin/addon/templates/api-keys-show.hbs +++ b/app/assets/javascripts/admin/addon/templates/api-keys-show.hbs @@ -1 +1,159 @@ - \ No newline at end of file + + {{d-icon "arrow-left"}} + {{i18n "admin.api.all_api_keys"}} + + +
+ + {{#if this.model.revoked_at}}{{d-icon "circle-xmark"}}{{/if}} + {{this.model.truncatedKey}} + + + + {{#if this.editingDescription}} + + {{else}} + + {{if + this.model.description + this.model.description + (i18n "admin.api.no_description") + }} + + {{/if}} + +
+ {{#if this.editingDescription}} + + + {{else}} + + {{/if}} +
+
+ + + {{#if this.model.user}} + + {{avatar this.model.user imageSize="small"}} + {{this.model.user.username}} + + {{else}} + {{i18n "admin.api.all_users"}} + {{/if}} + + + + {{format-date this.model.created_at leaveAgo="true"}} + + + + {{format-date this.model.updated_at leaveAgo="true"}} + + + + {{#if this.model.last_used_at}} + {{format-date this.model.last_used_at leaveAgo="true"}} + {{else}} + {{i18n "admin.api.never_used"}} + {{/if}} + + + + {{#if this.model.revoked_at}} + {{format-date this.model.revoked_at leaveAgo="true"}} + {{else}} + {{i18n "no_value"}} + {{/if}} +
+ {{#if this.model.revoked_at}} + + + {{else}} + + {{/if}} +
+
+ + {{#if this.model.api_key_scopes.length}} +

{{i18n "admin.api.scopes.title"}}

+ + + + + + + + + + + + {{#each this.model.api_key_scopes as |scope|}} + + + + + + + {{/each}} + +
{{i18n "admin.api.scopes.resource"}}{{i18n "admin.api.scopes.action"}}{{i18n "admin.api.scopes.allowed_urls"}}{{i18n "admin.api.scopes.allowed_parameters"}}
{{scope.resource}} + {{scope.action}} + + + + + {{#each scope.parameters as |p|}} +
+ {{p}}: + {{#if (get scope.allowed_parameters p)}} + {{get scope.allowed_parameters p}} + {{else}} + {{i18n "admin.api.scopes.any_parameter"}} + {{/if}} +
+ {{/each}} +
+ {{/if}} +
\ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/api-keys.hbs b/app/assets/javascripts/admin/addon/templates/api-keys.hbs index 820565bb47d..23cc9343fcb 100644 --- a/app/assets/javascripts/admin/addon/templates/api-keys.hbs +++ b/app/assets/javascripts/admin/addon/templates/api-keys.hbs @@ -1,21 +1,3 @@ -
- - <:breadcrumbs> - - - <:actions as |actions|> - - - - -
- {{outlet}} -
-
\ No newline at end of file + + {{outlet}} + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/api.hbs b/app/assets/javascripts/admin/addon/templates/api.hbs new file mode 100644 index 00000000000..00c46903ac1 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/api.hbs @@ -0,0 +1,8 @@ + + + + + +
+ {{outlet}} +
\ No newline at end of file diff --git a/app/assets/stylesheets/common/admin/admin_table.scss b/app/assets/stylesheets/common/admin/admin_table.scss index ea04fbad7e9..1fb5876b86f 100644 --- a/app/assets/stylesheets/common/admin/admin_table.scss +++ b/app/assets/stylesheets/common/admin/admin_table.scss @@ -96,14 +96,6 @@ } } - &__badge { - background-color: var(--primary-low); - border-radius: var(--d-border-radius); - font-size: var(--font-down-1); - margin-left: var(--space-1); - padding: var(--space-2); - } - // Success badge .status-label.--success { background-color: var(--success-low); diff --git a/app/controllers/admin/api_controller.rb b/app/controllers/admin/api_controller.rb index 04ed1684c92..f02b2464bcd 100644 --- a/app/controllers/admin/api_controller.rb +++ b/app/controllers/admin/api_controller.rb @@ -14,7 +14,6 @@ class Admin::ApiController < Admin::AdminController ApiKey .where(hidden: false) .includes(:user) - .includes(:created_by) .order("revoked_at DESC NULLS FIRST, created_at DESC") .offset(offset) .limit(limit) diff --git a/app/serializers/api_key_serializer.rb b/app/serializers/api_key_serializer.rb index f5de99ff410..d1ccac58de0 100644 --- a/app/serializers/api_key_serializer.rb +++ b/app/serializers/api_key_serializer.rb @@ -11,7 +11,6 @@ class ApiKeySerializer < ApplicationSerializer :revoked_at has_one :user, serializer: BasicUserSerializer, embed: :objects - has_one :created_by, serializer: BasicUserSerializer, embed: :objects has_many :api_key_scopes, serializer: ApiKeyScopeSerializer, embed: :objects def include_user_id? diff --git a/app/serializers/basic_api_key_serializer.rb b/app/serializers/basic_api_key_serializer.rb index cfecc068c8e..e8f194eccd3 100644 --- a/app/serializers/basic_api_key_serializer.rb +++ b/app/serializers/basic_api_key_serializer.rb @@ -4,5 +4,4 @@ class BasicApiKeySerializer < ApplicationSerializer attributes :id, :truncated_key, :description, :created_at, :last_used_at, :revoked_at has_one :user, serializer: BasicUserSerializer, embed: :objects - has_one :created_by, serializer: BasicUserSerializer, embed: :objects end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 106a65f669a..a55417b9ac2 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5396,20 +5396,6 @@ en: none_selected: "Select a group to get started" no_custom_groups: "Create a new custom group" - api_keys: - title: "API Keys" - description: "The API keys feature lets you securely integrate Discourse with external systems and automate actions. Admins can create keys with specific scopes to control access to resources and sensitive data. Scopes limit functionality, ensuring enhanced security." - add: "Add API key" - edit: "Edit" - save: "Save" - cancel: "Cancel" - back: "Back to API keys" - revoke: "Revoke" - undo_revoke: "Undo revoke" - revoked: "Revoked" - delete: Permanently delete - no_api_keys: "You don't have any API keys yet." - api: generate_master: "Generate Master API Key" none: "There are no active API keys right now." @@ -5417,30 +5403,30 @@ en: title: "API" key: "Key" keys: "Keys" - created: Created by + created: Created updated: Updated - last_used: Last used - never_used: Never + last_used: Last Used + never_used: (never) generate: "Generate" - undo_revoke: "Undo revoke" + undo_revoke: "Undo Revoke" revoke: "Revoke" - all_users: "All users" + all_users: "All Users" active_keys: "Active API Keys" manage_keys: Manage Keys show_details: Details description: Description no_description: (no description) all_api_keys: All API Keys - user_mode: User level + user_mode: User Level scope_mode: Scope impersonate_all_users: Impersonate any user - single_user: "Single user" + single_user: "Single User" user_placeholder: Enter username description_placeholder: What will this key be used for? save: Save new_key: New API Key revoked: Revoked - delete: Permanently delete + delete: Permanently Delete not_shown_again: This key will not be displayed again. Make sure you take a copy before continuing. continue: Continue scopes: @@ -5454,8 +5440,8 @@ en: global_description: API key has no restriction and all endpoints are accessible. resource: Resource action: Action - allowed_parameters: Allowed parameters - optional_allowed_parameters: Allowed parameters (optional) + allowed_parameters: Allowed Parameters + optional_allowed_parameters: Allowed Parameters (optional) any_parameter: (any parameter) allowed_urls: Allowed URLs descriptions: diff --git a/spec/system/admin_api_keys_spec.rb b/spec/system/admin_api_keys_spec.rb deleted file mode 100644 index c4a0e0146b4..00000000000 --- a/spec/system/admin_api_keys_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -#frozen_string_literal: true - -describe "Admin API Keys Page", type: :system do - fab!(:current_user) { Fabricate(:admin) } - - let(:api_keys_page) { PageObjects::Pages::AdminApiKeys.new } - let(:dialog) { PageObjects::Components::Dialog.new } - - before do - Fabricate(:api_key, description: "Integration") - - sign_in(current_user) - end - - it "shows a list of API keys" do - api_keys_page.visit_page - - expect(api_keys_page).to have_api_key_listed("Integration") - end - - it "can add a new API key" do - api_keys_page.visit_page - api_keys_page.add_api_key(description: "Second Integration") - - expect(api_keys_page).to have_api_key_listed("Second Integration") - end - - it "can edit existing API keys" do - api_keys_page.visit_page - api_keys_page.click_edit("Integration") - api_keys_page.edit_description("Old Integration") - api_keys_page.click_back - - expect(api_keys_page).to have_api_key_listed("Old Integration") - end - - it "can revoke API keys" do - api_keys_page.visit_page - api_keys_page.click_edit("Integration") - api_keys_page.click_revoke - api_keys_page.click_back - - expect(api_keys_page).to have_revoked_api_key_listed("Integration") - end - - it "can undo revokation of API keys" do - api_keys_page.visit_page - api_keys_page.click_edit("Integration") - api_keys_page.click_revoke - api_keys_page.click_unrevoke - api_keys_page.click_back - - expect(api_keys_page).to have_unrevoked_api_key_listed("Integration") - end - - it "can permanently delete revoked API keys" do - api_keys_page.visit_page - api_keys_page.click_edit("Integration") - api_keys_page.click_revoke - api_keys_page.click_delete - - expect(api_keys_page).to have_current_path("/admin/api/keys") - expect(api_keys_page).to have_no_api_key_listed("Integration") - end -end diff --git a/spec/system/page_objects/admin_api_keys.rb b/spec/system/page_objects/admin_api_keys.rb deleted file mode 100644 index 1696f442bac..00000000000 --- a/spec/system/page_objects/admin_api_keys.rb +++ /dev/null @@ -1,87 +0,0 @@ -# frozen_string_literal: true - -module PageObjects - module Pages - class AdminApiKeys < PageObjects::Pages::Base - def visit_page - page.visit "/admin/api/keys" - self - end - - def has_api_key_listed?(name) - page.has_css?(table_selector, text: name) - end - - def has_revoked_api_key_listed?(name) - row = page.find(table_selector, text: name) - row.has_css?(badge_selector, text: I18n.t("admin_js.admin.api_keys.revoked")) - end - - def has_unrevoked_api_key_listed?(name) - row = page.find(table_selector, text: name) - row.has_no_css?(badge_selector, text: I18n.t("admin_js.admin.api_keys.revoked")) - end - - def has_no_api_key_listed?(name) - page.has_no_css?(table_selector, text: name) - end - - def add_api_key(description:) - page.find(header_actions_selector, text: I18n.t("admin_js.admin.api_keys.add")).click - - form = page.find(".form-kit") - form.find(description_field_selector).fill_in(with: description) - form.find(".save").click - end - - def click_edit(description) - row = page.find(row_selector, text: description) - row.find("button", text: I18n.t("admin_js.admin.api_keys.edit")).click - end - - def click_revoke - page.find("button", text: I18n.t("admin_js.admin.api_keys.revoke")).click - end - - def click_unrevoke - page.find("button", text: I18n.t("admin_js.admin.api_keys.undo_revoke")).click - end - - def click_delete - page.find("button", text: I18n.t("admin_js.admin.api_keys.delete")).click - end - - def edit_description(new_description) - page.find("button", text: I18n.t("admin_js.admin.api_keys.edit")).click - page.find(description_field_selector).fill_in(with: new_description) - page.find("button", text: I18n.t("admin_js.admin.api_keys.save")).click - end - - def click_back - page.find("a.back-button").click - end - - private - - def table_selector - ".admin-api_keys__items" - end - - def row_selector - ".d-admin-row__content" - end - - def badge_selector - ".d-admin-table__badge" - end - - def header_actions_selector - ".d-page-header__actions" - end - - def description_field_selector - "input[name='description']" - end - end - end -end