diff --git a/addons/api/addon-test-support/handlers/cache-daemon-search.js b/addons/api/addon-test-support/handlers/cache-daemon-search.js index 23784fb76..36cf242bc 100644 --- a/addons/api/addon-test-support/handlers/cache-daemon-search.js +++ b/addons/api/addon-test-support/handlers/cache-daemon-search.js @@ -7,6 +7,7 @@ import sinon from 'sinon'; import { typeOf } from '@ember/utils'; import { resourceNames } from 'api/handlers/cache-daemon-handler'; import { singularize } from 'ember-inflector'; +import { underscore } from '@ember/string'; /** * This test helper can be used to help setup your sinon stubs in your tests. @@ -69,16 +70,18 @@ export default function setupStubs(hooks) { .withArgs('searchCacheDaemon') .onCall(i) .returns({ - [resourceName]: models.map((model) => { - // Use internal serializer to serialize the model correctly - // according to our mirage serializers - const modelData = - this.server.serializerOrRegistry.serialize(model); + [underscore(resourceNames[singularize(resourceName)])]: models.map( + (model) => { + // Use internal serializer to serialize the model correctly + // according to our mirage serializers + const modelData = + this.server.serializerOrRegistry.serialize(model); - // Serialize the data properly to standard JSON as that is what - // we're expecting from the cache daemon response - return JSON.parse(JSON.stringify(modelData)); - }), + // Serialize the data properly to standard JSON as that is what + // we're expecting from the cache daemon response + return JSON.parse(JSON.stringify(modelData)); + }, + ), }); }); }; diff --git a/addons/api/addon/handlers/cache-daemon-handler.js b/addons/api/addon/handlers/cache-daemon-handler.js index 792b0160a..21f543359 100644 --- a/addons/api/addon/handlers/cache-daemon-handler.js +++ b/addons/api/addon/handlers/cache-daemon-handler.js @@ -8,6 +8,7 @@ import { inject as service } from '@ember/service'; import { getOwner, setOwner } from '@ember/application'; import { generateMQLExpression } from '../utils/mql-query'; import { paginateResults } from '../utils/paginate-results'; +import { underscore } from '@ember/string'; /** * Not all types are yet supported by the cache daemon so we'll @@ -94,12 +95,14 @@ export default class CacheDaemonHandler { const sessionData = this.session.data?.authenticated; const auth_token_id = sessionData?.id; const token = sessionData?.token; + const resourceName = resourceNames[type]; + remainingQuery = { ...remainingQuery, query: searchQuery, auth_token_id, token, - resource: resourceNames[type], + resource: resourceName, }; let cacheDaemonResults = {}; @@ -130,7 +133,7 @@ export default class CacheDaemonHandler { } } else { __electronLog?.error( - 'Failed to search cache daemon; falling back to search controller', + `Failed to search cache daemon for ${resourceName}. Error:`, e.message, ); @@ -138,10 +141,7 @@ export default class CacheDaemonHandler { } } - // Currently returns with a singular top level field with resource name - // e.g. { targets: [...] } or { sessions: [..] } - // So this just unwraps to the array, or undefined - const [results] = Object.values(cacheDaemonResults); + const results = cacheDaemonResults[underscore(resourceName)]; const payload = { items: paginateResults(results, page, pageSize) }; const schema = store.modelFor(type); @@ -167,7 +167,15 @@ export default class CacheDaemonHandler { // This isn't conventional but is better than returning an ArrayProxy // or EmberArray since the ember store query method asserts it has to be an array // so we can't just return an object. - records.meta = { totalItems: results?.length ?? 0 }; + // Also include whether the results are incomplete or is still refreshing + // as part of the response + records.meta = { + totalItems: results?.length ?? 0, + isLoadIncomplete: cacheDaemonResults.incomplete ?? false, + // Sometimes the refresh status returns an error status if it takes too long but it's still refreshing + isRefreshing: cacheDaemonResults.refresh_status !== 'not-refreshing', + }; + return records; } default: diff --git a/addons/core/addon/styles/addon.scss b/addons/core/addon/styles/addon.scss index 614b5b825..544912585 100644 --- a/addons/core/addon/styles/addon.scss +++ b/addons/core/addon/styles/addon.scss @@ -7,7 +7,6 @@ display: flex; flex-wrap: wrap; align-items: center; - margin-bottom: 1rem; gap: 0.5rem; .filter-tag { @@ -27,18 +26,16 @@ margin-top: 3rem; } - .hds-segmented-group { + > * { margin-bottom: 1rem; + } + .hds-segmented-group { .hds-dropdown-toggle-button__text { white-space: nowrap; } } - .hds-table { - margin-bottom: 1rem; - } - .search-filtering-toolbar { display: flex; diff --git a/addons/core/translations/states/en-us.yaml b/addons/core/translations/states/en-us.yaml index c3d36f289..13eabdb4d 100644 --- a/addons/core/translations/states/en-us.yaml +++ b/addons/core/translations/states/en-us.yaml @@ -24,3 +24,6 @@ loading: title: Loading all items... description: All of your {resource} are still loading. Please wait while we finish loading everything on screen. generic-description: All of your resources are still loading. Please wait while we finish loading everything on screen. +incomplete-loading: + limit: We've reached the result limit. Please narrow down your search or filters if the result you're looking for is not shown. + refreshing: We're still currently loading the results. Please wait a moment before refreshing again. diff --git a/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js b/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js index 1a052925c..d6e8c5812 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js @@ -54,19 +54,6 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll ); } - /** - * Returns targets that are associated will all sessions the user has access to - * @returns {[TargetModel]} - */ - get availableTargets() { - const uniqueSessionTargetIds = new Set( - this.model.allSessions.map((session) => session.target_id), - ); - return this.model.allTargets.filter((target) => - uniqueSessionTargetIds.has(target.id), - ); - } - /** * Returns all status types for sessions * @returns {[object]} @@ -98,7 +85,7 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll get filters() { return { allFilters: { - targets: this.availableTargets, + targets: this.model.associatedTargets, status: this.sessionStatusOptions, scopes: this.availableScopes, }, diff --git a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js index cf03bc4df..8ee445da6 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js @@ -49,15 +49,6 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle // =methods - get showFilters() { - return ( - this.model.allTargets.length || - this.types.length || - this.search || - this.availableSessions.length - ); - } - /** * Returns true if model is empty but we have a search term or filters * @returns {boolean} @@ -85,13 +76,8 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle * @returns {[ScopeModel]} */ get availableScopes() { - const uniqueTargetScopeIds = new Set( - this.model.allTargets.map((target) => target.scope.id), - ); - - return this.model.projects.filter((project) => - uniqueTargetScopeIds.has(project.id), - ); + // TODO: Make use of implicit scopes or when scopes are added to cache daemon + return this.model.projects; } get availableSessionOptions() { diff --git a/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js b/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js index 4653a36c7..e4e41ca2b 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js +++ b/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js @@ -8,9 +8,10 @@ import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { STATUS_SESSION_ACTIVE, - STATUS_SESSION_PENDING, STATUS_SESSION_CANCELING, + STATUS_SESSION_PENDING, } from 'api/models/session'; +import chunk from 'lodash/chunk'; export default class ScopesScopeProjectsSessionsIndexRoute extends Route { // =services @@ -44,7 +45,6 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { }; allSessions; - allTargets; // =methods @@ -65,7 +65,7 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { /** * Loads queried sessions, the total number of sessions, all sessions, * all targets and all projects for filtering options for the current user. - * @return {Promise<{sessions: [SessionModel], projects: [ScopeModel], allSessions: [SessionModel], allTargets: [TargetModel], totalItems: number}>} + * @return {Promise<{sessions: [SessionModel], projects: [ScopeModel], allSessions: [SessionModel], associatedTargets: [TargetModel], totalItems: number}>} */ async model({ targets, status, scopes, page, pageSize }) { const projects = this.modelFor('scopes.scope.projects'); @@ -97,6 +97,7 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { page, pageSize, force_refresh: true, + max_result_set_size: -1, }; if (orgScope.isOrg && scopes.length === 0) { queryOptions.filter = orgFilter; @@ -104,36 +105,62 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { const sessions = await this.store.query('session', queryOptions); const totalItems = sessions.meta?.totalItems; - // Query all sessions and all targets for defining filtering values if entering route for the first time + // Query all sessions and associated targets for defining filtering values if entering route for the first time if (!this.allSessions?.length) { await this.getAllSessions(orgScope, scopes, orgFilter); } - if (!this.allTargets?.length) { - await this.getAllTargets(orgScope, orgFilter); - } + const associatedTargets = await this.getAssociatedTargets( + orgScope, + orgFilter, + ); return { sessions, projects, allSessions: this.allSessions, - allTargets: this.allTargets, + associatedTargets, totalItems, isCacheDaemonRunning: await this.ipc.invoke('isCacheDaemonRunning'), }; } - async getAllTargets(orgScope, orgFilter) { - const allTargetsQuery = { - scope_id: orgScope.id, - recursive: true, - force_refresh: true, - }; - if (orgScope.isOrg) { - allTargetsQuery.filter = orgFilter; + async getAssociatedTargets(orgScope) { + if (!this.allSessions) { + return []; } - this.allTargets = await this.store.query('target', allTargetsQuery, { - pushToStore: false, - }); + + const uniqueTargetIds = [ + ...new Set(this.allSessions.map((session) => session.target_id)), + ]; + // Chunk target IDs in case there's a lot of sessions as cache daemon syntax can't take too many + const chunkedTargetIds = chunk(uniqueTargetIds, 50); + + const associatedTargetsPromises = chunkedTargetIds.map((targetIds) => + this.store.query( + 'target', + { + scope_id: orgScope.id, + recursive: true, + force_refresh: true, + query: { + filters: { + id: { + logicalOperator: 'or', + values: targetIds.map((targetId) => ({ + equals: targetId, + })), + }, + }, + }, + }, + { + pushToStore: false, + }, + ), + ); + + const targetsArray = await Promise.all(associatedTargetsPromises); + return targetsArray.flat(); } async getAllSessions(orgScope, scopes, orgFilter) { @@ -146,6 +173,7 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { }, }, force_refresh: true, + max_result_set_size: -1, }; if (orgScope.isOrg && scopes.length === 0) { allSessionsQuery.filter = orgFilter; @@ -182,8 +210,8 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { const orgScope = this.modelFor('scopes.scope'); const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`; - await this.getAllTargets(orgScope, orgFilter); await this.getAllSessions(orgScope, [], orgFilter); + await this.getAssociatedTargets(orgScope); // Prime the store by searching for orgs only in case there are new org scopes; // otherwise we won't be able to correctly peek the org scopes for their display name in the UI. diff --git a/ui/desktop/app/routes/scopes/scope/projects/targets/index.js b/ui/desktop/app/routes/scopes/scope/projects/targets/index.js index a6a70ed76..a3d3642c0 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/targets/index.js +++ b/ui/desktop/app/routes/scopes/scope/projects/targets/index.js @@ -49,8 +49,6 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { }, }; - allTargets; - // =methods /** @@ -79,8 +77,12 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { * projects for filtering options. * * @returns {Promise<{totalItems: number, targets: [TargetModel], projects: [ScopeModel], allTargets: [TargetModel] }> } + * @return {Promise<{totalItems: number, targets: [TargetModel], projects: [ScopeModel], + * isCacheDaemonRunning: boolean, isLoadIncomplete: boolean, isRefreshing: boolean}>} */ async model({ search, scopes, availableSessions, types, page, pageSize }) { + const isCacheRunningPromise = this.ipc.invoke('isCacheDaemonRunning'); + const orgScope = this.modelFor('scopes.scope'); const projects = this.modelFor('scopes.scope.projects'); @@ -96,15 +98,7 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { filters.type.push({ equals: type }); }); - const aliasPromise = this.store.query('alias', { - scope_id: 'global', - force_refresh: true, - }); - const allTargetsPromise = !this.allTargets?.length - ? this.makeAllTargetsQuery(orgScope, orgFilter) - : Promise.resolve(); - - const sessions = await this.makeSessionQuery(orgScope, scopes, orgFilter); + const sessions = await this.getSessions(orgScope, scopes, orgFilter); this.addActiveSessionFilters(filters, availableSessions, sessions); const query = { @@ -119,20 +113,28 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { query.filter = orgFilter; } let targets = await this.store.query('target', query); - const totalItems = targets.meta?.totalItems; + const { totalItems, isLoadIncomplete, isRefreshing } = targets.meta; // Filter out targets to which users do not have the connect ability targets = targets.filter((target) => this.can.can('connect target', target), ); - const allTargets = await allTargetsPromise; - if (!this.allTargets?.length) { - // Filter out targets to which users do not have the connect ability - this.allTargets = allTargets.filter((target) => - target.authorized_actions.includes('authorize-session'), - ); - } + const aliasPromise = this.store.query('alias', { + scope_id: 'global', + force_refresh: true, + query: { + filters: { + destination_id: { + logicalOperator: 'or', + values: targets.map((target) => ({ + equals: target.id, + })), + }, + }, + }, + }); + // Load the aliases for the targets on the current page try { await aliasPromise; } catch (e) { @@ -144,13 +146,14 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { return { targets, projects, - allTargets: this.allTargets, totalItems, - isCacheDaemonRunning: await this.ipc.invoke('isCacheDaemonRunning'), + isLoadIncomplete, + isRefreshing, + isCacheDaemonRunning: await isCacheRunningPromise, }; } - async makeSessionQuery(orgScope, scopes, orgFilter) { + async getSessions(orgScope, scopes, orgFilter) { // Retrieve all sessions so that the session and activeSessions getters // in the target model always retrieve the most up-to-date sessions. const sessionQuery = { @@ -166,6 +169,7 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { }, }, force_refresh: true, + max_result_set_size: -1, }; if (orgScope.isOrg && scopes.length === 0) { sessionQuery.filter = orgFilter; @@ -173,27 +177,6 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { return this.store.query('session', sessionQuery); } - /** - * Get all the targets but only load them once when entering the route. Ideally we would lazy load it when needed - * but this can be revisited in the future. - * @param orgScope - * @param orgFilter - * @returns {Promise} - */ - async makeAllTargetsQuery(orgScope, orgFilter) { - // Query all targets for defining filtering values if entering route for first time - const query = { - scope_id: orgScope.id, - recursive: true, - force_refresh: true, - }; - if (orgScope.isOrg) { - query.filter = orgFilter; - } - const options = { pushToStore: false }; - return this.store.query('target', query, options); - } - /** * Add the filters for active sessions to the filter object. * @param filters @@ -255,14 +238,6 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { @action async refreshAll() { - const orgScope = this.modelFor('scopes.scope'); - const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`; - const allTargets = await this.makeAllTargetsQuery(orgScope, orgFilter); - // Filter out targets to which users do not have the connect ability - this.allTargets = allTargets.filter((target) => - target.authorized_actions.includes('authorize-session'), - ); - // Prime the store by searching for only orgs in case there are new org scopes; // otherwise we won't be able to correctly peek the org scopes for their display name in the UI. await this.store.query('scope', {}); diff --git a/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs b/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs index 97a391749..6775b115c 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs @@ -3,119 +3,118 @@ SPDX-License-Identifier: BUSL-1.1 }} -{{#if (or @model.sessions @model.allSessions)}} - {{#if @model.isCacheDaemonRunning}} -
- - - - - - - - - - {{#let (group-by itemOptions 'scopeModel') as |orgs|}} - {{#each orgs as |org|}} - - - {{org.key.displayName}} - - {{#each org.items as |project|}} - - {{project.displayName}} - - {{/each}} - {{/each}} - {{/let}} - - - - - - -
- - - {{/if}} - {{#if @model.sessions}} - - <:body as |B|> - - - - - - - - - {{B.data.target.displayName}} - - {{! + {{project.displayName}} + + {{/each}} + {{/each}} + {{/let}} + + + + + + + + + +{{/if}} +{{#if @model.sessions}} + + <:body as |B|> + + + + + + + + + {{B.data.target.displayName}} + + {{! Two if's here because: 1) Local proxy info is only relevant if the session is active or pending (aka isAvailable). Once the session @@ -126,50 +125,49 @@ from other devices (or even another tab), in which case we won't have the local proxy info available here. }} - - {{#if B.data.isAvailable}} - {{#if B.data.proxy}} - - {{/if}} - {{/if}} - - - - - - {{#if (can 'cancel session' B.data)}} - + {{#if B.data.isAvailable}} + {{#if B.data.proxy}} + {{/if}} - - - - - + + + + + {{#if (can 'cancel session' B.data)}} + + {{/if}} + + + + + +{{else if @model.allSessions}} + + + - {{else}} - - - - - {{/if}} + {{else}} diff --git a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs index 6bfbb7461..829284296 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs @@ -3,191 +3,199 @@ SPDX-License-Identifier: BUSL-1.1 }} -{{#if this.showFilters}} - {{#if @model.isCacheDaemonRunning}} -
- - - - - - - - - - - {{#let (group-by itemOptions 'scopeModel') as |orgs|}} - {{#each orgs as |org|}} - - - {{org.key.displayName}} - - {{#each org.items as |project|}} - - {{project.displayName}} - - {{/each}} - {{/each}} - {{/let}} - - - - - - -
- - {{/if}} - - {{#if @model.targets}} - - <:body as |B|> - - - - {{#if (can 'read model' B.data)}} - - {{B.data.displayName}} - - {{else}} - {{B.data.displayName}} - {{/if}} - {{#if B.data.description}} -

{{B.data.description}}

- {{/if}} -
-
- - {{truncate-list 'actions.more' B.data.associatedAliases}} - - - {{#if B.data.isActive}} - - {{/if}} - - - {{#if B.data.type}} - - {{/if}} - - -
- -
- {{#if B.data.project.name}} - - {{/if}} -
- -
- {{#if (can 'connect target' B.data)}} - {{#if (can 'read target' B.data)}} - - {{else}} - - {{/if}} - {{/if}} -
-
-
- -
- - - {{/if}} - {{#if this.noResults}} - - - + + - + + + + + + + + + {{#let (group-by itemOptions 'scopeModel') as |orgs|}} + {{#each orgs as |org|}} + + + {{org.key.displayName}} + + {{#each org.items as |project|}} + + {{project.displayName}} + + {{/each}} + {{/each}} + {{/let}} + + + + + + + + + {{#if @model.isLoadIncomplete}} + + {{t 'states.incomplete-loading.limit'}} + + {{/if}} + {{#if @model.isRefreshing}} + + {{t + 'states.incomplete-loading.refreshing' + }} + {{/if}} {{/if}} -{{#if this.noTargets}} + +{{#if @model.targets}} + + <:body as |B|> + + + + {{#if (can 'read model' B.data)}} + + {{B.data.displayName}} + + {{else}} + {{B.data.displayName}} + {{/if}} + {{#if B.data.description}} +

{{B.data.description}}

+ {{/if}} +
+
+ + {{truncate-list 'actions.more' B.data.associatedAliases}} + + + {{#if B.data.isActive}} + + {{/if}} + + + {{#if B.data.type}} + + {{/if}} + + +
+ +
+ {{#if B.data.project.name}} + + {{/if}} +
+ +
+ {{#if (can 'connect target' B.data)}} + {{#if (can 'read target' B.data)}} + + {{else}} + + {{/if}} + {{/if}} +
+
+
+ +
+ +{{/if}} +{{#if this.noResults}} + + + + +{{else if this.noTargets}} diff --git a/ui/desktop/electron-app/src/helpers/request-promise.js b/ui/desktop/electron-app/src/helpers/request-promise.js index 65041bde6..4516dd6ea 100644 --- a/ui/desktop/electron-app/src/helpers/request-promise.js +++ b/ui/desktop/electron-app/src/helpers/request-promise.js @@ -60,7 +60,7 @@ const unixSocketRequest = (options, reqBody) => if (statusCode < 200 || statusCode >= 400) { reject({ statusCode, - message: parsedResponse?.api_error ?? parsedResponse?.error, + message: parsedResponse?.message ?? parsedResponse?.error, }); } diff --git a/ui/desktop/tests/acceptance/projects/sessions/index-test.js b/ui/desktop/tests/acceptance/projects/sessions/index-test.js index eeee1b09f..1586c805e 100644 --- a/ui/desktop/tests/acceptance/projects/sessions/index-test.js +++ b/ui/desktop/tests/acceptance/projects/sessions/index-test.js @@ -186,7 +186,7 @@ module('Acceptance | projects | sessions | index', function (hooks) { test('visiting empty sessions', async function (assert) { this.server.db.sessions.remove(); - this.stubCacheDaemonSearch('sessions', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'sessions'); await visit(urls.projects); await click(`[href="${urls.sessions}"]`); @@ -371,14 +371,14 @@ module('Acceptance | projects | sessions | index', function (hooks) { 'sessions', 'sessions', 'targets', - 'aliases', - 'targets', 'sessions', 'targets', + 'aliases', { resource: 'sessions', func: () => [instances.session2], }, + 'targets', ); await visit(urls.globalSessions); diff --git a/ui/desktop/tests/acceptance/projects/targets/index-test.js b/ui/desktop/tests/acceptance/projects/targets/index-test.js index db0a11702..5ba046f5e 100644 --- a/ui/desktop/tests/acceptance/projects/targets/index-test.js +++ b/ui/desktop/tests/acceptance/projects/targets/index-test.js @@ -161,7 +161,7 @@ module('Acceptance | projects | targets | index', function (hooks) { setDefaultClusterUrl(this); this.ipcStub.withArgs('isCacheDaemonRunning').returns(true); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); }); test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) { @@ -207,7 +207,7 @@ module('Acceptance | projects | targets | index', function (hooks) { test('visiting targets list view with no targets', async function (assert) { this.server.db.targets.remove(); this.server.db.sessions.remove(); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.projects); @@ -219,7 +219,7 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user cannot navigate to a target without proper authorization', async function (assert) { instances.target.authorized_actions = instances.target.authorized_actions.filter((item) => item !== 'read'); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.projects); @@ -248,7 +248,7 @@ module('Acceptance | projects | targets | index', function (hooks) { instances.target.authorized_actions.filter( (item) => item !== 'authorize-session', ); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.projects); @@ -281,7 +281,7 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user can connect without target read permissions', async function (assert) { instances.target.authorized_actions = instances.target.authorized_actions.filter((item) => item !== 'read'); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); this.ipcStub.withArgs('cliExists').returns(true); this.ipcStub.withArgs('connect').returns({ session_id: instances.session.id, @@ -307,7 +307,7 @@ module('Acceptance | projects | targets | index', function (hooks) { instances.target.authorized_actions.filter((item) => item !== 'read'); this.ipcStub.withArgs('cliExists').returns(true); this.ipcStub.withArgs('connect').rejects(); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); const confirmService = this.owner.lookup('service:confirm'); confirmService.enabled = true; await visit(urls.projects); @@ -348,8 +348,6 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user can cancel a session from inside target sessions flyout', async function (assert) { this.stubCacheDaemonSearch( - 'aliases', - 'targets', 'sessions', 'targets', 'aliases', @@ -358,6 +356,7 @@ module('Acceptance | projects | targets | index', function (hooks) { func: () => [], }, 'targets', + 'aliases', ); await visit(urls.projects); @@ -387,7 +386,7 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user cannot cancel a session from inside target sessions flyout without permissions', async function (assert) { instances.session.authorized_actions = instances.session.authorized_actions.filter((item) => item !== 'cancel'); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.projects); await click(`[href="${urls.targets}"]`); @@ -425,7 +424,7 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user can navigate to session details from sessions table in flyout without permissions', async function (assert) { instances.session.authorized_actions = instances.session.authorized_actions.filter((item) => item !== 'read'); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.projects); await click(`[href="${urls.targets}"]`); @@ -447,8 +446,6 @@ module('Acceptance | projects | targets | index', function (hooks) { test('user can change org scope and only targets for that org will be displayed', async function (assert) { this.stubCacheDaemonSearch( - 'aliases', - 'targets', 'sessions', 'targets', 'aliases', @@ -457,6 +454,7 @@ module('Acceptance | projects | targets | index', function (hooks) { resource: 'targets', func: () => [instances.target], }, + 'aliases', ); await visit(urls.scopes.global); diff --git a/ui/desktop/tests/acceptance/projects/targets/target-test.js b/ui/desktop/tests/acceptance/projects/targets/target-test.js index 39b8eecbc..bed15c426 100644 --- a/ui/desktop/tests/acceptance/projects/targets/target-test.js +++ b/ui/desktop/tests/acceptance/projects/targets/target-test.js @@ -130,7 +130,7 @@ module('Acceptance | projects | targets | target', function (hooks) { setDefaultClusterUrl(this); this.ipcStub.withArgs('isCacheDaemonRunning').returns(true); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); }); test('user can connect to a target with an address', async function (assert) { diff --git a/ui/desktop/tests/acceptance/scopes-test.js b/ui/desktop/tests/acceptance/scopes-test.js index af0db0750..167e6c91b 100644 --- a/ui/desktop/tests/acceptance/scopes-test.js +++ b/ui/desktop/tests/acceptance/scopes-test.js @@ -143,7 +143,7 @@ module('Acceptance | scopes', function (hooks) { setDefaultClusterUrl(this); this.ipcStub.withArgs('isCacheDaemonRunning').returns(true); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); }); test('visiting index', async function (assert) { @@ -213,8 +213,6 @@ module('Acceptance | scopes', function (hooks) { test('can navigate among org scopes via header navigation', async function (assert) { assert.expect(3); this.stubCacheDaemonSearch( - 'aliases', - 'targets', 'sessions', 'targets', 'aliases', @@ -226,6 +224,7 @@ module('Acceptance | scopes', function (hooks) { 'aliases', 'sessions', 'targets', + 'aliases', ); await visit(urls.targets); @@ -264,7 +263,7 @@ module('Acceptance | scopes', function (hooks) { assert.expect(1); this.server.db.targets.remove(); this.server.db.sessions.remove(); - this.stubCacheDaemonSearch('aliases', 'targets', 'sessions', 'targets'); + this.stubCacheDaemonSearch('sessions', 'targets', 'aliases'); await visit(urls.targets);