diff --git a/addons/api/addon/models/session.js b/addons/api/addon/models/session.js index 6498634fc..6096a8745 100644 --- a/addons/api/addon/models/session.js +++ b/addons/api/addon/models/session.js @@ -128,7 +128,7 @@ export default class SessionModel extends GeneratedSessionModel { * @type {boolean} */ @computed('isActive', 'isPending') - get isCancelable() { + get isAvailable() { return this.isActive || this.isPending; } diff --git a/addons/api/tests/unit/models/session-test.js b/addons/api/tests/unit/models/session-test.js index 26b016866..793fe52d8 100644 --- a/addons/api/tests/unit/models/session-test.js +++ b/addons/api/tests/unit/models/session-test.js @@ -13,7 +13,7 @@ module('Unit | Model | session', function (hooks) { let store = this.owner.lookup('service:store'); let model = store.createRecord('session', {}); assert.ok(model); - assert.notOk(model.isCancelable); + assert.notOk(model.isAvailable); }); test('it allows cancellation of an active session', function (assert) { @@ -21,7 +21,7 @@ module('Unit | Model | session', function (hooks) { let model = store.createRecord('session', { status: 'active', }); - assert.ok(model.isCancelable); + assert.ok(model.isAvailable); }); test('it allows cancellation of a pending session', function (assert) { @@ -29,7 +29,7 @@ module('Unit | Model | session', function (hooks) { let model = store.createRecord('session', { status: 'pending', }); - assert.ok(model.isCancelable); + assert.ok(model.isAvailable); }); test('it computes isActive', function (assert) { diff --git a/ui/admin/app/templates/scopes/scope/sessions/index.hbs b/ui/admin/app/templates/scopes/scope/sessions/index.hbs index 930a520b3..a2c5db77c 100644 --- a/ui/admin/app/templates/scopes/scope/sessions/index.hbs +++ b/ui/admin/app/templates/scopes/scope/sessions/index.hbs @@ -122,7 +122,7 @@ - {{#if sessionAggregate.session.isCancelable}} + {{#if sessionAggregate.session.isAvailable}}
{{#if @model.host}} -
-
- {{t 'resources.host.details'}} -
- - {{! Host name }} - {{#if @model.host.name}} - - {{@model.host.name}} - - {{/if}} - {{! Host description }} - {{#if @model.host.description}} - - {{@model.host.description}} - - {{/if}} - {{! Host address }} - {{#if @model.host.address}} - - {{@model.host.address}} - - {{/if}} - {{! Host ID }} - - - {{@model.host.id}} - - - +
+ {{t 'resources.host.details'}}
+ + {{! Host name }} + {{#if @model.host.name}} + + {{@model.host.name}} + + {{/if}} + {{! Host description }} + {{#if @model.host.description}} + + {{@model.host.description}} + + {{/if}} + {{! Host address }} + {{#if @model.host.address}} + + {{@model.host.address}} + + {{/if}} + {{! Host ID }} + + + {{@model.host.id}} + + + {{/if}} -
+ {{#if @model.target}}
@@ -125,7 +123,7 @@ -
+ {{/if}}
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 bcc091de0..c50d3569b 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js @@ -20,9 +20,9 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll const sortedSessions = sortBy(sessions, 'session.created_time').reverse(); return [ // then move active sessions to the top - ...sortedSessions.filter((session) => session.isCancelable), + ...sortedSessions.filter((session) => session.isAvailable), // and all others to the end - ...sortedSessions.filter((session) => !session.isCancelable), + ...sortedSessions.filter((session) => !session.isAvailable), ]; } } diff --git a/ui/desktop/app/controllers/scopes/scope/projects/targets/target/sessions.js b/ui/desktop/app/controllers/scopes/scope/projects/targets/target/sessions.js index ae9ecc75f..e2938602d 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/targets/target/sessions.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/targets/target/sessions.js @@ -30,7 +30,7 @@ export default class ScopesScopeProjectsTargetsTargetSessionsController extends const sessions = this.sessions; const userId = this.session.data.authenticated.user_id; const filteredSessions = sessions.filter( - (session) => session.isCancelable && session.user_id === userId + (session) => session.isAvailable && session.user_id === userId ); // Sort sessions diff --git a/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js b/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js index 5fd899689..d55d40d86 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js +++ b/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js @@ -20,9 +20,7 @@ export default class ScopesScopeProjectsSessionsSessionRoute extends Route { * @return {SessionModel} */ async model({ session_id }) { - const session = await this.store.findRecord('session', session_id, { - reload: true, - }); + const session = await this.store.findRecord('session', session_id); /** * If the session has a host_id and the user has grants, diff --git a/ui/desktop/app/routes/scopes/scope/projects/targets/target.js b/ui/desktop/app/routes/scopes/scope/projects/targets/target.js index fae406ea9..f74d07f3b 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/targets/target.js +++ b/ui/desktop/app/routes/scopes/scope/projects/targets/target.js @@ -37,9 +37,11 @@ export default class ScopesScopeProjectsTargetsTargetRoute extends Route { }); if (target.host_sources.length >= 1) { - // if user does not have permissions to fetch host-sets or hosts - // this will catch the error and return an empty array - // from the model hook for hosts + /** + * if user does not have permissions to fetch host-sets or hosts + * this will catch the error and return an empty array + * from the model hook for hosts + */ try { const hostSets = await Promise.all( target.host_sources.map(({ host_source_id }) => @@ -69,9 +71,11 @@ export default class ScopesScopeProjectsTargetsTargetRoute extends Route { async afterModel(model, transition) { const { isConnecting } = transition.to.queryParams; - // if connecting and hosts length is 1 or less we will try to - // connect, even if there is no address on the target and - // rely on the CLI to give the user the proper error + /** + * if connecting and hosts length is 1 or less we will try to + * connect, even if there is no address on the target and + * rely on the CLI to give the user the proper error + */ if (isConnecting && model.hosts.length <= 1) { await this.connect(model.target); } @@ -120,10 +124,12 @@ export default class ScopesScopeProjectsTargetsTargetRoute extends Route { @action @loading async preConnect(model, toggleModal) { - // if hosts length is 1 or less we will try to - // connect, even if there is no address on the target and - // rely on the CLI to give the user the proper error or if - // there are 2 or more hosts we show the modal for host selection + /** + * if hosts length is 1 or less we will try to + * connect, even if there is no address on the target and + * rely on the CLI to give the user the proper error or if + * there are 2 or more hosts we show the modal for host selection + */ if (model.hosts.length <= 1) { await this.connect(model.target); } else { @@ -156,14 +162,35 @@ export default class ScopesScopeProjectsTargetsTargetRoute extends Route { const connectionDetails = await this.ipc.invoke('connect', options); // Associate the connection details with the session + let session; const { session_id, address, port, credentials } = connectionDetails; - const session = await this.store.findRecord('session', session_id); + try { + session = await this.store.findRecord('session', session_id); + } catch (error) { + /** + * if the user cannot read or fetch the session we add the important + * information returned from the connect command to allow the user + * to still continue their work with the information they need + */ + this.store.pushPayload('session', { + sessions: [ + { + id: session_id, + proxy_address: address, + proxy_port: port, + }, + ], + }); + session = this.store.peekRecord('session', session_id); + } // Flag the session has been open in the desktop client session.started_desktop_client = true; - // Update the session record with proxy information from the CLI - // In the future, it may make sense to push this off to the API so that - // we don't have to manually persist the proxy details. + /** + * Update the session record with proxy information from the CLI + * In the future, it may make sense to push this off to the API so that + * we don't have to manually persist the proxy details. + */ session.proxy_address = address; session.proxy_port = port; if (credentials) { 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 13795b56d..c035a5cff 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs @@ -130,7 +130,7 @@ <:body as |B|> - {{#if (can 'read session' B.data)}} + {{#if B.data.isAvailable}} - {{#if B.data.isCancelable}} + {{#if B.data.isAvailable}} {{#if B.data.proxy}} - {{#if B.data.isCancelable}} + {{#if B.data.isAvailable}} { + assert.true(err.errors[0].isForbidden); + }; + + this.server.get('/sessions/:id', () => new Response(403)); + stubs.ipcService.withArgs('cliExists').returns(true); + stubs.ipcService.withArgs('connect').returns({ + session_id: instances.session.id, + host_id: 'h_123', + address: 'a_123', + port: 'p_123', + protocol: 'tcp', + }); + + await visit(urls.target); + await click(TARGET_CONNECT_BUTTON); assert.strictEqual(currentURL(), urls.session); });