Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions addon/components/order-config-manager/activity-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,17 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
* An array of activity codes that should not be modified.
* @type {Array.<string>}
*/
@tracked immutableActivities = ['created', 'dispatched', 'started'];
/**
* Activities that cannot be edited or removed. Configs with their own lifecycle
* (`meta.lifecycle`) are not bound to the default dispatch activities.
*/
get immutableActivities() {
return this.lifecycle ? [] : ['created', 'dispatched', 'started'];
}

get lifecycle() {
return this.config?.meta?.lifecycle ?? null;
}

/**
* The configuration data for the activity flow.
Expand Down Expand Up @@ -180,6 +190,12 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
this.clearGraph({
onAfter: () => {
this.flow = {};
// A configured lifecycle resets to its saved flow, never to the default dispatch flow.
if (this.lifecycle && this.config?.flow && Object.keys(this.config.flow).length) {
this.deserializeFlow(this.config.flow);
return;
}

const defaultActivities = this.getDefaultActivities();
this.addActivityToGraph(defaultActivities);
},
Expand Down Expand Up @@ -361,7 +377,7 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
}
});

const rootCode = getOrderConfigFlowRootCode(deserializedFlow);
const rootCode = getOrderConfigFlowRootCode(deserializedFlow, this.lifecycle?.initial);
if (rootCode && deserializedFlow[rootCode]) {
this.addDeserializedActivityToGraph(deserializedFlow[rootCode]);
}
Expand Down Expand Up @@ -823,16 +839,26 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
const addButton = this.createAddActivityButton(activity, { x: width });
let tools = [];

if (activity.get('code') === 'created' || activity.get('code') === 'dispatched') {
tools = [];
}
const code = activity.get('code');
const canUpdate = this.abilities.can('fleet-ops update order-config');

if (activity.get('code') === 'started' && this.abilities.can('fleet-ops update order-config')) {
tools = [addButton];
}
if (this.lifecycle) {
// The configured initial activity is the root: it can gain children but not be removed.
if (canUpdate) {
tools = code === this.lifecycle.initial ? [addButton] : [removeButton, addButton];
}
} else {
if (code === 'created' || code === 'dispatched') {
tools = [];
}

if (!this.immutableActivities.includes(activity.get('code')) && this.abilities.can('fleet-ops update order-config')) {
tools = [removeButton, addButton];
if (code === 'started' && canUpdate) {
tools = [addButton];
}

if (!this.immutableActivities.includes(code) && canUpdate) {
tools = [removeButton, addButton];
}
}

const activityNodeView = activityNode.findView(this.paper);
Expand Down
29 changes: 29 additions & 0 deletions addon/components/order/details.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,35 @@
)
)
}}
{{else if this.profile}}
{{#each this.profileSections key="key" as |section|}}
{{#if section.native}}
{{#let
(component
section.componentName
resource=@resource
onChange=section.onChange
isLoading=@isLoading
isLoadingActivity=@isLoadingActivity
reloadToken=this.effectiveProofReloadToken
)
as |NativeSection|
}}
<NativeSection />
{{/let}}
{{else}}
<LazyEngineComponent @component={{section.component}} as |ProfileSection|>
<ProfileSection
@resource={{@resource}}
@controller={{@controller}}
@permission={{get-write-permission @resource}}
@isLoading={{@isLoading}}
@profile={{this.profile}}
@onChange={{@onDetailsChanged}}
/>
</LazyEngineComponent>
{{/if}}
{{/each}}
{{else}}
<RegistryYield @registry="fleet-ops:component:order:details:start" as |RegistryComponent|>
<RegistryComponent @resource={{@resource}} @controller={{@controller}} @permission={{get-write-permission @resource}} @isLoading={{@isLoading}} />
Expand Down
26 changes: 26 additions & 0 deletions addon/components/order/details.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';

export default class OrderDetailsComponent extends Component {
@service orderPresentation;
@tracked proofReloadToken = 0;

get effectiveProofReloadToken() {
return `${this.args.proofReloadToken ?? 0}:${this.proofReloadToken}`;
}

/** The extension presentation profile applying to this order's config, if any. */
get profile() {
return this.orderPresentation.profileFor(this.args.resource);
}

