Skip to content
Draft
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
63 changes: 63 additions & 0 deletions addon/components/cell/order-id-with-series.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<div class="flex items-center gap-1.5 overflow-visible" ...attributes>
{{#if this.isSeriesOrder}}
<span class="fleetops-recurring-order-indicator" tabindex="0">
<FaIcon @icon="arrows-rotate" />
<Attach::Popover @classNames="ember-attacher-tooltip clean fleetops-recurring-order-tooltip" @ariaRole="tooltip" @animation="scale" @placement="right" @interactive={{true}}>
<div class="fleetops-recurring-order-popover">
<div class="flex items-start justify-between gap-2 mb-2">
<div class="min-w-0">
<div class="fleetops-recurring-order-eyebrow">Recurring series</div>
<div class="fleetops-recurring-order-title">{{n-a this.series.name "Recurring series"}}</div>
</div>
<Badge @status={{this.series.status}}>{{smart-humanize this.series.status}}</Badge>
</div>

<div class="fleetops-recurring-order-schedule-card">
<div class="fleetops-recurring-order-summary">{{this.scheduleSummary}}</div>
<div class="fleetops-recurring-order-days">
{{#each this.scheduleDays as |day|}}
<span class="fleetops-recurring-order-day {{if day.scheduled 'is-scheduled'}} {{if day.highlighted 'is-highlighted'}}">{{day.label}}</span>
{{/each}}
</div>
</div>

<div class="grid grid-cols-2 gap-1.5 mt-2 text-xs">
<div class="fleetops-recurring-order-stat">
<span>Scheduled time</span>
<strong>{{n-a this.occurrenceTime "--"}}</strong>
</div>
<div class="fleetops-recurring-order-stat">
<span>Spawned</span>
<strong>{{this.spawnedCount}} orders</strong>
</div>
<div class="fleetops-recurring-order-stat col-span-2">
<span>This occurrence</span>
<strong>{{n-a this.occurrenceDateLabel "--"}}</strong>
</div>
</div>

{{#if this.series}}
<div class="fleetops-recurring-order-actions">
<button type="button" class="fleetops-recurring-order-action" {{on "click" this.openSeries}}>
<FaIcon @icon="arrow-up-right-from-square" />
<span>Open</span>
</button>
<button type="button" class="fleetops-recurring-order-action" {{on "click" this.skipNext}}>
<FaIcon @icon="forward-step" />
<span>Skip next</span>
</button>
<button type="button" class="fleetops-recurring-order-action" {{on "click" this.pauseSeries}}>
<FaIcon @icon="pause" />
<span>Pause</span>
</button>
</div>
{{/if}}
</div>
</Attach::Popover>
</span>
{{/if}}

<a href="javascript:;" class="text-blue-600 dark:text-blue-400 hover:underline font-normal" disabled={{and @column.permission (cannot @column.permission)}} {{on "click" this.openOrder}}>
{{@value}}
</a>
</div>
127 changes: 127 additions & 0 deletions addon/components/cell/order-id-with-series.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { format } from 'date-fns';
import { parseRrule, WEEKDAY_OPTIONS } from '../../utils/recurring-rrule';

export default class CellOrderIdWithSeriesComponent extends Component {
@service recurringOrderScheduleActions;

get order() {
return this.args.row;
}

get series() {
return this.order?.recurring_order_schedule;
}

get isSeriesOrder() {
return Boolean(
this.order?.is_recurring_generated === true ||
this.order?.meta?.is_recurring_generated === true ||
(this.order?.recurring_order_schedule_uuid && this.order?.recurring_occurrence_at) ||
(this.series?.public_id && this.order?.recurring_occurrence_at)
);
}

get recurrence() {
return parseRrule(this.series?.rrule);
}

get occurrenceDate() {
const value = this.order?.recurring_occurrence_at ?? this.order?.scheduled_at ?? this.series?.next_occurrence_at;
if (!value) {
return null;
}

const date = value instanceof Date ? value : new Date(value);

return Number.isNaN(date.getTime()) ? null : date;
}

get occurrenceWeekday() {
if (!this.occurrenceDate) {
return null;
}

return ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'][this.occurrenceDate.getDay()];
}

get occurrenceTime() {
return this.occurrenceDate ? format(this.occurrenceDate, 'HH:mm') : null;
}

get occurrenceDateLabel() {
return this.occurrenceDate ? format(this.occurrenceDate, 'EEE, d MMM yyyy') : null;
}

get scheduleDays() {
const weekdays = this.recurrence.weekdays ?? [];

if (this.recurrence.frequency === 'daily') {
return WEEKDAY_OPTIONS.map((day) => ({ ...day, scheduled: true, highlighted: day.code === this.occurrenceWeekday }));
}

return WEEKDAY_OPTIONS.map((day) => ({
...day,
scheduled: weekdays.includes(day.code),
highlighted: day.code === this.occurrenceWeekday,
}));
}

get scheduleSummary() {
const frequency = this.recurrence.frequency ?? 'weekly';
const interval = this.recurrence.interval > 1 ? `Every ${this.recurrence.interval} ${frequency}s` : `Every ${frequency}`;

if (frequency === 'weekly' && this.recurrence.weekdays?.length) {
const days = this.scheduleDays
.filter((day) => day.scheduled)
.map((day) => day.label)
.join(', ');

return `${interval} on ${days}`;
}

if (frequency === 'monthly' && this.recurrence.monthday) {
return `${interval} on day ${this.recurrence.monthday}`;
}

return interval;
}

get spawnedCount() {
return this.series?.generated_orders_count ?? this.series?.spawned_count ?? this.series?.meta?.spawned_count ?? this.series?.occurrences_count ?? 0;
}

@action openOrder(event) {
event?.preventDefault?.();
this.args.column?.onLinkClick?.(this.order);
}

@action openSeries(event) {
event?.preventDefault?.();
event?.stopPropagation?.();

if (this.series) {
return this.recurringOrderScheduleActions.transition.view(this.series);
}
}

@action skipNext(event) {
event?.preventDefault?.();
event?.stopPropagation?.();

if (this.series) {
return this.recurringOrderScheduleActions.skipNextOccurrence(this.series);
}
}

@action pauseSeries(event) {
event?.preventDefault?.();
event?.stopPropagation?.();

if (this.series) {
return this.recurringOrderScheduleActions.pause(this.series);
}
}
}
13 changes: 13 additions & 0 deletions addon/components/cell/recurring-series-badge.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{#if this.label}}
<button
type="button"
class="inline-flex items-center gap-1 rounded-md border border-indigo-200 bg-indigo-50 px-2 py-1 text-xs font-medium text-indigo-700 hover:bg-indigo-100 dark:border-indigo-800 dark:bg-indigo-950 dark:text-indigo-200"
{{on "click" this.openSeries}}
...attributes
>
<FaIcon @icon="arrows-rotate" />
<span class="truncate max-w-40">{{this.label}}</span>
</button>
{{else}}
<span class="text-gray-400 dark:text-gray-600">--</span>
{{/if}}
28 changes: 28 additions & 0 deletions addon/components/cell/recurring-series-badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';

export default class CellRecurringSeriesBadgeComponent extends Component {
@service recurringOrderScheduleActions;

get order() {
return this.args.row;
}

get series() {
return this.order?.recurring_order_schedule;
}

get label() {
return this.series?.name ?? this.series?.public_id ?? null;
}

@action openSeries(event) {
event?.preventDefault?.();
event?.stopPropagation?.();

if (this.series) {
return this.recurringOrderScheduleActions.transition.view(this.series);
}
}
}
11 changes: 11 additions & 0 deletions addon/components/cell/recurring-series-name.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="flex flex-col" ...attributes>
<a href="javascript:;" class="font-semibold text-blue-600 dark:text-blue-400 hover:underline" {{on "click" (fn @column.onLinkClick @row)}}>
{{n-a @row.name "Untitled series"}}
</a>
<div class="text-xs text-gray-500 dark:text-gray-400">
{{n-a @row.public_id}}
{{#if @row.meta.spawned_count}}
<span class="ml-1">- {{@row.meta.spawned_count}} spawned</span>
{{/if}}
</div>
</div>
3 changes: 3 additions & 0 deletions addon/components/cell/recurring-series-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Component from '@glimmer/component';

export default class CellRecurringSeriesNameComponent extends Component {}
12 changes: 12 additions & 0 deletions addon/components/cell/recurring-series-next-occurrence.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="flex flex-col" ...attributes>
<span class="text-sm text-gray-800 dark:text-gray-100">
{{#if @value}}
{{format-date-fns @value "d MMM yyyy HH:mm"}}
{{else}}
--
{{/if}}
</span>
{{#if @row.timezone}}
<span class="text-xs text-gray-500 dark:text-gray-400">{{@row.timezone}}</span>
{{/if}}
</div>
3 changes: 3 additions & 0 deletions addon/components/cell/recurring-series-next-occurrence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Component from '@glimmer/component';

export default class CellRecurringSeriesNextOccurrenceComponent extends Component {}
3 changes: 3 additions & 0 deletions addon/components/cell/recurring-series-pattern.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="text-xs text-gray-700 dark:text-gray-300 break-all" ...attributes>
{{n-a @value}}
</div>
3 changes: 3 additions & 0 deletions addon/components/cell/recurring-series-pattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Component from '@glimmer/component';

export default class CellRecurringSeriesPatternComponent extends Component {}
3 changes: 3 additions & 0 deletions addon/components/modals/recurring-order-schedule-form.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<RecurringOrderSchedule::Form @resource={{@options.resource}} @sourceOrder={{@options.sourceOrder}} />
</Modal::Default>
3 changes: 3 additions & 0 deletions addon/components/modals/recurring-order-schedules-manager.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<RecurringOrderSchedule::Manager />
</Modal::Default>
9 changes: 9 additions & 0 deletions addon/components/order/details/detail.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
{{#if @resource.adhoc}}
<Badge @hideStatusDot={{false}} @disableHumanize={{true}} @status="success">{{t "order.fields.ad-hoc"}}</Badge>
{{/if}}
{{#if @resource.meta.is_recurring_generated}}
<Badge @hideStatusDot={{false}} @status="info">Recurring</Badge>
{{/if}}
</div>
</:title>
<:default>
Expand Down Expand Up @@ -111,6 +114,12 @@
<div class="field-name">{{t "common.type"}}</div>
<div class="field-value">{{n-a (humanize @resource.type)}}</div>
</div>
{{#if @resource.meta.is_recurring_generated}}
<div class="field-info-container field-vertical-container dashed-bottom">
<div class="field-name">Recurring Schedule</div>
<div class="field-value">{{n-a @resource.meta.recurring_order_schedule_public_id @resource.meta.recurring_order_schedule_uuid}}</div>
</div>
{{/if}}
{{#if @resource.pod_required}}
<div class="field-info-container field-vertical-container">
<div class="field-name">{{t "order.fields.proof-of-delivery"}}</div>
Expand Down
11 changes: 10 additions & 1 deletion addon/components/order/form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
{{yield
(hash
Details=(component "order/form/details" resource=@resource)
Schedule=(component "order/form/schedule" resource=@resource repeatEnabled=@repeatEnabled seriesDraft=@seriesDraft onRepeatChange=@onRepeatChange)
OrchestratorConstraints=(component "order/form/orchestrator-constraints" resource=@resource)
CustomFields=(component "order/form/custom-fields" resource=@resource customFields=@customFields)
Route=(component "order/form/route" resource=@resource)
RegistryYield=(component "registry-yield" registry="fleet-ops:component:order:form" order=@resource)
Expand All @@ -14,7 +16,14 @@
)
}}
{{else}}
{{#if @scheduleFirst}}
<Order::Form::Schedule @resource={{@resource}} @repeatEnabled={{@repeatEnabled}} @seriesDraft={{@seriesDraft}} @onRepeatChange={{@onRepeatChange}} />
{{/if}}
<Order::Form::Details @resource={{@resource}} />
{{#unless @scheduleFirst}}
<Order::Form::Schedule @resource={{@resource}} @repeatEnabled={{@repeatEnabled}} @seriesDraft={{@seriesDraft}} @onRepeatChange={{@onRepeatChange}} />
{{/unless}}
<Order::Form::OrchestratorConstraints @resource={{@resource}} />
<Order::Form::Route @resource={{@resource}} />
<RegistryYield @registry="fleet-ops:component:order:form" as |RegistryComponent|>
<RegistryComponent @order={{@order}} />
Expand All @@ -25,4 +34,4 @@
<Order::Form::Documents @resource={{@resource}} />
<Order::Form::Metadata @resource={{@resource}} />
{{/if}}
</div>
</div>
Loading