@7365admin1/layer-common 4.71.0 → 4.71.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 4.71.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 99042e0: Building Management → Units import dialog: the instructions no longer ask for a block number (the import takes it from the chosen building).
8
+
9
+ ## 4.71.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 0a25e73: Inventory: show "Copy from old Equipment list" only when the store's sites have old Equipment records not yet copied.
14
+
3
15
  ## 4.71.0
4
16
 
5
17
  ### Minor Changes
@@ -1861,11 +1873,11 @@
1861
1873
  `utils/console-tier.ts` + `composables/useConsoleTier.ts` mirror the server's
1862
1874
  own rule from two endpoints the console already calls, unprojected:
1863
1875
 
1864
- GET /api/members/user/:user/app/admin the Seven365 staff membership
1865
- GET /api/roles/id/:role that membership's role document
1876
+ GET /api/members/user/:user/app/admin the Seven365 staff membership
1877
+ GET /api/roles/id/:role that membership's role document
1866
1878
 
1867
- owner = member.type === "admin" && role.type === "admin" && role.default === true
1868
- staff = member.type === "admin" && role.type === "admin"
1879
+ owner = member.type === "admin" && role.type === "admin" && role.default === true
1880
+ staff = member.type === "admin" && role.type === "admin"
1869
1881
 
1870
1882
  `role.default` is the marker because it is the only property of a platform
1871
1883
  staff role no API caller can set - `role.controller.ts` validates create and
@@ -31,7 +31,7 @@
31
31
  title="Import Blocks, Levels and Units from Excel"
32
32
  noun="rows"
33
33
  name-label="Building / Level / Unit"
34
- fill-hint="One row per unit: block number, building name, level and unit. Building Name and Level have dropdowns with this property's own values."
34
+ fill-hint="One row per unit: building name, level and unit. Pick Building Name and Level from the dropdowns (type a new name for a new building). No block number needed — an existing building keeps its own and a new one gets the next free number."
35
35
  duplicate-note="Units already on that level are skipped and left unchanged."
36
36
  template-file-name="units-import-template.xlsx"
37
37
  :download-template="() => downloadTemplate('building-units', { site })"
@@ -32,7 +32,7 @@
32
32
  <v-list density="compact">
33
33
  <v-list-item prepend-icon="mdi-plus" title="Add one item" @click="editItem(null)" />
34
34
  <v-list-item prepend-icon="mdi-file-excel-outline" title="Import from Excel" @click="showImport = true" />
35
- <v-list-item prepend-icon="mdi-content-copy" title="Copy from old Equipment list" @click="showLegacy = true" />
35
+ <v-list-item v-if="legacyToCopy" prepend-icon="mdi-content-copy" title="Copy from old Equipment list" @click="showLegacy = true" />
36
36
  </v-list>
37
37
  </v-menu>
38
38
  <v-spacer />
@@ -104,6 +104,7 @@ import useFile from "../composables/useFile";
104
104
  import useUtils from "../composables/useUtils";
105
105
  import { inventoryItemMeta } from "../utils/inventory-store-label";
106
106
  import { inventoryControls } from "../utils/inventory-presets";
107
+ import { hasLegacyEquipmentToCopy } from "../utils/inventory-legacy";
107
108
 
108
109
  const props = defineProps({
109
110
  store: { type: Object as PropType<TInventoryStore>, required: true },
@@ -113,7 +114,7 @@ const props = defineProps({
113
114
  const ctl = computed(() => inventoryControls(props.store.access));
114
115
  const emit = defineEmits(["changed"]);
115
116
 
116
- const { getItems } = useInventory();
117
+ const { getItems, getLegacyEquipment } = useInventory();
117
118
  const { getFileUrl } = useFile();
118
119
  const { debounce } = useUtils();
119
120
 
@@ -179,15 +180,26 @@ function openItem(item: TInventoryItem) {
179
180
  const showImport = ref(false);
180
181
  const showReceiveImport = ref(false);
181
182
  const showLegacy = ref(false);
183
+ // Offer the old Equipment copy only where this store's sites have old records not yet copied.
184
+ const legacyToCopy = ref(false);
185
+ async function checkLegacy() {
186
+ if (!props.store.access.canManage) return (legacyToCopy.value = false);
187
+ try {
188
+ legacyToCopy.value = hasLegacyEquipmentToCopy(await getLegacyEquipment(props.store._id));
189
+ } catch {
190
+ legacyToCopy.value = false;
191
+ }
192
+ }
182
193
 
183
194
  function done() {
184
195
  load();
196
+ checkLegacy();
185
197
  emit("changed");
186
198
  }
187
199
 
188
200
  watch(page, load);
189
201
  watch(lowOnly, () => (page.value === 1 ? load() : (page.value = 1)));
190
202
  watch(search, debounce(() => (page.value === 1 ? load() : (page.value = 1)), 400));
191
- watch(() => props.store._id, () => (page.value === 1 ? load() : (page.value = 1)));
192
- onMounted(load);
203
+ watch(() => props.store._id, () => (checkLegacy(), page.value === 1 ? load() : (page.value = 1)));
204
+ onMounted(() => (load(), checkLegacy()));
193
205
  </script>
@@ -65,7 +65,7 @@ export default function useInventory() {
65
65
  api<Blob>(`/stores/${store}/reports/${report}/export`, { query, responseType: "blob" }),
66
66
  checkUsage: (store: string, ids: string[], checked: boolean) =>
67
67
  api<{ updated: number }>(`/stores/${store}/usage/check`, { method: "POST", body: { ids, checked } }),
68
- getLegacyEquipment: (store: string) => api<{ serviceType: string; count: number }[]>(`/stores/${store}/legacy-equipment`),
68
+ getLegacyEquipment: (store: string) => api<{ serviceType: string; count: number; pending?: number }[]>(`/stores/${store}/legacy-equipment`),
69
69
  importLegacyEquipment: (store: string, serviceType: string, commit: boolean) =>
70
70
  api<{ committed: boolean; ready: number; skipped: number; errors: number; rows: { row: number; name: string; status: string; message: string }[] }>(
71
71
  `/stores/${store}/legacy-equipment/import`,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "4.71.0",
5
+ "version": "4.71.2",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
@@ -0,0 +1,10 @@
1
+ type TLegacyGroup = { count: number; pending?: number };
2
+
3
+ /**
4
+ * Whether "Copy from old Equipment list" has anything to bring in: false for a
5
+ * site that never had an old Equipment list, and false once every old name is
6
+ * already in the store. An API without `pending` falls back to `count`.
7
+ */
8
+ export function hasLegacyEquipmentToCopy(groups: TLegacyGroup[] | null | undefined) {
9
+ return (groups ?? []).some((g) => (g.pending ?? g.count) > 0);
10
+ }