Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #30 from fleetbase/dev-v0.2.6
Browse files Browse the repository at this point in the history
dev-v0.2.6
  • Loading branch information
roncodes authored Oct 6, 2023
2 parents 9af46ee + b8d302f commit 0901110
Show file tree
Hide file tree
Showing 24 changed files with 897 additions and 426 deletions.
12 changes: 12 additions & 0 deletions addon/components/admin/visibility-controls.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<ContentPanel @title="Visibility Controls" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<p class="mb-4 dark:text-white text-gray-800">Visibility controls allow you to disable sections of Fleet-Ops. Toggle the checkbox to enable or disable sections to hide in Fleet-ops.</p>
{{#each this.visibilitySettings as |visibilityControl|}}
<InputGroup @wrapperClass="mb-1i">
<Checkbox @value={{visibilityControl.visible}} @label={{concat visibilityControl.name " Visible"}} @onToggle={{fn (mut visibilityControl.visible)}} @helpText="Enable or disable visibility for this section in Fleet-Ops." />
</InputGroup>
{{/each}}
</ContentPanel>

<div class="mt-3 flex items-center justify-end">
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.saveVisibilitySettings}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
</div>
82 changes: 82 additions & 0 deletions addon/components/admin/visibility-controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { isArray } from '@ember/array';

export default class AdminVisibilityControlsComponent extends Component {
@service fetch;
@tracked visibilitySettings = [
{ name: 'Dashboard', route: 'operations.orders', visible: true },
{ name: 'Service Rates', route: 'operations.service-rates', visible: true },
{ name: 'Drivers', route: 'management.drivers', visible: true },
{ name: 'Vehicles', route: 'management.vehicles', visible: true },
{ name: 'Fleets', route: 'management.fleets', visible: true },
{ name: 'Vendors', route: 'management.vendors', visible: true },
{ name: 'Contacts', route: 'management.contacts', visible: true },
{ name: 'Places', route: 'management.places', visible: true },
{ name: 'Fuel Reports', route: 'management.fuel-reports', visible: true },
{ name: 'Issues', route: 'management.issues', visible: true },
];
@tracked isLoading = false;

constructor() {
super(...arguments);
this.loadVisibilitySettings();
}

@action mutateVisibility(route, visible) {
this.visibilitySettings = [...this.visibilitySettings].map((visibilityControl) => {
if (visibilityControl.route === route) {
return {
...visibilityControl,
visible,
};
}

return visibilityControl;
});
}

@action loadVisibilitySettings() {
this.isLoading = true;

this.fetch
.get('fleet-ops/settings/visibility')
.then(({ visibilitySettings }) => {
if (isArray(visibilitySettings)) {
for (let i = 0; i < visibilitySettings.length; i++) {
const visibilityControl = visibilitySettings.objectAt(i);
this.mutateVisibility(visibilityControl.route, visibilityControl.visible);
}
}
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
}

@action saveVisibilitySettings() {
this.isLoading = true;

this.fetch
.post('fleet-ops/settings/visibility', { visibilitySettings: this.visibilitySettings })
.then(({ visibilitySettings }) => {
if (isArray(visibilitySettings)) {
for (let i = 0; i < visibilitySettings.length; i++) {
const visibilityControl = visibilitySettings.objectAt(i);
this.mutateVisibility(visibilityControl.route, visibilityControl.visible);
}
}
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
}
}
17 changes: 13 additions & 4 deletions addon/components/fleet-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { inject as service } from '@ember/service';
export default class FleetPanelComponent extends Component {
@service fetch;
@service modalsManager;
@service universe;
@service store;
@service fetch;
@tracked currentTab;
Expand All @@ -26,18 +27,26 @@ export default class FleetPanelComponent extends Component {
}

@action addDriver(driver) {
this.fetch.post('fleets/assign-driver', { driver: driver.id, fleet: this.fleet.id });
this.fetch.post('fleets/assign-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
this.universe.trigger('fleet.driver.assigned', this.fleet, driver);
});
}

@action removeDriver(driver) {
this.fetch.post('fleets/remove-driver', { driver: driver.id, fleet: this.fleet.id });
this.fetch.post('fleets/remove-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
this.universe.trigger('fleet.driver.unassigned', this.fleet, driver);
});
}

@action addVehicle(vehicle) {
this.fetch.post('fleets/assign-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id });
this.fetch.post('fleets/assign-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
this.universe.trigger('fleet.vehicle.assigned', this.fleet, vehicle);
});
}

@action removeVehicle(vehicle) {
this.fetch.post('fleets/remove-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id });
this.fetch.post('fleets/remove-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
this.universe.trigger('fleet.vehicle.unassigned', this.fleet, vehicle);
});
}
}
2 changes: 1 addition & 1 deletion addon/components/fleet-vehicle-listing.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{yield}}<div class="fleet-vehicle-listing" {{did-insert this.setupComponent}} ...attributes>
<div class="fleet-vehicle-listing" {{did-insert this.setupComponent}} ...attributes>
<div class="mb-2 flex items-center justify-between">
<div class="flex items-center">
<div class="fleet-vehicle-listing-search">
Expand Down
26 changes: 26 additions & 0 deletions addon/components/layout/fleet-ops-sidebar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div class="mb-2">
<Button @text="Create new order" @type="primary" @size="xs" @icon="paper-plane" @iconPrefix="fas" @iconSize="sm" @wrapperClass="w-full" class="w-full" @onClick={{this.onClickCreateOrder}} />
</div>
{{#each this.universeMenuItems as |menuItem|}}
{{#if menuItem.renderComponentInPlace}}
{{component menuItem.component}}
{{else}}
<Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
{{/if}}
{{/each}}
{{#each this.menuPanels as |menuPanel|}}
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
{{#each menuPanel.items as |item|}}
<Layout::Sidebar::Item @route={{concat this.routePrefix item.route}} @icon={{item.icon}}>{{item.title}}</Layout::Sidebar::Item>
{{/each}}
</Layout::Sidebar::Panel>
{{/each}}
{{#each this.universeMenuPanels as |menuPanel|}}
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
{{#each menuPanel.items as |menuItem|}}
<Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
{{/each}}
</Layout::Sidebar::Panel>
{{/each}}
<Layout::Sidebar::Item @onClick={{this.onClickSettings}} @icon="cogs">Settings</Layout::Sidebar::Item>
{{yield}}
129 changes: 129 additions & 0 deletions addon/components/layout/fleet-ops-sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { isArray } from '@ember/array';

/**
* LayoutFleetOpsSidebarComponent
*
* This component manages the sidebar layout for Fleet Ops, including visibility and actions.
*/
export default class LayoutFleetOpsSidebarComponent extends Component {
@service universe;
@tracked routePrefix = 'console.fleet-ops.';
@tracked menuPanels = [];
@tracked universeMenuItems = [];
@tracked universeMenuPanels = [];

constructor() {
super(...arguments);
this.createMenuItemsFromUniverseRegistry();
this.createMenuPanels();
}

createMenuItemsFromUniverseRegistry() {
this.universeMenuItems = this.universe.getMenuItemsFromRegistry('engine:fleet-ops');
this.universeMenuPanels = this.universe.getMenuPanelsFromRegistry('engine:fleet-ops');
}

/**
* Initialize menu panels with visibility settings.
*/
createMenuPanels() {
const operationsItems = [
{ title: 'Dashboard', icon: 'home', route: 'operations.orders' },
{ title: 'Service Rates', icon: 'file-invoice-dollar', route: 'operations.service-rates' },
];

const resourcesItems = [
{ title: 'Drivers', icon: 'route', route: 'management.drivers' },
{ title: 'Vehicles', icon: 'truck', route: 'management.vehicles' },
{ title: 'Fleets', icon: 'user-group', route: 'management.fleets' },
{ title: 'Vendors', icon: 'warehouse', route: 'management.vendors' },
{ title: 'Contacts', icon: 'address-book', route: 'management.contacts' },
{ title: 'Places', icon: 'location-dot', route: 'management.places' },
{ title: 'Fuel Reports', icon: 'gas-pump', route: 'management.fuel-reports' },
{ title: 'Issues', icon: 'triangle-exclamation', route: 'management.issues' },
];

const createPanel = (title, routePrefix, items = []) => ({
title,
open: true,
visible: this.isPanelVisible(routePrefix),
items: items
.map((item) => ({
...item,
visible: this.isItemVisible(item.route),
}))
.filter((item) => item.visible),
});

this.menuPanels = [createPanel('Operations', 'operations', operationsItems), createPanel('Resources', 'management', resourcesItems)].filter((panel) => {
const isVisible = panel.visible && panel.items.length > 0;
return isVisible;
});
}

/**
* Check if a panel should be visible based on visibility settings.
*
* @param {string} routePrefix - The route prefix to check for visibility.
* @returns {boolean} - Whether the panel should be visible.
*/
isPanelVisible(routePrefix) {
return this.isVisible(routePrefix, false);
}

/**
* Check if a menu item should be visible based on visibility settings.
*
* @param {string} routePrefix - The route prefix to check for visibility.
* @returns {boolean} - Whether the menu item should be visible.
*/
isItemVisible(routePrefix) {
return this.isVisible(routePrefix, true);
}

/**
* Utility function to check visibility based on route prefix.
*
* @param {string} routePrefix - The route prefix to check for visibility.
* @param {boolean} exactMatch - Whether to match the route exactly or just the prefix.
* @returns {boolean} - Whether the item should be visible.
*/
isVisible(routePrefix, exactMatch) {
const { visibilitySettings } = this.args;

if (!isArray(visibilitySettings)) {
return true;
}

return visibilitySettings.some((visibilityControl) => {
const match = exactMatch ? visibilityControl.route === routePrefix : visibilityControl.route.startsWith(routePrefix);
return match && visibilityControl.visible;
});
}

/**
* Action handler for creating an order.
*/
@action onClickCreateOrder() {
const { onClickCreateOrder } = this.args;

if (typeof onClickCreateOrder === 'function') {
onClickCreateOrder();
}
}

/**
* Action handler for opening settings.
*/
@action onClickSettings() {
const { onClickSettings } = this.args;

if (typeof onClickSettings === 'function') {
onClickSettings();
}
}
}
19 changes: 19 additions & 0 deletions addon/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import loadInitializers from 'ember-load-initializers';
import Resolver from 'ember-resolver';
import config from './config/environment';
import services from '@fleetbase/ember-core/exports/services';
import AdminVisibilityControlsComponent from './components/admin/visibility-controls';

const { modulePrefix } = config;
const externalRoutes = ['console', 'extensions'];
Expand All @@ -18,6 +19,24 @@ export default class FleetOpsEngine extends Engine {
// register menu item in header
universe.registerHeaderMenuItem('Fleet-Ops', 'console.fleet-ops', { icon: 'route', priority: 0 });

// register admin settings -- create a fleet-ops menu panel with it's own setting options
universe.registerAdminMenuPanel(
'Fleet-Ops Config',
[
{
title: 'Visibility Controls',
icon: 'eye',
component: AdminVisibilityControlsComponent,
},
],
{
slug: 'fleet-ops',
}
);

// create primary registry for engine
universe.createRegistry('engine:fleet-ops');

// register the vehicle panel
universe.createRegistry('component:vehicle-panel');

Expand Down
5 changes: 5 additions & 0 deletions addon/helpers/is-section-visible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { helper } from '@ember/component/helper';

export default helper(function isSectionVisible(positional /*, named*/) {
return positional;
});
1 change: 1 addition & 0 deletions addon/routes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import buildRoutes from 'ember-engines/routes';

export default buildRoutes(function () {
this.route('virtual', { path: '/:slug/:view' });
this.route('operations', { path: '/' }, function () {
this.route('dispatch');
this.route('zones', function () {});
Expand Down
8 changes: 6 additions & 2 deletions addon/routes/application.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';

export default class ApplicationRoute extends Route {
@service loader;
@service fetch;

@action loading(transition) {
loading(transition) {
const resourceName = this.getResouceName(transition);
this.loader.showOnInitialTransition(transition, 'section.next-view-section', resourceName ? `Loading ${resourceName}...` : `Loading...`);
}

model() {
return this.fetch.get('fleet-ops/settings/visibility');
}

getResouceName(transition) {
const { to } = transition;

Expand Down
10 changes: 10 additions & 0 deletions addon/routes/virtual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class VirtualRoute extends Route {
@service universe;

model({ slug, view }) {
return this.universe.lookupMenuItemFromRegistry('engine:fleet-ops', slug, view);
}
}
Loading

0 comments on commit 0901110

Please sign in to comment.