/** Profile sections with the change handler each native section expects. */
get profileSections() {
const handlers = {
activity: this.handleActivityChanged,
detail: this.args.onDetailsChanged,
'custom-fields': this.args.onCustomFieldsChanged,
notes: this.args.onNotesChanged,
route: this.args.onRouteChanged,
payload: this.args.onPayloadChanged,
documents: this.args.onDocumentsChanged,
comments: this.args.onCommentsChanged,
metadata: this.args.onMetadataChanged,
};

return this.orderPresentation.renderableSectionsFor(this.profile, 'details').map((section) => {
return section.native ? { ...section, onChange: handlers[section.name] } : section;
});
}

@action handleActivityChanged(optionsOrActivity) {
if (typeof this.args.onActivityChanged === 'function') {
this.args.onActivityChanged(optionsOrActivity?.activityCreated ?? optionsOrActivity);
Expand Down
12 changes: 12 additions & 0 deletions addon/components/order/form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
RegistryYieldEnd=(component "registry-yield" registry="fleet-ops:component:order:form:end" order=@resource)
)
}}
{{else if this.profile}}
{{#each this.profileSections key="key" as |section|}}
{{#if section.native}}
{{#let (component section.componentName resource=@resource hiddenFields=this.hiddenFields) as |NativeSection|}}
<NativeSection />
{{/let}}
{{else}}
<LazyEngineComponent @component={{section.component}} as |ProfileSection|>
<ProfileSection @resource={{@resource}} @order={{@resource}} @controller={{@controller}} @profile={{this.profile}} @hiddenFields={{this.hiddenFields}} />
</LazyEngineComponent>
{{/if}}
{{/each}}
{{else}}
<RegistryYield @registry="fleet-ops:component:order:form:start" as |RegistryComponent|>
<RegistryComponent @order={{@resource}} @resource={{@resource}} />
Expand Down
14 changes: 14 additions & 0 deletions addon/components/order/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@ export default class OrderFormComponent extends Component {
@service customFieldsRegistry;
@service mapManager;
@service currentUser;
@service orderPresentation;
@tracked customFields;

constructor() {
super(...arguments);
this.orderConfigActions.loadAll.perform();
}

/** The extension presentation profile applying to this order's config, if any. */
get profile() {
return this.orderPresentation.profileFor(this.args.resource);
}

get profileSections() {
return this.orderPresentation.renderableSectionsFor(this.profile, 'form');
}

get hiddenFields() {
return this.orderPresentation.hiddenFieldsFor(this.args.resource);
}

@action selectFacilitator(model) {
this.args.resource.set('facilitator', model);
this.args.resource.set('driver', null);
Expand Down
34 changes: 30 additions & 4 deletions addon/components/order/form/details.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,27 @@
@onChange={{perform this.selectOrderConfig}}
@placeholder={{t "order.fields.order-type-placeholder"}}
@triggerClass="form-select form-input"
@disabled={{cannot-write @resource}}
@disabled={{or (cannot-write @resource) this.orderTypeLocked}}
as |orderConfig|
>
<SelectOption::OrderConfig @option={{orderConfig}} />
</PowerSelect>
</div>
</InputGroup>

{{#if this.profileDetailFields}}
<div class="contents">
<LazyEngineComponent @component={{this.profileDetailFields}} as |ProfileDetailFields|>
<ProfileDetailFields @resource={{@resource}} @order={{@resource}} @profile={{this.profile}} />
</LazyEngineComponent>
</div>
{{/if}}

{{#if this.show.internalId}}
<InputGroup @name={{t "order.fields.internal-id"}} @value={{@resource.internal_id}} @helpText={{t "order.fields.internal-id-help-text"}} @disabled={{cannot-write @resource}} />
{{/if}}

{{#if this.show.schedule}}
<InputGroup>
<InputLabel @labelText={{t "order.fields.schedule"}} @helpText={{t "order.fields.schedule-help-text"}} />
<DateTimeInput
Expand All @@ -30,7 +41,9 @@
@disabled={{or @resource.dispatched (cannot-write @resource)}}
/>
</InputGroup>
{{/if}}

{{#if this.show.customer}}
<InputGroup @name={{t "order.fields.customer"}} @helpText={{t "order.fields.customer-help-text"}}>
<ModelSelect
@modelName="customer"
Expand All @@ -48,7 +61,9 @@
<SelectOption::Customer @option={{model}} />
</ModelSelect>
</InputGroup>
{{/if}}

{{#if this.show.facilitator}}
<InputGroup @name={{t "order.fields.facilitator"}} @helpText={{t "order.fields.facilitator-help-text"}}>
<ModelSelect
@modelName="facilitator"
Expand All @@ -66,8 +81,9 @@
<SelectOption::Facilitator @option={{model}} />
</ModelSelect>
</InputGroup>
{{/if}}

{{#if (and @resource.facilitator.isIntegratedVendor @resource.facilitator.service_types.length)}}
{{#if (and this.show.serviceType @resource.facilitator.isIntegratedVendor @resource.facilitator.service_types.length)}}
<InputGroup @name={{t "order.fields.service-type"}} @helpText={{concat (t "order.fields.service-type-help-text") @resource.facilitator.name "."}}>
<Select
class="w-full"
Expand All @@ -82,6 +98,7 @@
</InputGroup>
{{/if}}

{{#if this.show.driver}}
<InputGroup @name={{t "order.fields.assign-driver"}} @helpText={{t "order.fields.assign-driver-help-text"}}>
<ModelSelect
@modelName="driver"
Expand All @@ -101,7 +118,9 @@
<SelectOption::Driver @option={{model}} />
</ModelSelect>
</InputGroup>
{{/if}}

{{#if this.show.vehicle}}
<InputGroup @name={{t "order.fields.assign-vehicle"}} @helpText={{t "order.fields.assign-vehicle-help-text"}}>
<ModelSelect
@modelName="vehicle"
Expand All @@ -120,8 +139,9 @@
<SelectOption::Vehicle @option={{model}} />
</ModelSelect>
</InputGroup>
{{/if}}

{{#if (and @resource.pod_required (not @resource.facilitator.isIntegratedVendor))}}
{{#if (and this.show.pod @resource.pod_required (not @resource.facilitator.isIntegratedVendor))}}
<InputGroup @name={{t "order.fields.proof-delivery"}} @helpText={{t "order.fields.proof-delivery-help-text"}} @required={{true}}>
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
<PowerSelect
Expand All @@ -142,7 +162,7 @@
</InputGroup>
{{/if}}

{{#if @resource.adhoc}}
{{#if (and this.show.adhoc @resource.adhoc)}}
<div>
<InputGroup
@name={{t "order.fields.adhoc-ping"}}
Expand All @@ -158,6 +178,7 @@
</div>
{{/if}}

{{#if this.show.adhoc}}
<div class="lg:col-span-2">
<InputGroup @wrapperClass="pt-2">
<Toggle
Expand All @@ -170,7 +191,9 @@
/>
</InputGroup>
</div>
{{/if}}

{{#if this.show.dispatch}}
<div class="lg:col-span-2">
<InputGroup @wrapperClass="pt-1">
<Toggle
Expand All @@ -183,7 +206,9 @@
/>
</InputGroup>
</div>
{{/if}}

{{#if this.show.pod}}
<div class="lg:col-span-2">
<InputGroup @wrapperClass="pt-1">
<Toggle
Expand All @@ -196,6 +221,7 @@
/>
</InputGroup>
</div>
{{/if}}

<RegistryYield @registry="fleet-ops:component:order:form:details" as |RegistryComponent|>
<RegistryComponent @order={{@resource}} @resource={{@resource}} />
Expand Down
Loading
Loading