diff --git a/addon/components/cell/contact-identity.hbs b/addon/components/cell/contact-identity.hbs
deleted file mode 100644
index 853719f46..000000000
--- a/addon/components/cell/contact-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/customer-identity.hbs b/addon/components/cell/customer-identity.hbs
deleted file mode 100644
index 2a25fec37..000000000
--- a/addon/components/cell/customer-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/driver-identity.hbs b/addon/components/cell/driver-identity.hbs
deleted file mode 100644
index 24624a8bd..000000000
--- a/addon/components/cell/driver-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/fleet-identity.hbs b/addon/components/cell/fleet-identity.hbs
deleted file mode 100644
index 2efe4afc3..000000000
--- a/addon/components/cell/fleet-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/order-identity.hbs b/addon/components/cell/order-identity.hbs
deleted file mode 100644
index f6e6ddebb..000000000
--- a/addon/components/cell/order-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/place-identity.hbs b/addon/components/cell/place-identity.hbs
deleted file mode 100644
index eea619a5e..000000000
--- a/addon/components/cell/place-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/vehicle-identity.hbs b/addon/components/cell/vehicle-identity.hbs
deleted file mode 100644
index 3374e7e79..000000000
--- a/addon/components/cell/vehicle-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/cell/vendor-identity.hbs b/addon/components/cell/vendor-identity.hbs
deleted file mode 100644
index 364f72b01..000000000
--- a/addon/components/cell/vendor-identity.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/contact/pill.hbs b/addon/components/contact/pill.hbs
deleted file mode 100644
index 43118e203..000000000
--- a/addon/components/contact/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/contact/summary.hbs b/addon/components/contact/summary.hbs
deleted file mode 100644
index b27212aac..000000000
--- a/addon/components/contact/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/customer/pill.hbs b/addon/components/customer/pill.hbs
deleted file mode 100644
index 160ea62ba..000000000
--- a/addon/components/customer/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/customer/summary.hbs b/addon/components/customer/summary.hbs
deleted file mode 100644
index 6c168790d..000000000
--- a/addon/components/customer/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/driver/pill.hbs b/addon/components/driver/pill.hbs
deleted file mode 100644
index cefeed497..000000000
--- a/addon/components/driver/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/driver/summary.hbs b/addon/components/driver/summary.hbs
deleted file mode 100644
index 2f2834fa9..000000000
--- a/addon/components/driver/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/fleet/pill.hbs b/addon/components/fleet/pill.hbs
deleted file mode 100644
index 68f25548d..000000000
--- a/addon/components/fleet/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/fleet/summary.hbs b/addon/components/fleet/summary.hbs
deleted file mode 100644
index fc035f943..000000000
--- a/addon/components/fleet/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/order/pill.hbs b/addon/components/order/pill.hbs
deleted file mode 100644
index 434fc468c..000000000
--- a/addon/components/order/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/order/summary.hbs b/addon/components/order/summary.hbs
deleted file mode 100644
index f3f42a464..000000000
--- a/addon/components/order/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/place/pill.hbs b/addon/components/place/pill.hbs
deleted file mode 100644
index 0b96aa8f5..000000000
--- a/addon/components/place/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/place/summary.hbs b/addon/components/place/summary.hbs
deleted file mode 100644
index a96ae6a4b..000000000
--- a/addon/components/place/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/select-option/contact.hbs b/addon/components/select-option/contact.hbs
deleted file mode 100644
index 08e782a09..000000000
--- a/addon/components/select-option/contact.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/customer.hbs b/addon/components/select-option/customer.hbs
deleted file mode 100644
index 5c626e92f..000000000
--- a/addon/components/select-option/customer.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/driver.hbs b/addon/components/select-option/driver.hbs
deleted file mode 100644
index 06f2f8fa1..000000000
--- a/addon/components/select-option/driver.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/fleet.hbs b/addon/components/select-option/fleet.hbs
deleted file mode 100644
index 88894a8dd..000000000
--- a/addon/components/select-option/fleet.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/order.hbs b/addon/components/select-option/order.hbs
deleted file mode 100644
index d8da9184c..000000000
--- a/addon/components/select-option/order.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/place.hbs b/addon/components/select-option/place.hbs
deleted file mode 100644
index 1e65f260b..000000000
--- a/addon/components/select-option/place.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/vehicle.hbs b/addon/components/select-option/vehicle.hbs
deleted file mode 100644
index d144b4962..000000000
--- a/addon/components/select-option/vehicle.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/select-option/vendor.hbs b/addon/components/select-option/vendor.hbs
deleted file mode 100644
index 83355a005..000000000
--- a/addon/components/select-option/vendor.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/addon/components/vehicle/pill.hbs b/addon/components/vehicle/pill.hbs
deleted file mode 100644
index 16e8dc110..000000000
--- a/addon/components/vehicle/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/vehicle/summary.hbs b/addon/components/vehicle/summary.hbs
deleted file mode 100644
index 577d3938c..000000000
--- a/addon/components/vehicle/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/components/vendor/pill.hbs b/addon/components/vendor/pill.hbs
deleted file mode 100644
index 4fcf04ef5..000000000
--- a/addon/components/vendor/pill.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
- {{yield resource}}
-
diff --git a/addon/components/vendor/summary.hbs b/addon/components/vendor/summary.hbs
deleted file mode 100644
index c231423b0..000000000
--- a/addon/components/vendor/summary.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/addon/utils/placeholder-images.js b/addon/utils/placeholder-images.js
index 28b8e36f4..f3af16abc 100644
--- a/addon/utils/placeholder-images.js
+++ b/addon/utils/placeholder-images.js
@@ -1,71 +1,6 @@
-import config from 'ember-get-config';
-
/**
- * Flat silhouettes shown wherever a resource has no photo, in one consistent style
- * across the console. They are inline data URIs so the engine does not depend on a
- * hosted asset; a console can override any of them through
- * `defaultValues.placeholders.` in its environment config.
+ * The styled placeholder silhouettes now live in `@fleetbase/fleetops-data`,
+ * where every extension that shows a driver, vehicle or contact can reach
+ * them. This module keeps the FleetOps import path working.
*/
-export const PLACEHOLDER_IMAGES = {
- trailer:
- 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48cmVjdCB4PSI4OCIgeT0iMTI4IiB3aWR0aD0iNDcwIiBoZWlnaHQ9IjE5NiIgcng9IjE2IiBmaWxsPSIjYmRiZGJkIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iMTAiLz48cmVjdCB4PSIxMDgiIHk9IjE1MCIgd2lkdGg9IjQzMCIgaGVpZ2h0PSIxNTIiIHJ4PSI4IiBmaWxsPSIjYzljOWM5Ii8+PHBhdGggZD0iTTEyOCAxNzhoMzkwTTEyOCAyMjZoMzkwTTEyOCAyNzRoMzkwIiBzdHJva2U9IiNiZGJkYmQiIHN0cm9rZS13aWR0aD0iNiIvPjxyZWN0IHg9IjUyMiIgeT0iMTQ2IiB3aWR0aD0iMTAiIGhlaWdodD0iMTYwIiByeD0iNCIgZmlsbD0iI2IwYjBiMCIvPjxyZWN0IHg9Ijg4IiB5PSIzMjQiIHdpZHRoPSI0NzAiIGhlaWdodD0iMTgiIHJ4PSI2IiBmaWxsPSIjYTlhOWE5Ii8+PHJlY3QgeD0iMTU2IiB5PSIzNDIiIHdpZHRoPSIxNCIgaGVpZ2h0PSI1MiIgcng9IjQiIGZpbGw9IiNhOWE5YTkiLz48cmVjdCB4PSIxNDYiIHk9IjM5MiIgd2lkdGg9IjM0IiBoZWlnaHQ9IjEwIiByeD0iNCIgZmlsbD0iI2E5YTlhOSIvPjxyZWN0IHg9Ijg4IiB5PSIzNDIiIHdpZHRoPSI1MiIgaGVpZ2h0PSIxNiIgcng9IjYiIGZpbGw9IiNhOWE5YTkiLz48Y2lyY2xlIGN4PSI0MTIiIGN5PSIzNjYiIHI9IjQwIiBmaWxsPSIjOGY4ZjhmIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iOCIvPjxjaXJjbGUgY3g9IjQxMiIgY3k9IjM2NiIgcj0iMTYiIGZpbGw9IiNkOWQ5ZDkiLz48Y2lyY2xlIGN4PSI1MDAiIGN5PSIzNjYiIHI9IjQwIiBmaWxsPSIjOGY4ZjhmIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iOCIvPjxjaXJjbGUgY3g9IjUwMCIgY3k9IjM2NiIgcj0iMTYiIGZpbGw9IiNkOWQ5ZDkiLz48L2c+PC9zdmc+',
- vehicle:
- 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDApIHNjYWxlKDEuMCkiIG9wYWNpdHk9IjEuMCI+PHJlY3QgeD0iMjE2IiB5PSIxMzIiIHdpZHRoPSIzNTAiIGhlaWdodD0iMTkyIiByeD0iMTQiIGZpbGw9IiNiZGJkYmQiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxyZWN0IHg9IjIzNiIgeT0iMTU0IiB3aWR0aD0iMzEwIiBoZWlnaHQ9IjE0OCIgcng9IjgiIGZpbGw9IiNjOWM5YzkiLz48cGF0aCBkPSJNMjU2IDE4MmgyNzBNMjU2IDIzMGgyNzBNMjU2IDI3OGgyNzAiIHN0cm9rZT0iI2JkYmRiZCIgc3Ryb2tlLXdpZHRoPSI2Ii8+PHBhdGggZD0iTTIxNiAzMjRWMTkwSDk2Yy0xMiAwLTIyIDgtMjYgMjBMNjAgMjQ0djgweiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTEwNCAyMDZoODh2NTJIODR6IiBmaWxsPSIjZDlkOWQ5Ii8+PHJlY3QgeD0iNjAiIHk9IjMyNCIgd2lkdGg9IjUwNiIgaGVpZ2h0PSIxOCIgcng9IjYiIGZpbGw9IiNhOWE5YTkiLz48cmVjdCB4PSI1NiIgeT0iMjkyIiB3aWR0aD0iMTgiIGhlaWdodD0iMzAiIHJ4PSI1IiBmaWxsPSIjZDlkOWQ5Ii8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iMzY2IiByPSI0MCIgZmlsbD0iIzhmOGY4ZiIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjgiLz48Y2lyY2xlIGN4PSIxNTAiIGN5PSIzNjYiIHI9IjE2IiBmaWxsPSIjZDlkOWQ5Ii8+PGNpcmNsZSBjeD0iNDcwIiBjeT0iMzY2IiByPSI0MCIgZmlsbD0iIzhmOGY4ZiIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjgiLz48Y2lyY2xlIGN4PSI0NzAiIGN5PSIzNjYiIHI9IjE2IiBmaWxsPSIjZDlkOWQ5Ii8+PC9nPjwvZz48L3N2Zz4=',
- driver: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48cGF0aCBkPSJNMTEwIDQ4MGMwLTk2IDc2LTE2NiAyMTAtMTY2czIxMCA3MCAyMTAgMTY2eiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI3MCAzMjJsNTAgNTQgNTAtNTQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q5ZDlkOSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PGNpcmNsZSBjeD0iMzIwIiBjeT0iMjA0IiByPSI5MiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzMCAxODZjMC02MiA0Mi05NiA5MC05NnM5MCAzNCA5MCA5NnoiIGZpbGw9IiNhOWE5YTkiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMjAgOTZ2ODgiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSI2Ii8+PGNpcmNsZSBjeD0iMzIwIiBjeT0iOTIiIHI9IjkiIGZpbGw9IiNhOWE5YTkiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSI2Ii8+PHBhdGggZD0iTTIyMiAxODZoMTkwYzY2IDAgOTYgMTAgOTYgMjJzLTMwIDIyLTk2IDIySDIyMnoiIGZpbGw9IiNhOWE5YTkiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PC9nPjwvc3ZnPg==',
- contact:
- 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48cGF0aCBkPSJNMTEwIDQ4MGMwLTk2IDc2LTE2NiAyMTAtMTY2czIxMCA3MCAyMTAgMTY2eiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI3MCAzMjJsNTAgNTQgNTAtNTQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q5ZDlkOSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PGNpcmNsZSBjeD0iMzIwIiBjeT0iMTg4IiByPSI5NiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PC9nPjwvc3ZnPg==',
- customer:
- 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48cGF0aCBkPSJNMTEwIDQ4MGMwLTk2IDc2LTE2NiAyMTAtMTY2czIxMCA3MCAyMTAgMTY2eiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI3MCAzMjJsNTAgNTQgNTAtNTQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q5ZDlkOSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PGNpcmNsZSBjeD0iMzIwIiBjeT0iMTg4IiByPSI5NiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iNDkwIiBjeT0iMzkyIiByPSI2MCIgZmlsbD0iIzhmOGY4ZiIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTQ1OCAzOTRsMjIgMjIgNDQtNDgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q5ZDlkOSIgc3Ryb2tlLXdpZHRoPSIxNCIvPjwvZz48L3N2Zz4=',
- vendor: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48cGF0aCBkPSJNNzIgMjAwTDMyMCA5NmwyNDggMTA0djI0SDcyeiIgZmlsbD0iI2E5YTlhOSIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHJlY3QgeD0iMTAwIiB5PSIyMjIiIHdpZHRoPSI0NDAiIGhlaWdodD0iMTkwIiByeD0iOCIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHJlY3QgeD0iMjcyIiB5PSIyOTIiIHdpZHRoPSI5NiIgaGVpZ2h0PSIxMjAiIHJ4PSI2IiBmaWxsPSIjOGY4ZjhmIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iOCIvPjxyZWN0IHg9IjE0MCIgeT0iMjYyIiB3aWR0aD0iODgiIGhlaWdodD0iNjYiIHJ4PSI2IiBmaWxsPSIjZDlkOWQ5Ii8+PHJlY3QgeD0iNDEyIiB5PSIyNjIiIHdpZHRoPSI4OCIgaGVpZ2h0PSI2NiIgcng9IjYiIGZpbGw9IiNkOWQ5ZDkiLz48cGF0aCBkPSJNMTg0IDI2MnY2Nk0xNDAgMjk1aDg4TTQ1NiAyNjJ2NjZNNDEyIDI5NWg4OCIgc3Ryb2tlPSIjYmRiZGJkIiBzdHJva2Utd2lkdGg9IjYiLz48cmVjdCB4PSI2MCIgeT0iNDEyIiB3aWR0aD0iNTIwIiBoZWlnaHQ9IjE2IiByeD0iNiIgZmlsbD0iI2E5YTlhOSIvPjwvZz48L3N2Zz4=',
- fleet: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNDgwIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQ4MCI+PGcgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNTAgLTQwKSBzY2FsZSgwLjcyKSIgb3BhY2l0eT0iMC40NSI+PHJlY3QgeD0iMjE2IiB5PSIxMzIiIHdpZHRoPSIzNTAiIGhlaWdodD0iMTkyIiByeD0iMTQiIGZpbGw9IiNiZGJkYmQiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxyZWN0IHg9IjIzNiIgeT0iMTU0IiB3aWR0aD0iMzEwIiBoZWlnaHQ9IjE0OCIgcng9IjgiIGZpbGw9IiNjOWM5YzkiLz48cGF0aCBkPSJNMjU2IDE4MmgyNzBNMjU2IDIzMGgyNzBNMjU2IDI3OGgyNzAiIHN0cm9rZT0iI2JkYmRiZCIgc3Ryb2tlLXdpZHRoPSI2Ii8+PHBhdGggZD0iTTIxNiAzMjRWMTkwSDk2Yy0xMiAwLTIyIDgtMjYgMjBMNjAgMjQ0djgweiIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTEwNCAyMDZoODh2NTJIODR6IiBmaWxsPSIjZDlkOWQ5Ii8+PHJlY3QgeD0iNjAiIHk9IjMyNCIgd2lkdGg9IjUwNiIgaGVpZ2h0PSIxOCIgcng9IjYiIGZpbGw9IiNhOWE5YTkiLz48cmVjdCB4PSI1NiIgeT0iMjkyIiB3aWR0aD0iMTgiIGhlaWdodD0iMzAiIHJ4PSI1IiBmaWxsPSIjZDlkOWQ5Ii8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iMzY2IiByPSI0MCIgZmlsbD0iIzhmOGY4ZiIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjgiLz48Y2lyY2xlIGN4PSIxNTAiIGN5PSIzNjYiIHI9IjE2IiBmaWxsPSIjZDlkOWQ5Ii8+PGNpcmNsZSBjeD0iNDcwIiBjeT0iMzY2IiByPSI0MCIgZmlsbD0iIzhmOGY4ZiIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjgiLz48Y2lyY2xlIGN4PSI0NzAiIGN5PSIzNjYiIHI9IjE2IiBmaWxsPSIjZDlkOWQ5Ii8+PC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgwIDEwKSBzY2FsZSgwLjgpIiBvcGFjaXR5PSIwLjciPjxyZWN0IHg9IjIxNiIgeT0iMTMyIiB3aWR0aD0iMzUwIiBoZWlnaHQ9IjE5MiIgcng9IjE0IiBmaWxsPSIjYmRiZGJkIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iMTAiLz48cmVjdCB4PSIyMzYiIHk9IjE1NCIgd2lkdGg9IjMxMCIgaGVpZ2h0PSIxNDgiIHJ4PSI4IiBmaWxsPSIjYzljOWM5Ii8+PHBhdGggZD0iTTI1NiAxODJoMjcwTTI1NiAyMzBoMjcwTTI1NiAyNzhoMjcwIiBzdHJva2U9IiNiZGJkYmQiIHN0cm9rZS13aWR0aD0iNiIvPjxwYXRoIGQ9Ik0yMTYgMzI0VjE5MEg5NmMtMTIgMC0yMiA4LTI2IDIwTDYwIDI0NHY4MHoiIGZpbGw9IiNiZGJkYmQiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0xMDQgMjA2aDg4djUySDg0eiIgZmlsbD0iI2Q5ZDlkOSIvPjxyZWN0IHg9IjYwIiB5PSIzMjQiIHdpZHRoPSI1MDYiIGhlaWdodD0iMTgiIHJ4PSI2IiBmaWxsPSIjYTlhOWE5Ii8+PHJlY3QgeD0iNTYiIHk9IjI5MiIgd2lkdGg9IjE4IiBoZWlnaHQ9IjMwIiByeD0iNSIgZmlsbD0iI2Q5ZDlkOSIvPjxjaXJjbGUgY3g9IjE1MCIgY3k9IjM2NiIgcj0iNDAiIGZpbGw9IiM4ZjhmOGYiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iMzY2IiByPSIxNiIgZmlsbD0iI2Q5ZDlkOSIvPjxjaXJjbGUgY3g9IjQ3MCIgY3k9IjM2NiIgcj0iNDAiIGZpbGw9IiM4ZjhmOGYiIHN0cm9rZT0iI2RlZGVkZSIgc3Ryb2tlLXdpZHRoPSI4Ii8+PGNpcmNsZSBjeD0iNDcwIiBjeT0iMzY2IiByPSIxNiIgZmlsbD0iI2Q5ZDlkOSIvPjwvZz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDYwKSBzY2FsZSgwLjg4KSIgb3BhY2l0eT0iMS4wIj48cmVjdCB4PSIyMTYiIHk9IjEzMiIgd2lkdGg9IjM1MCIgaGVpZ2h0PSIxOTIiIHJ4PSIxNCIgZmlsbD0iI2JkYmRiZCIgc3Ryb2tlPSIjZGVkZWRlIiBzdHJva2Utd2lkdGg9IjEwIi8+PHJlY3QgeD0iMjM2IiB5PSIxNTQiIHdpZHRoPSIzMTAiIGhlaWdodD0iMTQ4IiByeD0iOCIgZmlsbD0iI2M5YzljOSIvPjxwYXRoIGQ9Ik0yNTYgMTgyaDI3ME0yNTYgMjMwaDI3ME0yNTYgMjc4aDI3MCIgc3Ryb2tlPSIjYmRiZGJkIiBzdHJva2Utd2lkdGg9IjYiLz48cGF0aCBkPSJNMjE2IDMyNFYxOTBIOTZjLTEyIDAtMjIgOC0yNiAyMEw2MCAyNDR2ODB6IiBmaWxsPSIjYmRiZGJkIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTA0IDIwNmg4OHY1Mkg4NHoiIGZpbGw9IiNkOWQ5ZDkiLz48cmVjdCB4PSI2MCIgeT0iMzI0IiB3aWR0aD0iNTA2IiBoZWlnaHQ9IjE4IiByeD0iNiIgZmlsbD0iI2E5YTlhOSIvPjxyZWN0IHg9IjU2IiB5PSIyOTIiIHdpZHRoPSIxOCIgaGVpZ2h0PSIzMCIgcng9IjUiIGZpbGw9IiNkOWQ5ZDkiLz48Y2lyY2xlIGN4PSIxNTAiIGN5PSIzNjYiIHI9IjQwIiBmaWxsPSIjOGY4ZjhmIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iOCIvPjxjaXJjbGUgY3g9IjE1MCIgY3k9IjM2NiIgcj0iMTYiIGZpbGw9IiNkOWQ5ZDkiLz48Y2lyY2xlIGN4PSI0NzAiIGN5PSIzNjYiIHI9IjQwIiBmaWxsPSIjOGY4ZjhmIiBzdHJva2U9IiNkZWRlZGUiIHN0cm9rZS13aWR0aD0iOCIvPjxjaXJjbGUgY3g9IjQ3MCIgY3k9IjM2NiIgcj0iMTYiIGZpbGw9IiNkOWQ5ZDkiLz48L2c+PC9nPjwvc3ZnPg==',
-};
-
-/**
- * Hosted images the data models and console config fall back to when a record has no
- * photo. Treat them as "no photo" so the styled placeholder wins over the legacy PNG.
- */
-const LEGACY_DEFAULT_PATTERN = /(no-avatar|vehicle-placeholder|image-file-icon|fallback-placeholder|default-extension-icon)\.(png|svg|jpe?g)/i;
-
-const CONFIG_KEYS = {
- vehicle: 'vehicleImage',
- driver: 'driverImage',
- vendor: 'vendorImage',
- contact: 'contactImage',
- customer: 'customerImage',
- fleet: 'fleetImage',
- trailer: 'trailerImage',
-};
-
-export function getPlaceholderImage(type = 'contact') {
- const overrides = config?.defaultValues?.placeholders ?? {};
- // A console that already replaced its hosted defaults with inline images wins;
- // hosted PNG defaults are ignored so the silhouette set stays consistent.
- const configured = config?.defaultValues?.[CONFIG_KEYS[type]];
- const inlineConfigured = typeof configured === 'string' && configured.startsWith('data:') ? configured : null;
-
- return overrides[type] || inlineConfigured || PLACEHOLDER_IMAGES[type] || PLACEHOLDER_IMAGES.contact;
-}
-
-export function isDefaultImage(url) {
- if (typeof url !== 'string' || url.trim() === '') {
- return true;
- }
-
- if (LEGACY_DEFAULT_PATTERN.test(url)) {
- return true;
- }
-
- const defaults = Object.values(config?.defaultValues ?? {}).filter((value) => typeof value === 'string');
-
- return defaults.includes(url);
-}
-
-/**
- * The image to show for a record: its own photo, or the styled placeholder when the
- * photo is missing or one of the legacy hosted defaults.
- */
-export function resolveResourceImage(url, type) {
- return isDefaultImage(url) ? getPlaceholderImage(type) : url;
-}
-
-export default getPlaceholderImage;
+export { PLACEHOLDER_IMAGES, getPlaceholderImage, isDefaultImage, resolveResourceImage, default } from '@fleetbase/fleetops-data/utils/placeholder-images';
diff --git a/addon/utils/resource-descriptors/assets.js b/addon/utils/resource-descriptors/assets.js
index 3875af786..3b38dce42 100644
--- a/addon/utils/resource-descriptors/assets.js
+++ b/addon/utils/resource-descriptors/assets.js
@@ -1,68 +1,13 @@
import { get } from '@ember/object';
import { first, present, relation, photo, icon, badge, badges, fact, relatedFact, money, join, panelOpener } from './helpers';
+import { sharedDescriptors } from './shared';
/**
* Vehicles, trailers, equipment, parts, generic assets and warranties.
*/
export default function buildAssetDescriptors(owner) {
return [
- {
- key: 'vehicle',
- labelKey: 'resource.vehicle',
- icon: 'truck',
- modelNames: ['vehicle'],
- aliases: ['attachable-vehicle', 'maintenance-subject-vehicle'],
- polymorphicTypes: ['fleet-ops:vehicle', 'Fleetbase\\FleetOps\\Models\\Vehicle'],
- permission: 'fleet-ops view vehicle',
- statusTones: {
- available: 'text-green-500',
- active: 'text-green-500',
- in_service: 'text-green-500',
- maintenance: 'text-yellow-500',
- unavailable: 'text-gray-400',
- inactive: 'text-gray-400',
- out_of_service: 'text-red-500',
- },
- title: (vehicle) =>
- first(vehicle, 'displayName', 'display_name', 'name', 'yearMakeModel', 'public_id') ?? join([get(vehicle, 'year'), get(vehicle, 'make'), get(vehicle, 'model')]),
- identifier: (vehicle) => first(vehicle, 'plate_number', 'call_sign', 'vin', 'serial_number'),
- image: (vehicle) => photo(vehicle, 'vehicle'),
- online: (vehicle) => {
- const online = get(vehicle, 'online');
-
- return typeof online === 'boolean' ? online : undefined;
- },
- status: (vehicle) => first(vehicle, 'status'),
- badges: (vehicle) => {
- const driver = relation(owner, vehicle, 'driver');
-
- return badges(
- badge('plate', 'id-card', first(vehicle, 'plate_number', 'call_sign', 'vehicle_number')),
- badge('driver', 'user', first(driver, 'name', 'displayName') ?? first(vehicle, 'driver_name'), {
- relatedType: 'driver',
- relatedId: driver?.id ?? get(vehicle, 'driver_uuid'),
- })
- );
- },
- selectDetails: (vehicle) => [first(vehicle, 'plate_number', 'vin', 'serial_number', 'call_sign'), first(vehicle, 'driver_name')],
- facts: (vehicle) => {
- const driver = relation(owner, vehicle, 'driver');
- const trailers = relation(owner, vehicle, 'trailers');
- const trailer = trailers && typeof trailers.objectAt === 'function' ? trailers.objectAt(0) : Array.isArray(trailers) ? trailers[0] : null;
- const extra = trailers?.length > 1 ? ` (+${trailers.length - 1})` : '';
-
- return [
- fact('make-model', join([get(vehicle, 'year'), get(vehicle, 'make'), get(vehicle, 'model'), get(vehicle, 'trim')])),
- fact('plate', join([first(vehicle, 'plate_number'), first(vehicle, 'vin')], ' · ')),
- relatedFact('driver', driver, 'driver', first(vehicle, 'driver_name')),
- trailer ? { ...relatedFact('trailer', trailer, 'trailer', first(trailer, 'displayName', 'display_name', 'name')), suffix: extra } : fact('trailer', null),
- fact('odometer', present(get(vehicle, 'odometer')) ? join([get(vehicle, 'odometer'), get(vehicle, 'odometer_unit')]) : null),
- fact('status', first(vehicle, 'status'), { format: 'humanize' }),
- ];
- },
- open: panelOpener(owner, 'vehicle-actions'),
- components: { identity: 'cell/vehicle-identity' },
- },
+ ...sharedDescriptors(owner, ['vehicle']),
{
key: 'trailer',
labelKey: 'resource.trailer',
diff --git a/addon/utils/resource-descriptors/helpers.js b/addon/utils/resource-descriptors/helpers.js
index ce786123f..8d2065ad6 100644
--- a/addon/utils/resource-descriptors/helpers.js
+++ b/addon/utils/resource-descriptors/helpers.js
@@ -1,59 +1,29 @@
-import formatDate from '@fleetbase/ember-ui/utils/format-date';
-import { get } from '@ember/object';
-import { getPlaceholderImage, resolveResourceImage } from '../placeholder-images';
+import { first, relation } from '@fleetbase/fleetops-data/utils/resource-descriptors/helpers';
/**
- * Small building blocks the FleetOps descriptors share. They are written
- * against attribute names, so an identity stub or an API payload renders
- * the same as an Ember Data record.
+ * The building blocks the FleetOps descriptors share. The ones a descriptor
+ * needs to read a record live in `@fleetbase/fleetops-data`, so the shared
+ * resources render the same in every extension; this module re-exports them
+ * and adds the openers that only make sense with the FleetOps engine's own
+ * services and routes.
*/
-
-export function present(value) {
- return value !== undefined && value !== null && String(value).trim() !== '';
-}
-
-/** The first present value at any of the paths. */
-export function first(record, ...paths) {
- if (!record) {
- return null;
- }
-
- for (const path of paths) {
- const value = get(record, path);
-
- if (present(value)) {
- return value;
- }
- }
-
- return null;
-}
-
-/** A related record read through its reference, never a promise proxy. */
-export function relation(owner, record, name) {
- const registry = owner?.lookup?.('service:resource-registry');
-
- if (registry && typeof registry.relationValue === 'function') {
- return registry.relationValue(record, name);
- }
-
- const value = record ? get(record, name) : null;
-
- if (value && typeof value === 'object' && typeof value.then === 'function') {
- return value.content ?? null;
- }
-
- return value ?? null;
-}
-
-/** A photo with the styled placeholder as fallback. */
-export function photo(record, type, path = 'photo_url') {
- return { url: resolveResourceImage(get(record, path), type), fallback: getPlaceholderImage(type), shape: type === 'vehicle' || type === 'trailer' ? 'square' : 'round' };
-}
-
-export function icon(name, iconClass) {
- return iconClass ? { icon: name, iconClass } : { icon: name };
-}
+export {
+ present,
+ first,
+ lookupService,
+ relation,
+ photo,
+ icon,
+ badge,
+ badges,
+ fact,
+ relatedFact,
+ dateLabel,
+ typeLabel,
+ money,
+ join,
+ polymorphicType,
+} from '@fleetbase/fleetops-data/utils/resource-descriptors/helpers';
/** A coloured tile for records that carry their own colour (service areas, zones). */
export function colourTile(record, name) {
@@ -62,75 +32,6 @@ export function colourTile(record, name) {
return colour ? { icon: name, iconClass: 'resource-colour-tile', colour } : { icon: name };
}
-export function badge(key, iconName, label, extra = {}) {
- return present(label) ? { key, icon: iconName, label, ...extra } : null;
-}
-
-export function badges(...list) {
- return list.filter(Boolean);
-}
-
-export function fact(label, value, extra = {}) {
- return { labelKey: `resource-summary.facts.${label}`, value, ...extra };
-}
-
-/** A fact that renders as the related record's pill when the record is loaded. */
-export function relatedFact(label, related, relatedType, fallbackValue) {
- return { labelKey: `resource-summary.facts.${label}`, related: related ?? null, relatedType, value: fallbackValue ?? null };
-}
-
-/**
- * A date the way the console writes one everywhere else (date-fns, not the
- * browser locale), or null for anything that is not a date.
- */
-export function dateLabel(value, pattern = 'dd MMM yyyy, HH:mm') {
- if (!present(value)) {
- return null;
- }
-
- const date = value instanceof Date ? value : new Date(value);
-
- return Number.isNaN(date.getTime()) ? null : formatDate(date, pattern);
-}
-
-/**
- * A contact's type the way a person reads it: "customer-fleet-ops:contact"
- * and "customer" both become "Customer"; anything unreadable becomes null.
- */
-export function typeLabel(value) {
- if (!present(value)) {
- return null;
- }
-
- const head = String(value)
- .split(':')[0]
- .replace(/-fleet-ops$/, '')
- .replace(/[-_]+/g, ' ')
- .trim();
-
- return head ? head.charAt(0).toUpperCase() + head.slice(1) : null;
-}
-
-export function money(amount, currency) {
- if (!present(amount)) {
- return null;
- }
-
- return present(currency) ? `${amount} ${currency}` : String(amount);
-}
-
-export function join(parts, separator = ' ') {
- return parts.filter(present).join(separator) || null;
-}
-
-/** The resolved `*_type` for a polymorphic relation, from the record or a `_type` attribute. */
-export function polymorphicType(record, relationName, typeAttr) {
- const related = record ? get(record, relationName) : null;
- const modelName = related?.constructor?.modelName ?? related?.content?.constructor?.modelName;
-
- return modelName ?? (typeAttr ? get(record, typeAttr) : null) ?? null;
-}
-
/**
* An opener that hands the record to an action service's context panel,
* falling back to its route transition. Resolved lazily from the engine
diff --git a/addon/utils/resource-descriptors/operations.js b/addon/utils/resource-descriptors/operations.js
index 6247438b9..ed6721e4c 100644
--- a/addon/utils/resource-descriptors/operations.js
+++ b/addon/utils/resource-descriptors/operations.js
@@ -1,5 +1,6 @@
import { get } from '@ember/object';
import { first, present, relation, icon, colourTile, fact, relatedFact, money, join, panelOpener, routeOpener, polymorphicType, dateLabel } from './helpers';
+import { sharedDescriptors } from './shared';
/**
* Places, orders, order configs, service rates, service areas, zones,
@@ -7,67 +8,7 @@ import { first, present, relation, icon, colourTile, fact, relatedFact, money, j
*/
export default function buildOperationsDescriptors(owner) {
return [
- {
- key: 'place',
- labelKey: 'resource.place',
- icon: 'location-dot',
- modelNames: ['place'],
- polymorphicTypes: ['fleet-ops:place', 'Fleetbase\\FleetOps\\Models\\Place'],
- permission: 'fleet-ops view place',
- title: (place) => first(place, 'displayName', 'name', 'address', 'street1', 'public_id'),
- identifier: (place) => join([first(place, 'city'), first(place, 'country')], ', ') ?? first(place, 'public_id'),
- image: () => icon('location-dot'),
- selectDetails: (place) => [first(place, 'address', 'street1'), join([first(place, 'city'), first(place, 'country')], ', ')],
- facts: (place) => [
- fact('address', first(place, 'address', 'street1')),
- fact('phone', first(place, 'phone')),
- fact('type', first(place, 'type'), { format: 'humanize' }),
- relatedFact('vendor', relation(owner, place, 'vendor'), 'vendor', first(place, 'vendor_name')),
- fact('coordinates', first(place, 'positionString') ?? (present(get(place, 'latitude')) ? `${get(place, 'latitude')}, ${get(place, 'longitude')}` : null)),
- ],
- open: panelOpener(owner, 'place-actions'),
- },
- {
- key: 'order',
- labelKey: 'resource.order',
- icon: 'box',
- modelNames: ['order'],
- polymorphicTypes: ['fleet-ops:order', 'Fleetbase\\FleetOps\\Models\\Order'],
- permission: 'fleet-ops view order',
- statusTones: {
- created: 'text-gray-400',
- preparing: 'text-yellow-500',
- dispatched: 'text-yellow-500',
- started: 'text-yellow-500',
- in_progress: 'text-yellow-500',
- enroute: 'text-yellow-500',
- completed: 'text-green-500',
- delivered: 'text-green-500',
- canceled: 'text-red-500',
- cancelled: 'text-red-500',
- failed: 'text-red-500',
- },
- title: (order) => first(order, 'tracking', 'tracking_number.tracking_number', 'public_id'),
- identifier: (order) => first(order, 'public_id', 'internal_id'),
- image: () => icon('box'),
- status: (order) => first(order, 'status'),
- selectDetails: (order) => [first(order, 'public_id'), first(order, 'status')],
- facts: (order) => [
- fact('status', first(order, 'status'), { format: 'humanize' }),
- relatedFact('customer', relation(owner, order, 'customer'), polymorphicType(order, 'customer', 'customer_type'), first(order, 'customer_name')),
- relatedFact('driver', relation(owner, order, 'driver_assigned'), 'driver', first(order, 'driver_name')),
- fact('route', join([first(order, 'pickupName', 'pickup_name'), first(order, 'dropoffName', 'dropoff_name')], ' → ')),
- fact('scheduled', get(order, 'scheduled_at'), { format: 'date' }),
- fact('order-config', first(order, 'order_config.name', 'type')),
- ],
- open: (order) => {
- if (!order || order.isIdentityStub || !first(order, 'id', 'uuid')) {
- return false;
- }
-
- return panelOpener(owner, 'order-actions')(order);
- },
- },
+ ...sharedDescriptors(owner, ['place', 'order']),
{
key: 'order-config',
labelKey: 'resource.order-config',
diff --git a/addon/utils/resource-descriptors/people.js b/addon/utils/resource-descriptors/people.js
index 7a8eec6bc..926ce1014 100644
--- a/addon/utils/resource-descriptors/people.js
+++ b/addon/utils/resource-descriptors/people.js
@@ -1,88 +1,13 @@
import { get } from '@ember/object';
-import { first, present, relation, photo, badge, badges, fact, relatedFact, join, panelOpener, dateLabel, typeLabel } from './helpers';
+import { first, photo, fact, panelOpener } from './helpers';
+import { sharedDescriptors } from './shared';
/**
* Drivers, vendors, contacts, customers and fleets.
*/
export default function buildPeopleDescriptors(owner) {
return [
- {
- key: 'driver',
- labelKey: 'resource.driver',
- icon: 'id-card',
- modelNames: ['driver'],
- aliases: ['attachable-driver', 'facilitator-driver', 'fleet-driver'],
- polymorphicTypes: ['fleet-ops:driver', 'Fleetbase\\FleetOps\\Models\\Driver'],
- permission: 'fleet-ops view driver',
- statusTones: {
- available: 'text-green-500',
- active: 'text-green-500',
- on_duty: 'text-green-500',
- busy: 'text-yellow-500',
- assigned: 'text-yellow-500',
- unavailable: 'text-gray-400',
- offline: 'text-gray-400',
- suspended: 'text-red-500',
- },
- title: (driver) => first(driver, 'name', 'displayName', 'display_name', 'public_id'),
- identifier: (driver) => first(driver, 'phone', 'email'),
- image: (driver) => photo(driver, 'driver'),
- online: (driver) => {
- const online = get(driver, 'online');
-
- return typeof online === 'boolean' ? online : undefined;
- },
- status: (driver) => first(driver, 'status'),
- badges: (driver) => {
- const vehicle = relation(owner, driver, 'vehicle');
- const label = first(vehicle, 'displayName', 'display_name', 'name') ?? first(driver, 'vehicle_assigned.display_name', 'vehicle_name');
-
- return badges(badge('vehicle', 'car', label, { relatedType: 'vehicle', relatedId: vehicle?.id ?? get(driver, 'vehicle_uuid') }));
- },
- selectDetails: (driver) => [first(driver, 'phone'), first(driver, 'email')],
- facts: (driver) => [
- fact('phone', first(driver, 'phone')),
- fact('email', first(driver, 'email')),
- relatedFact('vehicle', relation(owner, driver, 'vehicle'), 'vehicle', first(driver, 'vehicle_name')),
- fact(
- 'licence',
- join(
- [
- first(driver, 'drivers_license_number'),
- dateLabel(get(driver, 'license_expiry'), 'dd MMM yyyy') ? `expires ${dateLabel(get(driver, 'license_expiry'), 'dd MMM yyyy')}` : null,
- ],
- ' · '
- )
- ),
- relatedFact('vendor', relation(owner, driver, 'vendor'), 'vendor', first(driver, 'vendor_name')),
- fact('status', first(driver, 'status'), { format: 'humanize' }),
- ],
- open: panelOpener(owner, 'driver-actions'),
- components: { identity: 'cell/driver-identity' },
- },
- {
- key: 'vendor',
- labelKey: 'resource.vendor',
- icon: 'building',
- modelNames: ['vendor'],
- aliases: ['facilitator-vendor', 'customer-vendor'],
- polymorphicTypes: ['fleet-ops:vendor', 'Fleetbase\\FleetOps\\Models\\Vendor'],
- permission: 'fleet-ops view vendor',
- title: (vendor) => first(vendor, 'name', 'public_id'),
- identifier: (vendor) => first(vendor, 'prettyType', 'internal_id', 'business_id'),
- image: (vendor) => photo(vendor, 'vendor', 'logo_url'),
- status: (vendor) => first(vendor, 'status'),
- selectDetails: (vendor) => [first(vendor, 'email'), first(vendor, 'phone')],
- facts: (vendor) => [
- fact('type', first(vendor, 'prettyType', 'type'), { format: 'humanize' }),
- fact('email', first(vendor, 'email')),
- fact('phone', first(vendor, 'phone')),
- fact('website', first(vendor, 'website_url')),
- fact('address', first(vendor, 'address', 'place.address', 'address_street')),
- fact('country', first(vendor, 'country')),
- ],
- open: panelOpener(owner, 'vendor-actions'),
- },
+ ...sharedDescriptors(owner, ['driver', 'vendor', 'contact', 'customer', 'fleet']),
{
key: 'integrated-vendor',
labelKey: 'resource.integrated-vendor',
@@ -105,69 +30,5 @@ export default function buildPeopleDescriptors(owner) {
],
open: panelOpener(owner, 'integrated-vendor-actions'),
},
- {
- key: 'contact',
- labelKey: 'resource.contact',
- icon: 'address-book',
- modelNames: ['contact'],
- aliases: ['facilitator-contact', 'customer-contact'],
- polymorphicTypes: ['fleet-ops:contact', 'Fleetbase\\FleetOps\\Models\\Contact'],
- permission: 'fleet-ops view contact',
- title: (contact) => first(contact, 'name', 'public_id'),
- identifier: (contact) => first(contact, 'title') ?? typeLabel(first(contact, 'type')),
- image: (contact) => photo(contact, 'contact'),
- selectDetails: (contact) => [first(contact, 'email'), first(contact, 'phone')],
- facts: (contact) => [
- fact('title', first(contact, 'title')),
- fact('email', first(contact, 'email')),
- fact('phone', first(contact, 'phone')),
- relatedFact('place', relation(owner, contact, 'place'), 'place', first(contact, 'address', 'place.address')),
- relatedFact('user', relation(owner, contact, 'user'), 'user', first(contact, 'user.name')),
- ],
- open: panelOpener(owner, 'contact-actions'),
- },
- {
- key: 'customer',
- labelKey: 'resource.customer',
- icon: 'user-tag',
- modelNames: ['customer'],
- aliases: ['facilitator-customer'],
- polymorphicTypes: ['fleet-ops:customer', 'Fleetbase\\FleetOps\\Models\\Customer'],
- permission: 'fleet-ops view contact',
- title: (customer) => first(customer, 'name', 'public_id'),
- identifier: (customer) => typeLabel(first(customer, 'customer_type', 'type')) ?? 'Customer',
- image: (customer) => photo(customer, 'customer'),
- selectDetails: (customer) => [first(customer, 'email'), first(customer, 'phone')],
- facts: (customer) => [
- fact('type', typeLabel(first(customer, 'customer_type', 'type'))),
- fact('email', first(customer, 'email')),
- fact('phone', first(customer, 'phone')),
- fact('address', first(customer, 'address', 'address_street')),
- relatedFact('place', relation(owner, customer, 'place'), 'place', first(customer, 'place.address')),
- ],
- open: panelOpener(owner, 'customer-actions'),
- },
- {
- key: 'fleet',
- labelKey: 'resource.fleet',
- icon: 'layer-group',
- modelNames: ['fleet'],
- polymorphicTypes: ['fleet-ops:fleet', 'Fleetbase\\FleetOps\\Models\\Fleet'],
- permission: 'fleet-ops view fleet',
- title: (fleet) => first(fleet, 'name', 'public_id'),
- identifier: (fleet) => first(fleet, 'task', 'public_id'),
- image: (fleet) => photo(fleet, 'fleet'),
- status: (fleet) => first(fleet, 'status'),
- selectDetails: (fleet) => [first(fleet, 'task'), present(get(fleet, 'drivers_count')) ? `${get(fleet, 'drivers_count')} drivers` : null],
- facts: (fleet) => [
- fact('task', first(fleet, 'task')),
- relatedFact('service-area', relation(owner, fleet, 'service_area'), 'service-area', first(fleet, 'service_area.name')),
- relatedFact('zone', relation(owner, fleet, 'zone'), 'zone', first(fleet, 'zone.name')),
- relatedFact('vendor', relation(owner, fleet, 'vendor'), 'vendor', first(fleet, 'vendor.name')),
- fact('drivers', present(get(fleet, 'drivers_count')) ? `${get(fleet, 'drivers_online_count') ?? 0} online of ${get(fleet, 'drivers_count')}` : null),
- fact('vehicles', present(get(fleet, 'vehicles_count')) ? `${get(fleet, 'vehicles_online_count') ?? 0} online of ${get(fleet, 'vehicles_count')}` : null),
- ],
- open: panelOpener(owner, 'fleet-actions'),
- },
];
}
diff --git a/addon/utils/resource-descriptors/shared.js b/addon/utils/resource-descriptors/shared.js
new file mode 100644
index 000000000..52996a19f
--- /dev/null
+++ b/addon/utils/resource-descriptors/shared.js
@@ -0,0 +1,18 @@
+import { buildSharedResourceDescriptors, guardOrder } from '@fleetbase/fleetops-data/utils/resource-descriptors';
+import { panelOpener } from './helpers';
+
+/**
+ * The descriptors `@fleetbase/fleetops-data` shares with every extension,
+ * opened through this engine's own action services instead of through a
+ * lazy engine load: inside FleetOps the services are already here, and the
+ * registry keeps these richer versions over the shared ones.
+ */
+export function sharedDescriptors(owner, keys) {
+ const byKey = Object.fromEntries(buildSharedResourceDescriptors(owner).map((descriptor) => [descriptor.key, descriptor]));
+
+ return keys.map((key) => {
+ const open = panelOpener(owner, `${key}-actions`);
+
+ return { ...byKey[key], canOpen: undefined, open: key === 'order' ? guardOrder(open) : open };
+ });
+}
diff --git a/app/components/cell/contact-identity.js b/app/components/cell/contact-identity.js
deleted file mode 100644
index 1376da5c5..000000000
--- a/app/components/cell/contact-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/contact-identity';
diff --git a/app/components/cell/customer-identity.js b/app/components/cell/customer-identity.js
deleted file mode 100644
index c6c49f586..000000000
--- a/app/components/cell/customer-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/customer-identity';
diff --git a/app/components/cell/driver-identity.js b/app/components/cell/driver-identity.js
deleted file mode 100644
index b5d3ccad4..000000000
--- a/app/components/cell/driver-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/driver-identity';
diff --git a/app/components/cell/fleet-identity.js b/app/components/cell/fleet-identity.js
deleted file mode 100644
index 68a9502ea..000000000
--- a/app/components/cell/fleet-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/fleet-identity';
diff --git a/app/components/cell/order-identity.js b/app/components/cell/order-identity.js
deleted file mode 100644
index 76de50a6a..000000000
--- a/app/components/cell/order-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/order-identity';
diff --git a/app/components/cell/place-identity.js b/app/components/cell/place-identity.js
deleted file mode 100644
index 839bb7cfb..000000000
--- a/app/components/cell/place-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/place-identity';
diff --git a/app/components/cell/vehicle-identity.js b/app/components/cell/vehicle-identity.js
deleted file mode 100644
index 75d5c291b..000000000
--- a/app/components/cell/vehicle-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/vehicle-identity';
diff --git a/app/components/cell/vendor-identity.js b/app/components/cell/vendor-identity.js
deleted file mode 100644
index f950c37d3..000000000
--- a/app/components/cell/vendor-identity.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/cell/vendor-identity';
diff --git a/app/components/contact/pill.js b/app/components/contact/pill.js
deleted file mode 100644
index 0750ead81..000000000
--- a/app/components/contact/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/contact/pill';
diff --git a/app/components/contact/summary.js b/app/components/contact/summary.js
deleted file mode 100644
index cd939f193..000000000
--- a/app/components/contact/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/contact/summary';
diff --git a/app/components/customer/pill.js b/app/components/customer/pill.js
deleted file mode 100644
index 52396929a..000000000
--- a/app/components/customer/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/customer/pill';
diff --git a/app/components/customer/summary.js b/app/components/customer/summary.js
deleted file mode 100644
index 015e5e9a3..000000000
--- a/app/components/customer/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/customer/summary';
diff --git a/app/components/driver/pill.js b/app/components/driver/pill.js
deleted file mode 100644
index b83229abd..000000000
--- a/app/components/driver/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/driver/pill';
diff --git a/app/components/driver/summary.js b/app/components/driver/summary.js
deleted file mode 100644
index e5f6dea18..000000000
--- a/app/components/driver/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/driver/summary';
diff --git a/app/components/fleet/pill.js b/app/components/fleet/pill.js
deleted file mode 100644
index 6035f0a78..000000000
--- a/app/components/fleet/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/fleet/pill';
diff --git a/app/components/fleet/summary.js b/app/components/fleet/summary.js
deleted file mode 100644
index 1e6ad64c2..000000000
--- a/app/components/fleet/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/fleet/summary';
diff --git a/app/components/order/pill.js b/app/components/order/pill.js
deleted file mode 100644
index 25f6c506a..000000000
--- a/app/components/order/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/order/pill';
diff --git a/app/components/order/summary.js b/app/components/order/summary.js
deleted file mode 100644
index f9fb14c7d..000000000
--- a/app/components/order/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/order/summary';
diff --git a/app/components/place/pill.js b/app/components/place/pill.js
deleted file mode 100644
index 81613fc7f..000000000
--- a/app/components/place/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/place/pill';
diff --git a/app/components/place/summary.js b/app/components/place/summary.js
deleted file mode 100644
index f76f00435..000000000
--- a/app/components/place/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/place/summary';
diff --git a/app/components/select-option/contact.js b/app/components/select-option/contact.js
deleted file mode 100644
index eb901f6c2..000000000
--- a/app/components/select-option/contact.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/contact';
diff --git a/app/components/select-option/customer.js b/app/components/select-option/customer.js
deleted file mode 100644
index 6cfc77a27..000000000
--- a/app/components/select-option/customer.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/customer';
diff --git a/app/components/select-option/driver.js b/app/components/select-option/driver.js
deleted file mode 100644
index 85f6b655b..000000000
--- a/app/components/select-option/driver.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/driver';
diff --git a/app/components/select-option/fleet.js b/app/components/select-option/fleet.js
deleted file mode 100644
index e2a5c0d97..000000000
--- a/app/components/select-option/fleet.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/fleet';
diff --git a/app/components/select-option/order.js b/app/components/select-option/order.js
deleted file mode 100644
index 0cdbb5fb1..000000000
--- a/app/components/select-option/order.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/order';
diff --git a/app/components/select-option/place.js b/app/components/select-option/place.js
deleted file mode 100644
index 3616ffca7..000000000
--- a/app/components/select-option/place.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/place';
diff --git a/app/components/select-option/vehicle.js b/app/components/select-option/vehicle.js
deleted file mode 100644
index faa85864d..000000000
--- a/app/components/select-option/vehicle.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/vehicle';
diff --git a/app/components/select-option/vendor.js b/app/components/select-option/vendor.js
deleted file mode 100644
index 7c771c3ff..000000000
--- a/app/components/select-option/vendor.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/select-option/vendor';
diff --git a/app/components/vehicle/pill.js b/app/components/vehicle/pill.js
deleted file mode 100644
index c1dcb8086..000000000
--- a/app/components/vehicle/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/vehicle/pill';
diff --git a/app/components/vehicle/summary.js b/app/components/vehicle/summary.js
deleted file mode 100644
index 261636caa..000000000
--- a/app/components/vehicle/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/vehicle/summary';
diff --git a/app/components/vendor/pill.js b/app/components/vendor/pill.js
deleted file mode 100644
index da3df5298..000000000
--- a/app/components/vendor/pill.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/vendor/pill';
diff --git a/app/components/vendor/summary.js b/app/components/vendor/summary.js
deleted file mode 100644
index 635d4c80e..000000000
--- a/app/components/vendor/summary.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@fleetbase/fleetops-engine/components/vendor/summary';