Compare commits

..

19 Commits

Author SHA1 Message Date
Ron
50f30742a8 Merge pull request #309 from fleetbase/dev-v0.5.15
v0.5.15
2024-10-17 17:09:03 +08:00
Ronald A. Richardson
c7b1a876f5 v0.5.15 - Additional recovery actions added, added ability for admins to reset user password, patches to webhook handler and logging 2024-10-17 17:02:18 +08:00
Ron
892eaeeca0 Merge pull request #306 from fleetbase/dev-v0.5.14
v0.5.14
2024-10-15 17:53:05 +08:00
Ronald A. Richardson
32f4b69697 order list overlay revamp, ability to create customer with order in consumable api, few patches and fixes 2024-10-15 17:46:36 +08:00
Ron
6317c4b2e4 Merge pull request #304 from fleetbase/dev-v0.5.13
v0.1.3 - critical patches for driver creation flow on fleetops, added ability …
2024-10-10 19:46:55 +08:00
Ronald A. Richardson
e7c229ece5 critical patches for driver creation flow on fleetops, added ability for registry to handle tar/gz bundle uploads, added registry endpoint to upload bundles using auth token, few minor patches 2024-10-10 19:35:45 +08:00
Ron
983a3d22b5 Merge pull request #303 from fleetbase/dev-v0.5.12
v0.5.12 - bump version
2024-10-10 10:56:59 +08:00
Ronald A. Richardson
42105380ca bump version 2024-10-10 10:56:08 +08:00
Ron
8fd4a40016 Merge pull request #302 from fleetbase/dev-v0.5.12
v1.5.12 - critical hotfix to make sure session store is set for json resources
2024-10-10 10:55:42 +08:00
Ronald A. Richardson
331e98af20 critical hotfix to make sure session store is set for json resources 2024-10-10 10:52:37 +08:00
Ron
b1d226256a Merge pull request #301 from fleetbase/dev-v0.5.11
v0.5.11 - Added Manual Verify for Users [IAM], Added ability to Transfer Org Ow…
2024-10-10 00:50:23 +08:00
Ronald A. Richardson
f1ee8b0c99 Added Manual Verify for Users [IAM], Added ability to Transfer Org Ownership and Leave Orgs, Added recovery command, fixes and patches 2024-10-10 00:49:03 +08:00
Ron
23d5ecfdb8 Merge pull request #300 from fleetbase/dev-v0.5.10
patches and improvements
2024-10-08 21:42:07 +08:00
Ronald A. Richardson
2795a2f1be update app router.js 2024-10-08 21:41:07 +08:00
Ron
69afdee975 Merge pull request #299 from fleetbase/dev-v0.5.10
v0.5.10 - patches and improvements
2024-10-08 21:39:34 +08:00
Ronald A. Richardson
60845b9953 patches and improvements 2024-10-08 21:33:55 +08:00
Ron
f3997a1bb7 Merge pull request #298 from fleetbase/dev-v0.5.9
v0.5.9
2024-10-03 17:48:38 +08:00
Ronald A. Richardson
23a691e7e7 removed ember-leaflet patches, using perm fix and improved engine boot timeout and callbacks 2024-10-03 17:43:25 +08:00
Ronald A. Richardson
3dc562987a Hotfix release 2024-10-03 14:58:39 +08:00
39 changed files with 1958 additions and 1587 deletions

View File

