Merge remote-tracking branch 'origin/main' into dmg-background
This commit is contained in:
19 files changed
+381
-171
No files matched your search
@@ -60,7 +60,7 @@ module('Integration | Component | error/message', function (hooks) {
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-message-description').textContent.trim(),
|
||||
'Please contact your administrator or try again later.'
|
||||
'We\'re not sure what happened. Please contact your administrator or try again later.'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@ cancel: Cancel
|
||||
delete: Delete
|
||||
remove: Remove
|
||||
discard: Discard
|
||||
disconnect: Disconnect
|
||||
dismiss: Dismiss
|
||||
save: Save
|
||||
submit: Submit
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
description: We ran into a problem and could not continue. You can ask your administrator or try again later.
|
||||
unknown:
|
||||
title: Something went wrong
|
||||
description: Please contact your administrator or try again later.
|
||||
description: We're not sure what happened. Please contact your administrator or try again later.
|
||||
generic:
|
||||
title: Error
|
||||
authentication-failed:
|
||||
|
||||
@@ -95,6 +95,9 @@ host:
|
||||
none:
|
||||
title: No Hosts
|
||||
description: No hosts available in this scope.
|
||||
none-friendly:
|
||||
title: No Hosts Available
|
||||
description: No hosts available to display yet.
|
||||
actions:
|
||||
add: Add Host
|
||||
create: New Host
|
||||
@@ -110,6 +113,12 @@ session:
|
||||
none:
|
||||
title: No Sessions
|
||||
description: There are no active sessions within the current scope.
|
||||
none-friendly:
|
||||
title: No Sessions Available
|
||||
description: No sessions available to display yet.
|
||||
none-active-friendly:
|
||||
title: No Active Sessions Available
|
||||
description: No active sessions available to display yet.
|
||||
actions:
|
||||
connect: Connect
|
||||
org:
|
||||
@@ -195,6 +204,9 @@ target:
|
||||
messages:
|
||||
welcome:
|
||||
title: Welcome to Targets
|
||||
none:
|
||||
title: No Targets Available
|
||||
description: No Targets to display yet. Contact your Boundary admin if you don't see a Target you expect access to.
|
||||
actions:
|
||||
create: New Target
|
||||
delete: Delete Target
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeProjectsSessionsIndexController extends Controller {
|
||||
@@ -15,7 +14,6 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll
|
||||
* and active/pending.
|
||||
* @type {SessionModel[]}
|
||||
*/
|
||||
@computed('model.@each.{created_time,active}', 'session.data.authenticated.user_id')
|
||||
get sorted() {
|
||||
const userId = this.session.data.authenticated.user_id;
|
||||
const sessions = this.model;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { A } from '@ember/array';
|
||||
|
||||
@@ -9,14 +8,21 @@ export default class ScopesScopeProjectsTargetsTargetSessionsController extends
|
||||
@service session;
|
||||
|
||||
/**
|
||||
* Sort and filter to active sessions of current user
|
||||
* Sessions belonging to the target.
|
||||
* @type {SessionModel[]}
|
||||
*/
|
||||
get sessions() {
|
||||
return this.model.sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort and filter to active sessions of current user.
|
||||
* @param {[SessionModel]} model
|
||||
* @param {object} session
|
||||
* @type {[SessionModel]}
|
||||
*/
|
||||
@computed('model.@each.{created_time,active}', 'session.data.authenticated.user_id')
|
||||
get selfActiveSessions() {
|
||||
const sessions = this.model;
|
||||
get cancelableUserSessions() {
|
||||
const sessions = this.sessions;
|
||||
const userId = this.session.data.authenticated.user_id;
|
||||
const filteredSessions =
|
||||
sessions.filter(session =>
|
||||
@@ -27,10 +33,6 @@ export default class ScopesScopeProjectsTargetsTargetSessionsController extends
|
||||
// Sort sessions
|
||||
const sortedSessions = A(filteredSessions).sortBy('created_time').reverse();
|
||||
|
||||
// Move active sessions to top
|
||||
return [
|
||||
...sortedSessions.filter(session => session.isActive),
|
||||
...sortedSessions.filter(session => !session.isActive)
|
||||
]
|
||||
return sortedSessions;
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,16 @@ export default class ApplicationRoute extends Route.extend(
|
||||
this.session.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from origin and invalidates session, thereby resetting
|
||||
* the client and reloading to the onboarding origin screen.
|
||||
*/
|
||||
@action
|
||||
disconnect() {
|
||||
this.origin.resetOrigin();
|
||||
this.invalidateSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks into ember-loading to kick off loading indicator in the
|
||||
* application template.
|
||||
|
||||
@@ -4,15 +4,6 @@ import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeProjectsTargetsTargetSessionsRoute extends Route {
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* @return {[SessionModel]}
|
||||
*/
|
||||
model() {
|
||||
return this.modelFor('scopes.scope.projects.targets.target').sessions;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
@@ -25,4 +16,5 @@ export default class ScopesScopeProjectsTargetsTargetSessionsRoute extends Route
|
||||
async cancelSession(session) {
|
||||
await session.cancelSession();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import Service from '@ember/service';
|
||||
import { assert } from '@ember/debug';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class OriginService extends Service {
|
||||
|
||||
@@ -72,4 +73,13 @@ export default class OriginService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the origin.
|
||||
*/
|
||||
@notifyError(({ message }) => message, { catch: true })
|
||||
async resetOrigin() {
|
||||
this.rendererOrigin = null;
|
||||
await this.ipc.invoke('resetOrigin');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,15 @@
|
||||
{{page-title (t "errors.generic.title") }}
|
||||
|
||||
<main>
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Error::Message />
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Button @style="primary" {{on "click" (route-action "disconnect")}}>
|
||||
{{t "actions.disconnect"}}
|
||||
</Rose::Button>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
</main>
|
||||
@@ -0,0 +1,23 @@
|
||||
{{page-title (t "errors.generic.title") }}
|
||||
|
||||
{{! Most error types will land here }}
|
||||
{{#if @model.errors}}
|
||||
<Rose::Layout::Centered>
|
||||
{{#each @model.errors as |error|}}
|
||||
<Error::Message @status={{error.status}}/>
|
||||
{{/each}}
|
||||
</Rose::Layout::Centered>
|
||||
{{/if}}
|
||||
|
||||
{{! But a disconnected state doesn't get normalized errors }}
|
||||
{{#unless @model.errors}}
|
||||
<Rose::Layout::Centered>
|
||||
<Error::Message />
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Button @style="primary" {{on "click" (route-action "disconnect")}}>
|
||||
{{t "actions.disconnect"}}
|
||||
</Rose::Button>
|
||||
</Rose::Layout::Centered>
|
||||
{{/unless}}
|
||||
@@ -83,9 +83,9 @@
|
||||
{{else}}
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message @title={{t "resources.session.messages.none.title"}} as |message|>
|
||||
<Rose::Message @title={{t "resources.session.messages.none-friendly.title"}} as |message|>
|
||||
<message.description>
|
||||
{{t "resources.session.messages.none.description"}}
|
||||
{{t "resources.session.messages.none-friendly.description"}}
|
||||
</message.description>
|
||||
</Rose::Message>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
@@ -7,74 +7,86 @@
|
||||
</page.header>
|
||||
|
||||
<page.body>
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t "form.name.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.id.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.type.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "resources.project.title"}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model as |model|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell>
|
||||
<LinkTo
|
||||
@route="scopes.scope.projects.targets.target"
|
||||
@model={{model.id}}
|
||||
>
|
||||
{{model.displayName}}
|
||||
</LinkTo>
|
||||
{{#if model.target.description}}
|
||||
<p>{{model.target.description}}</p>
|
||||
{{/if}}
|
||||
{{#if model.target.isActive}}
|
||||
<Rose::Badge @style="success">
|
||||
{{t "states.active"}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@text={{model.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{model.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{#if model.type}}
|
||||
<Rose::Badge>
|
||||
{{t (concat "resources.target.types." model.type)}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<div>
|
||||
{{#if @model}}
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t "form.name.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.id.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.type.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "resources.project.title"}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model as |model|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell>
|
||||
<LinkTo
|
||||
@route="scopes.scope.projects.targets.target"
|
||||
@model={{model.id}}
|
||||
>
|
||||
{{model.displayName}}
|
||||
</LinkTo>
|
||||
{{#if model.target.description}}
|
||||
<p>{{model.target.description}}</p>
|
||||
{{/if}}
|
||||
{{#if model.target.isActive}}
|
||||
<Rose::Badge @style="success">
|
||||
{{t "states.active"}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@text={{model.project.id}}
|
||||
@text={{model.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{model.project.id}}</code>
|
||||
<code>{{model.id}}</code>
|
||||
</Copyable>
|
||||
</div>
|
||||
<Rose::Badge @style='informational'>
|
||||
{{model.project.name}}
|
||||
</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Button @style="secondary" {{on "click" (route-action "connect" model)}}>
|
||||
{{t "resources.session.actions.connect"}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{#if model.type}}
|
||||
<Rose::Badge>
|
||||
{{t (concat "resources.target.types." model.type)}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<div>
|
||||
<Copyable
|
||||
@text={{model.target.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{model.target.id}}</code>
|
||||
</Copyable>
|
||||
</div>
|
||||
<Rose::Badge @style='informational'>
|
||||
{{model.project.name}}
|
||||
</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Button @style="secondary" {{on "click" (route-action "connect" model)}}>
|
||||
{{t "resources.session.actions.connect"}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
{{else}}
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message @title={{t "resources.target.messages.none.title"}} as |message|>
|
||||
<message.description>
|
||||
{{t "resources.target.messages.none.description"}}
|
||||
</message.description>
|
||||
</Rose::Message>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
{{/if}}
|
||||
</page.body>
|
||||
|
||||
</Rose::Layout::Page>
|
||||
@@ -1,32 +1,46 @@
|
||||
{{page-title (t "resources.host-set.title_plural")}}
|
||||
|
||||
<Rose::Table as |table|>
|
||||
<table.body as |body|>
|
||||
{{#each @model.hosts as |host|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
{{host.displayName}}
|
||||
<p>{{host.description}}</p>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@text={{host.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{host.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>{{host.attributes.address}}</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t (concat 'resources.host.types.' host.type)}}</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Button @style="secondary" {{on "click" (route-action "connect" @model.target host)}}>
|
||||
{{t "resources.session.actions.connect"}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
{{#if @model.hosts}}
|
||||
|
||||
<Rose::Table as |table|>
|
||||
<table.body as |body|>
|
||||
{{#each @model.hosts as |host|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
{{host.displayName}}
|
||||
<p>{{host.description}}</p>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@text={{host.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{host.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>{{host.attributes.address}}</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t (concat 'resources.host.types.' host.type)}}</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Button @style="secondary" {{on "click" (route-action "connect" @model.target host)}}>
|
||||
{{t "resources.session.actions.connect"}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
|
||||
{{else}}
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message @title={{t "resources.host.messages.none-friendly.title"}} as |message|>
|
||||
<message.description>
|
||||
{{t "resources.host.messages.none-friendly.description"}}
|
||||
</message.description>
|
||||
</Rose::Message>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
{{/if}}
|
||||
@@ -1,33 +1,35 @@
|
||||
<Rose::Table as |table|>
|
||||
<table.body as |body|>
|
||||
{{#each this.selfActiveSessions as |session|}}
|
||||
<body.row as |row|>
|
||||
<row.cell class="nowrap">
|
||||
<Rose::Icon
|
||||
class={{concat "session-status-" session.status}}
|
||||
@name="app-icons/action-session"
|
||||
@size="medium" />
|
||||
<Copyable
|
||||
@text={{session.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{session.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{!--
|
||||
Two if's here because:
|
||||
1) Local proxy info is only relevant if the session is
|
||||
active or pending (aka isCancelable). Once the session
|
||||
is canceled or in the process thereof, the local proxy
|
||||
may no longer be used.
|
||||
2) The session actually has proxy information associated
|
||||
with it. It's possible for the user to start sessions
|
||||
from other devices (or even another tab), in which case we
|
||||
won't have the local proxy info available here.
|
||||
--}}
|
||||
{{#if session.isCancelable}}
|
||||
{{#if this.cancelableUserSessions}}
|
||||
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t "form.id.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.proxy.label"}}</row.headerCell>
|
||||
<row.headerCell>{{t "form.started.label"}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
|
||||
{{#each this.cancelableUserSessions as |session|}}
|
||||
<body.row as |row|>
|
||||
|
||||
<row.cell class="nowrap">
|
||||
<Rose::Icon
|
||||
class={{concat "session-status-" session.status}}
|
||||
@name="app-icons/action-session"
|
||||
@size="medium" />
|
||||
<Copyable
|
||||
@text={{session.id}}
|
||||
@buttonText={{t "actions.copy-to-clipboard"}}
|
||||
@acknowledgeText={{t "states.copied"}}
|
||||
>
|
||||
<code>{{session.id}}</code>
|
||||
</Copyable>
|
||||
<Rose::Badge>{{session.status}}</Rose::Badge>
|
||||
</row.cell>
|
||||
|
||||
<row.cell>
|
||||
{{#if session.proxy}}
|
||||
<Copyable
|
||||
@text={{session.proxy}}
|
||||
@@ -37,24 +39,39 @@
|
||||
<code>{{session.proxy}}</code>
|
||||
</Copyable>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<time datetime={{format-date-iso session.created_time}}>
|
||||
{{format-date-iso-human session.created_time}}
|
||||
</time>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{session.status}}</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{#if session.isCancelable}}
|
||||
<Rose::Button @style="secondary" {{on "click" (route-action "cancelSession" session)}}>
|
||||
{{t "actions.cancel"}}
|
||||
</Rose::Button>
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</row.cell>
|
||||
|
||||
<row.cell>
|
||||
<time datetime={{format-date-iso session.created_time}}>
|
||||
{{format-date-iso-human session.created_time}}
|
||||
</time>
|
||||
</row.cell>
|
||||
|
||||
<row.cell>
|
||||
{{#if session.isCancelable}}
|
||||
<Rose::Button
|
||||
@style="secondary"
|
||||
{{on "click" (route-action "cancelSession" session)}}
|
||||
>
|
||||
{{t "actions.cancel"}}
|
||||
</Rose::Button>
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
|
||||
{{else}}
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message @title={{t "resources.session.messages.none-active-friendly.title"}} as |message|>
|
||||
<message.description>
|
||||
{{t "resources.session.messages.none-active-friendly.description"}}
|
||||
</message.description>
|
||||
</Rose::Message>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
{{/if}}
|
||||
@@ -17,6 +17,13 @@ handle('setOrigin', async (requestOrigin) => {
|
||||
origin.origin = requestOrigin;
|
||||
});
|
||||
|
||||
/**
|
||||
* Resets the origin.
|
||||
*/
|
||||
handle('resetOrigin', async (requestOrigin) => {
|
||||
origin.resetOrigin();
|
||||
});
|
||||
|
||||
/**
|
||||
* Check for boundary cli existence
|
||||
*/
|
||||
|
||||
@@ -4,12 +4,14 @@ const {
|
||||
default: installExtension,
|
||||
EMBER_INSPECTOR,
|
||||
} = require('electron-devtools-installer');
|
||||
const { session, app, protocol, BrowserWindow, ipcMain } = require('electron');
|
||||
const { session, app, protocol, BrowserWindow, ipcMain, Menu } = require('electron');
|
||||
require('./handlers.js');
|
||||
|
||||
const origin = require('./origin.js');
|
||||
const { generateCSPHeader } = require('./content-security-policy.js');
|
||||
|
||||
const menu = require('./menu.js');
|
||||
|
||||
const isDev = require('electron-is-dev');
|
||||
|
||||
// Register the custom file protocol
|
||||
@@ -88,6 +90,12 @@ app.on('ready', async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Configure menu in prod env
|
||||
if(!isDev) {
|
||||
const menuTemplate = Menu.buildFromTemplate(menu.generateMenuTemplate());
|
||||
Menu.setApplicationMenu(menuTemplate);
|
||||
}
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1024,
|
||||
height: 768,
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
const { shell } = require('electron')
|
||||
|
||||
const generateMenuTemplate = () => {
|
||||
return [
|
||||
// { role: 'appMenu' }
|
||||
{
|
||||
label: 'Boundary Desktop',
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
},
|
||||
// { role: 'fileMenu' }
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{ role: 'close' }
|
||||
]
|
||||
},
|
||||
// { role: 'editMenu' }
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// { role: 'windowMenu' }
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window' }
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: () => shell.openExternal('https://www.boundaryproject.io')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateMenuTemplate: generateMenuTemplate
|
||||
};
|
||||
@@ -24,7 +24,7 @@ class RuntimeSettings {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Validates the origin is reachable and has a scopes endpoint.
|
||||
*/
|
||||
async validateOrigin(origin) {
|
||||
// If the origin is the Electron origin, it is automatically valid.
|
||||
@@ -40,6 +40,13 @@ class RuntimeSettings {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin to null.
|
||||
*/
|
||||
async resetOrigin() {
|
||||
this.origin = null;
|
||||
}
|
||||
|
||||
// Quick and dirty event handler pattern to enable the application to respond
|
||||
// when the origin is changed.
|
||||
#originWatchers = [];
|
||||
|
||||
Reference in new issue
Block a user