@@ -9,10 +9,10 @@
"license": "AGPL-3.0-or-later",
"require": {
"php": "^8.0",
"fleetbase/core-api": "^1.5.9",
"fleetbase/fleetops-api": "^0.5.8",
"fleetbase/registry-bridge": "^0.0.14",
"fleetbase/storefront-api": "^0.3.15",
"fleetbase/core-api": "^1.5.15",
"fleetbase/fleetops-api": "^0.5.12",
"fleetbase/registry-bridge": "^0.0.17",
"fleetbase/storefront-api": "^0.3.16",
"guzzlehttp/guzzle": "^7.0.1",
"laravel/framework": "^10.0",
"laravel/octane": "^2.3",

412
api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<div class="modal-body-container pt-0i text-gray-900 dark:text-white">
<InputGroup @name="Organization name" @value={{@options.organization.name}} />
<InputGroup @name="Organization description" @value={{@options.organization.description}} />
<InputGroup @name="Organization phone number">
<PhoneInput @value={{@options.organization.phone}} @onInput={{fn (mut @options.organization.phone)}} class="form-input w-full" />
</InputGroup>
<InputGroup @name="Organization currency">
<CurrencySelect @value={{@options.organization.currency}} @onSelect={{fn (mut @options.organization.currency)}} @triggerClass="w-full form-select" />
</InputGroup>
</div>
</Modal::Default>

View File

@@ -0,0 +1,3 @@
import Component from '@glimmer/component';
export default class ModalsEditOrganizationComponent extends Component {}

View File

@@ -0,0 +1,43 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<div class="modal-body-container pt-0i text-gray-900 dark:text-white">
{{#if @options.isOwner}}
{{#if @options.hasOtherMembers}}
<p>
<div class="text-base mb-2">
As the owner of
<strong>{{@options.organization.name}}</strong>, leaving the organization requires you to nominate a new owner.
</div>
<div>Please select a member from the dropdown below to transfer ownership before you can proceed.</div>
</p>
<InputGroup @name="Select a New Owner" @wrapperClass="mt-2 mb-0i">
<Select
@options={{@options.organization.users}}
@value={{@options.newOwnerId}}
@onSelect={{@options.selectNewOwner}}
@optionLabel="name"
@optionValue="id"
@placeholder="Select a member"
/>
</InputGroup>
{{else if @options.willBeDeleted}}
<p>
<div class="text-base mb-2">
You are the sole owner of
<strong>{{@options.organization.name}}</strong>.
</div>
<div>By leaving, the organization will be permanently deleted along with all its data.</div>
<div>Are you sure you want to proceed?</div>
</p>
<p class="mt-3"><em>This action cannot be undone.</em></p>
{{/if}}
{{else}}
<p>
<div class="text-base mb-2">
Are you sure you want to leave the organization
<strong>{{@options.organization.name}}</strong>?
</div>
<div>You will no longer have access to its resources and settings.</div>
</p>
{{/if}}
</div>
</Modal::Default>

View File

@@ -0,0 +1,3 @@
import Component from '@glimmer/component';
export default class ModalsLeaveOrganizationComponent extends Component {}

View File

@@ -161,7 +161,7 @@ export default class ConsoleController extends Controller {
}
/**
* Action to invalidate and log user out
* Action to create or join an organization.
*
* @void
*/

View File

@@ -0,0 +1,203 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
import { htmlSafe } from '@ember/template';
export default class ConsoleAccountOrganizationsController extends Controller {
@service currentUser;
@service modalsManager;
@service crud;
@service notifications;
@service intl;
@service fetch;
@service router;
@action async leaveOrganization(organization) {
const isOwner = this.currentUser.id === organization.owner_uuid;
const hasOtherMembers = organization.users_count > 1;
const willBeDeleted = isOwner && organization.users_count === 1;
if (this.model.length === 1) {
return this.notifications.warning('Unable to leave your only organization.');
}
if (hasOtherMembers) {
organization.loadUsers({ exclude: [this.currentUser.id] });
}
this.modalsManager.show('modals/leave-organization', {
title: isOwner ? (willBeDeleted ? 'Delete Organization' : 'Transfer Ownership and Leave') : 'Leave Organization',
acceptButtonText: isOwner ? (willBeDeleted ? 'Delete Organization' : 'Transfer Ownership and Leave') : 'Leave Organization',
acceptButtonScheme: 'danger',
acceptButtonIcon: isOwner ? (willBeDeleted ? 'trash' : 'person-walking-arrow-right') : 'person-walking-arrow-right',
acceptButtonDisabled: isOwner && hasOtherMembers,
isOwner,
hasOtherMembers,
willBeDeleted,
organization,
newOwnerId: null,
selectNewOwner: (newOwnerId) => {
this.modalsManager.setOption('newOwnerId', newOwnerId);
this.modalsManager.setOption('acceptButtonDisabled', false);
},
confirm: async (modal) => {
modal.startLoading();
if (isOwner) {
if (hasOtherMembers) {
const newOwnerId = this.modalsManager.getOption('newOwnerId');
try {
await organization.transferOwnership(newOwnerId, { leave: true });
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
}
if (willBeDeleted) {
try {
await organization.destroyRecord();
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
}
}
try {
await organization.leave();
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
},
});
}
@action switchOrganization(organization) {
this.modalsManager.confirm({
title: this.intl.t('console.switch-organization.modal-title', { organizationName: organization.name }),
body: this.intl.t('console.switch-organization.modal-body'),
acceptButtonText: this.intl.t('console.switch-organization.modal-accept-button-text'),
acceptButtonScheme: 'primary',
confirm: async (modal) => {
modal.startLoading();
try {
await this.fetch.post('auth/switch-organization', { next: organization.uuid });
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.switch-organization.success-notification'));
return later(
this,
() => {
window.location.reload();
},
900
);
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}
@action deleteOrganization(organization) {
const isOwner = this.currentUser.id === organization.owner_uuid;
if (this.model.length === 1) {
return this.notifications.warning('Unable to delete your only organization.');
}
if (!isOwner) {
return this.notifications.warning('You do not have rights to delete this organization.');
}
this.crud.delete(organization, {
title: `Are you sure you want to delete the organization ${organization.name}?`,
body: htmlSafe(
`This action will permanently remove all data, including orders, members, and settings associated with the organization. <br /><br /><strong>This action cannot be undone.</strong>`
),
acceptButtonText: 'Delete Organization',
acceptButtonScheme: 'danger',
acceptButtonIcon: 'trash',
confirm: async (modal) => {
modal.startLoading();
try {
await organization.destroyRecord();
return this.router.refresh();
} catch (error) {
this.notifications.serverError(error);
}
},
});
}
@action editOrganization(organization) {
this.modalsManager.show('modals/edit-organization', {
title: 'Edit Organization',
acceptButtonText: 'Save Changes',
acceptButtonIcon: 'save',
isOwner: this.currentUser.id === organization.owner_uuid,
organization,
confirm: async (modal) => {
modal.startLoading();
try {
await organization.save();
return this.router.refresh();
} catch (error) {
this.notifications.serverError(error);
}
},
});
}
@action createOrganization() {
const currency = this.currentUser.currency;
const country = this.currentUser.country;
this.modalsManager.show('modals/edit-organization', {
title: 'Create Organization',
acceptButtonText: this.intl.t('common.confirm'),
acceptButtonIcon: 'check',
acceptButtonIconPrefix: 'fas',
organization: {
name: null,
decription: null,
phone: null,
currency,
country,
timezone: null,
},
confirm: async (modal) => {
modal.startLoading();
const organization = modal.getOption('organization');
const { name, description, phone, currency, country, timezone } = organization;
try {
await this.fetch.post('auth/create-organization', {
name,
description,
phone,
currency,
country,
timezone,
});
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.create-or-join-organization.create-success-notification'));
return this.router.refresh();
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}
}

View File

@@ -1,8 +1,8 @@
export function initialize(owner) {
const universe = owner.lookup('service:universe');
export function initialize(application) {
const universe = application.lookup('service:universe');
if (universe) {
universe.createRegistries(['@fleetbase/console', 'auth:login']);
universe.bootEngines(owner);
universe.bootEngines(application);
}
}

View File

@@ -1,5 +1,5 @@
export function initialize(owner) {
const leafletService = owner.lookup('service:leaflet');
export function initialize(application) {
const leafletService = application.lookup('service:leaflet');
if (leafletService) {
leafletService.load({
onReady: function (L) {

View File

@@ -1,5 +1,6 @@
import Model, { attr, belongsTo } from '@ember-data/model';
import { computed } from '@ember/object';
import { getOwner } from '@ember/application';
import { format, formatDistanceToNow } from 'date-fns';
import autoSerialize from '../utils/auto-serialize';
@@ -34,6 +35,7 @@ export default class Company extends Model {
@attr('string') slug;
/** @dates */
@attr('date') joined_at;
@attr('date') deleted_at;
@attr('date') created_at;
@attr('date') updated_at;
@@ -71,4 +73,32 @@ export default class Company extends Model {
toJSON() {
return autoSerialize(this);
}
async transferOwnership(newOwner, params = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
return fetch.post('companies/transfer-ownership', { company: this.id, newOwner, ...params });
}
async leave(user = null, params = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
return fetch.post('companies/leave', { company: this.id, user, ...params });
}
async loadUsers(params = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const users = await fetch.get(`companies/${this.id}/users`, { ...params }, { normalizeToEmberData: true, normalizeModelType: 'user' });
this.set('users', users);
return users;
} catch (error) {
this.set('users', []);
return [];
}
}
}

View File

@@ -69,6 +69,17 @@ export default class UserModel extends Model {
});
}
verify() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
return fetch.patch(`users/verify/${this.id}`).then((response) => {
this.email_verified_at = response.email_verified_at;
return response;
});
}
removeFromCurrentCompany() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');

View File

@@ -7,15 +7,18 @@ export default class Router extends EmberRouter {
}
Router.map(function () {
this.route('virtual', { path: '/:slug' });
this.route('install');
this.route('onboard', function () {
this.route('verify-email');
});
this.route('auth', function () {
this.route('login', { path: '/' });
this.route('forgot-password');
this.route('reset-password', { path: '/reset-password/:id' });
this.route('two-fa');
this.route('verification');
});
this.route('onboard', function () {
this.route('verify-email');
this.route('portal-login', { path: '/portal' });
});
this.route('invite', { path: 'join' }, function () {
this.route('for-driver', { path: '/fleet/:public_id' });
@@ -23,24 +26,23 @@ Router.map(function () {
});
this.route('console', { path: '/' }, function () {
this.route('home', { path: '/' });
this.route('extensions');
this.route('notifications');
this.route('account', function () {
this.route('virtual', { path: '/:slug/:view' });
this.route('virtual', { path: '/:slug' });
this.route('auth');
});
this.route('settings', function () {
this.route('virtual', { path: '/:slug/:view' });
this.route('virtual', { path: '/:slug' });
this.route('two-fa');
});
this.route('virtual', { path: '/:slug/:view' });
this.route('virtual', { path: '/:slug' });
this.route('admin', function () {
this.route('config', function () {
this.route('database');
this.route('cache');
this.route('filesystem');
this.route('mail');
this.route('notification-channels');
this.route('notification-channels', { path: '/push-notifications' });
this.route('queue');
this.route('services');
this.route('socket');
@@ -48,12 +50,16 @@ Router.map(function () {
this.route('branding');
this.route('notifications');
this.route('two-fa-settings');
this.route('virtual', { path: '/:slug/:view' });
this.route('virtual', { path: '/:slug' });
this.route('organizations', function () {
this.route('index', { path: '/' });
this.route('users', { path: '/:company_id' });
this.route('index', { path: '/' }, function () {
this.route('users', { path: '/:public_id/users' });
});
});
this.route('schedule-monitor', function () {
this.route('logs', { path: '/:id/logs' });
});
});
});
this.route('install');
this.route('catch', { path: '/*' });
});

View File

@@ -1,6 +1,7 @@
import Route from '@ember/routing/route';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import isElectron from '@fleetbase/ember-core/utils/is-electron';
import pathToRoute from '@fleetbase/ember-core/utils/path-to-route';
@@ -16,6 +17,36 @@ export default class ApplicationRoute extends Route {
@service universe;
@tracked defaultTheme;
/**
* Handle the transition into the application.
*
* @memberof ApplicationRoute
*/
@action willTransition(transition) {
this.universe.callHooks('application:will-transition', this.session, this.router, transition);
}
/**
* On application route activation
*
* @memberof ApplicationRoute
* @void
*/
@action activate() {
this.initializeTheme();
this.initializeLocale();
}
/**
* The application loading event.
* Here will just run extension hooks.
*
* @memberof ApplicationRoute
*/
@action loading(transition) {
this.universe.callHooks('application:loading', this.session, this.router, transition);
}
/**
* Check the installation status of Fleetbase and transition user accordingly.
*
@@ -45,27 +76,18 @@ export default class ApplicationRoute extends Route {
* @return {Transition}
* @memberof ApplicationRoute
*/
async beforeModel() {
async beforeModel(transition) {
await this.session.setup();
await this.universe.booting();
this.universe.callHooks('application:before-model', this.session, this.router, transition);
const shift = this.urlSearchParams.get('shift');
if (this.session.isAuthenticated && shift) {
return this.router.transitionTo(pathToRoute(shift));
}
}
/**
* On application route activation
*
* @memberof ApplicationRoute
* @void
*/
activate() {
this.initializeTheme();
this.initializeLocale();
}
/**
* Initializes the application's theme settings, applying necessary class names and default theme configurations.
*

View File

@@ -0,0 +1,10 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class CatchRoute extends Route {
@service router;
beforeModel() {
return this.router.transitionTo('auth.login');
}
}

View File

@@ -0,0 +1,10 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ConsoleAccountOrganizationsRoute extends Route {
@service currentUser;
model() {
return this.currentUser.loadOrganizations();
}
}

View File

@@ -1,6 +1,6 @@
<div>
<div class="mx-auto w-12 h-12">
<LogoIcon @url={{@brand.icon_url}} @size="12" class="mx-auto" />
<LogoIcon @size="12" class="mx-auto rounded-sm" />
</div>
<h2 class="mt-6 mb-3 text-3xl font-extrabold leading-9 text-center text-gray-900 dark:text-gray-100">
{{t "auth.login.title"}}

View File

@@ -0,0 +1,2 @@
{{page-title "Catch"}}
{{outlet}}

View File

@@ -3,6 +3,7 @@
<Layout::Sidebar::Panel @open={{true}} @title={{t "common.account"}}>
<Layout::Sidebar::Item @route="console.account.index" @icon="user">Profile</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.account.auth" @icon="key">Auth</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.account.organizations" @icon="building">Organizations</Layout::Sidebar::Item>
{{#each this.universe.accountMenuItems as |menuItem|}}
<Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem "console.account.virtual" menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
{{/each}}

View File

@@ -0,0 +1,37 @@
{{page-title "Organizations"}}
<Layout::Section::Header @title="Organizations" />
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-4">
<div class="flex flex-row justify-end">
<Button @type="primary" @icon="plus" @text="Create Organization" @onClick={{this.createOrganization}} />
</div>
<ContentPanel @title="Your Organizations" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<div class="space-y-2">
{{#each @model as |organization|}}
<div class="grid grid-cols-3 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 rounded-lg px-3 py-2 items-center">
<div>
<div class="font-semibold">{{organization.name}}</div>
<div>Member Since: {{format-date organization.joined_at}}</div>
</div>
<div class="col-span-2 flex flex-row items-center justify-end space-x-2">
{{#let (eq organization.owner_uuid this.currentUser.id) as |isOwner|}}
<Button @type="danger" @size="xs" @icon="person-walking-arrow-right" @text="Leave" @onClick={{fn this.leaveOrganization organization}} />
{{#unless (eq this.currentUser.companyId organization.id)}}
<Button @size="xs" @icon="shuffle" @text="Switch" @onClick={{fn this.switchOrganization organization}} />
{{/unless}}
{{#if isOwner}}
<Button @size="xs" @icon="pencil" @text="Edit" @onClick={{fn this.editOrganization organization}} />
<Button @type="danger" @size="xs" @icon="trash" @text="Delete" @onClick={{fn this.deleteOrganization organization}} />
{{/if}}
{{/let}}
</div>
</div>
{{/each}}
</div>
</ContentPanel>
</div>
</div>
<Spacer @height="300px" />
</Layout::Section::Body>

View File

@@ -74,12 +74,6 @@ module.exports = function (environment) {
autoClear: true,
clearDuration: 1000 * 3.5,
},
'ember-leaflet': {
excludeCSS: true,
excludeJS: true,
excludeImages: true,
},
};
if (environment === 'development') {

View File

@@ -1,6 +1,6 @@
{
"name": "@fleetbase/console",
"version": "0.5.8",
"version": "0.5.15",
"private": true,
"description": "Modular logistics and supply chain operating system (LSOS)",
"repository": "https://github.com/fleetbase/fleetbase",
@@ -28,16 +28,16 @@
"test:ember": "ember test"
},
"dependencies": {
"@fleetbase/ember-core": "^0.2.19",
"@fleetbase/ember-ui": "^0.2.32",
"@fleetbase/fleetops-engine": "^0.5.8",
"@fleetbase/storefront-engine": "^0.3.15",
"@fleetbase/dev-engine": "^0.2.7",
"@fleetbase/iam-engine": "^0.1.1",
"@fleetbase/registry-bridge-engine": "^0.0.14",
"@fleetbase/fleetops-data": "^0.1.18",
"@fleetbase/leaflet-routing-machine": "^3.2.16",
"@ember/legacy-built-in-components": "^0.4.2",
"@fleetbase/dev-engine": "^0.2.8",
"@fleetbase/ember-core": "^0.2.21",
"@fleetbase/ember-ui": "^0.2.35",
"@fleetbase/fleetops-data": "^0.1.18",
"@fleetbase/fleetops-engine": "^0.5.12",
"@fleetbase/iam-engine": "^0.1.3",
"@fleetbase/leaflet-routing-machine": "^3.2.16",
"@fleetbase/registry-bridge-engine": "^0.0.17",
"@fleetbase/storefront-engine": "^0.3.16",
"@fortawesome/ember-fontawesome": "^2.0.0",
"ember-changeset": "^4.1.2",
"ember-changeset-validations": "^4.1.1",
@@ -137,12 +137,9 @@
},
"pnpm": {
"overrides": {
"@fleetbase/ember-core": "^0.2.19",
"@fleetbase/ember-ui": "^0.2.32",
"@fleetbase/ember-core": "^0.2.21",
"@fleetbase/ember-ui": "^0.2.35",
"@fleetbase/fleetops-data": "^0.1.18"
},
"patchedDependencies": {
"ember-leaflet@5.1.3": "patches/ember-leaflet@5.1.3.patch"
}
},
"prettier": {

View File

@@ -1,95 +0,0 @@
diff --git a/index.js b/index.js
index 7361871adfe0b79c70a3699e38cc435f3741cb33..e02f7e6d61605d8b770ed5c0454b6c905d538ff9 100644
--- a/index.js
+++ b/index.js
@@ -1,87 +1,5 @@
-'use strict';
-const resolve = require('resolve');
-const path = require('path');
-const mergeTrees = require('broccoli-merge-trees');
-const Funnel = require('broccoli-funnel');
-const fastbootTransform = require('fastboot-transform');
+'use strict'
module.exports = {
- name: require('./package').name,
-
- treeForVendor() {
- let dist = path.join(this.pathBase('leaflet'), 'dist');
-
- let leafletJs = fastbootTransform(
- new Funnel(dist, {
- files: ['leaflet-src.js'],
- destDir: 'leaflet'
- })
- );
-
- let leafletFiles = new Funnel(dist, {
- exclude: ['leaflet.js', 'leaflet-src.js', '*.html'],
- destDir: 'leaflet'
- });
-
- return mergeTrees([leafletJs, leafletFiles]);
- },
-
- included(app) {
- this._super.included.apply(this, arguments);
-
- // Addon options from the apps ember-cli-build.js
- let options = app.options[this.name] || {};
-
- // If the addon has the _findHost() method (in ember-cli >= 2.7.0), we'll just
- // use that.
- // if (typeof this._findHost === 'function') {
- // app = this._findHost();
- // }
-
- // Otherwise, we'll use this implementation borrowed from the _findHost()
- // method in ember-cli.
- // Keep iterating upward until we don't have a grandparent.
- // Has to do this grandparent check because at some point we hit the project.
- let current = this;
- do {
- if (current.lazyLoading === true || (current.lazyLoading && current.lazyLoading.enabled === true)) {
- app = current;
- break;
- }
- app = current.app || app;
- } while (current.parent.parent && (current = current.parent));
-
- if (!options.excludeJS) {
- app.import('vendor/leaflet/leaflet-src.js');
- }
-
- // Import leaflet css
- if (!options.excludeCSS) {
- app.import('vendor/leaflet/leaflet.css');
- }
-
- // Import leaflet images
- if (!options.excludeImages) {
- let imagesDestDir = '/assets/images';
- app.import('vendor/leaflet/images/layers-2x.png', {
- destDir: imagesDestDir
- });
- app.import('vendor/leaflet/images/layers.png', {
- destDir: imagesDestDir
- });
- app.import('vendor/leaflet/images/marker-icon-2x.png', {
- destDir: imagesDestDir
- });
- app.import('vendor/leaflet/images/marker-icon.png', {
- destDir: imagesDestDir
- });
- app.import('vendor/leaflet/images/marker-shadow.png', {
- destDir: imagesDestDir
- });
- }
- },
-
- pathBase(packageName) {
- return path.dirname(resolve.sync(packageName + '/package.json', { basedir: __dirname }));
- }
-};
+ name: require('./package').name
+}

2410
console/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ const recast = require('recast');
const babelParser = require('recast/parsers/babel');
const builders = recast.types.builders;
function getExtensionMountPath (extensionName) {
function getExtensionMountPath(extensionName) {
let extensionNameSegments = extensionName.split('/');
let mountName = extensionNameSegments[1];
@@ -16,7 +16,7 @@ function getExtensionMountPath (extensionName) {
return mountName.replace('-engine', '');
}
function only (subject, props = []) {
function only(subject, props = []) {
const keys = Object.keys(subject);
const result = {};
@@ -31,13 +31,13 @@ function only (subject, props = []) {
return result;
}
function getExtensions () {
function getExtensions() {
return new Promise((resolve, reject) => {
const extensions = [];
const seenPackages = new Set();
return fg(['node_modules/*/package.json', 'node_modules/*/*/package.json'])
.then(results => {
.then((results) => {
for (let i = 0; i < results.length; i++) {
const packagePath = results[i];
const packageJson = fs.readFileSync(packagePath);
@@ -69,7 +69,7 @@ function getExtensions () {
});
}
function getRouterFileContents () {
function getRouterFileContents() {
const routerFilePath = path.join(__dirname, 'router.map.js');
const routerFileContents = fs.readFileSync(routerFilePath, 'utf-8');
@@ -78,25 +78,25 @@ function getRouterFileContents () {
(async () => {
const extensions = await getExtensions();
const consoleExtensions = extensions.filter(extension => !extension.fleetbase || extension.fleetbase.mount !== 'root');
const rootExtensions = extensions.filter(extension => extension.fleetbase && extension.fleetbase.mount === 'root');
const consoleExtensions = extensions.filter((extension) => !extension.fleetbase || extension.fleetbase.mount !== 'root');
const rootExtensions = extensions.filter((extension) => extension.fleetbase && extension.fleetbase.mount === 'root');
const routerFileContents = getRouterFileContents();
const ast = recast.parse(routerFileContents, { parser: babelParser });
recast.visit(ast, {
visitCallExpression (path) {
visitCallExpression(path) {
if (path.value.type === 'CallExpression' && path.value.callee.property.name === 'route' && path.value.arguments[0].value === 'console') {
let functionExpression;
// Find the function expression
path.value.arguments.forEach(arg => {
path.value.arguments.forEach((arg) => {
if (arg.type === 'FunctionExpression') {
functionExpression = arg;
}
});
if (functionExpression) {
// Check and add the new engine mounts
consoleExtensions.forEach(extension => {
consoleExtensions.forEach((extension) => {
const mountPath = getExtensionMountPath(extension.name);
let route = mountPath;
@@ -105,7 +105,7 @@ function getRouterFileContents () {
}
// Check if engine is already mounted
const isMounted = functionExpression.body.body.some(expressionStatement => {
const isMounted = functionExpression.body.body.some((expressionStatement) => {
return expressionStatement.expression.arguments[0].value === extension.name;
});
@@ -131,14 +131,14 @@ function getRouterFileContents () {
if (path.value.type === 'CallExpression' && path.value.callee.property.name === 'map') {
let functionExpression;
path.value.arguments.forEach(arg => {
path.value.arguments.forEach((arg) => {
if (arg.type === 'FunctionExpression') {
functionExpression = arg;
}
});
if (functionExpression) {
rootExtensions.forEach(extension => {
rootExtensions.forEach((extension) => {
const mountPath = getExtensionMountPath(extension.name);
let route = mountPath;
@@ -146,7 +146,7 @@ function getRouterFileContents () {
route = extension.fleetbase.route;
}
const isMounted = functionExpression.body.body.some(expressionStatement => {
const isMounted = functionExpression.body.body.some((expressionStatement) => {
return expressionStatement.expression.arguments[0].value === extension.name;
});

View File

@@ -30,6 +30,7 @@ Router.map(function () {
this.route('account', function () {
this.route('virtual', { path: '/:slug' });
this.route('auth');
this.route('organizations');
});
this.route('settings', function () {
this.route('virtual', { path: '/:slug' });
@@ -61,4 +62,5 @@ Router.map(function () {
});
});
});
this.route('catch', { path: '/*' });
});

View File

@@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | modals/edit-organization', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Modals::EditOrganization />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Modals::EditOrganization>
template block text
</Modals::EditOrganization>
`);
assert.dom().hasText('template block text');
});
});

View File

@@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | modals/leave-organization', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Modals::LeaveOrganization />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Modals::LeaveOrganization>
template block text
</Modals::LeaveOrganization>
`);
assert.dom().hasText('template block text');
});
});

View File

@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Controller | console/account/organizations', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let controller = this.owner.lookup('controller:console/account/organizations');
assert.ok(controller);
});
});

View File

@@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Route | catch', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:catch');
assert.ok(route);
});
});

View File

@@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Route | console/account/organizations', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:console/account/organizations');
assert.ok(route);
});
});