vue2-excel-grid 2.2.2 → 2.3.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-excel-grid",
3
- "version": "2.2.2",
3
+ "version": "2.3.0",
4
4
  "description": "Excel-style grid component for Vue 2.6.14 with virtual scrolling",
5
5
  "license": "MIT",
6
6
  "author": "Fozilbek Raimberdiyev",
@@ -1460,10 +1460,34 @@ const ExcelGridComponent = {
1460
1460
  localSyncKey: { type: String, default: null },
1461
1461
 
1462
1462
  /**
1463
- * Maximum number of local versions kept per `localSyncKey`. Once a new
1464
- * version pushes the count past this, the oldest version(s) (by
1465
- * `createdAt`) are deleted automatically (FIFO). Has no effect without
1466
- * `localSyncKey`.
1463
+ * Optional tenant/organization identifier for multi-tenant hosts (SaaS
1464
+ * apps where the same browser/device is used across different
1465
+ * organizations). When set, it's combined with `localSyncKey`
1466
+ * internally (`${tenant}::${localSyncKey}`) so each tenant gets a fully
1467
+ * isolated IndexedDB version history — switching tenants on the same
1468
+ * device never shows another tenant's saved drafts. Omit it (default)
1469
+ * for single-tenant hosts; behavior is then identical to before this
1470
+ * prop existed.
1471
+ *
1472
+ * Has no effect without `localSyncKey` — it only changes how that key
1473
+ * is namespaced internally, it doesn't opt into the feature by itself.
1474
+ * Reactive: changing `tenant` (e.g. after an async "current
1475
+ * organization" load) reloads that tenant's own version list/buffer,
1476
+ * the same way a `localSyncKey` that starts empty and becomes truthy
1477
+ * later does. Avoid `::` inside `tenant`/`localSyncKey` values
1478
+ * themselves — it's the internal separator between the two.
1479
+ * @type {String}
1480
+ * @default null
1481
+ * @example
1482
+ * <excel-grid :columns="columns" v-model="data" local-sync-key="invoice-42" :tenant="currentOrgId" toolbar />
1483
+ */
1484
+ tenant: { type: String, default: null },
1485
+
1486
+ /**
1487
+ * Maximum number of local versions kept per `localSyncKey` (per
1488
+ * `tenant`, when set). Once a new version pushes the count past this,
1489
+ * the oldest version(s) (by `createdAt`) are deleted automatically
1490
+ * (FIFO). Has no effect without `localSyncKey`.
1467
1491
  * @type {Number}
1468
1492
  * @default 10
1469
1493
  * @example
@@ -1666,6 +1690,17 @@ const ExcelGridComponent = {
1666
1690
  computed: {
1667
1691
  t() { return getMessages(this.locale) },
1668
1692
 
1693
+ // localSyncKey feature — the actual IndexedDB storage key. idbStore.js
1694
+ // itself knows nothing about "tenants"; this is the one place that
1695
+ // namespaces localSyncKey by tenant when one is given, so every
1696
+ // storage-layer call site below just uses this instead of
1697
+ // this.localSyncKey directly. null whenever localSyncKey itself is
1698
+ // unset — tenant alone doesn't opt into the feature.
1699
+ effectiveSyncKey() {
1700
+ if (!this.localSyncKey) return null
1701
+ return this.tenant ? `${this.tenant}::${this.localSyncKey}` : this.localSyncKey
1702
+ },
1703
+
1669
1704
  pinnedLeftSet() {
1670
1705
  const s = new Set()
1671
1706
  this.leafCols.forEach(col => { if (this.internalPinnedColumns[col.key] === 'left') s.add(col._flatIndex) })
@@ -2419,17 +2454,23 @@ const ExcelGridComponent = {
2419
2454
  },
2420
2455
  widthMode() { this.$nextTick(this.syncHeaderViewportWidth) },
2421
2456
 
2422
- // localSyncKey feature — mounted() only calls _loadLocalVersionsOnMount()
2423
- // once, at mount time. Without this watcher, a key that starts empty (a
2424
- // host conditionally passing `:local-sync-key="ready ? id : null"`, or
2425
- // one only known after an async load) and later becomes truthy would
2426
- // never load its version list, never promote a leftover buffer, and
2427
- // never show the toolbar badge — the feature would look "broken" for the
2428
- // rest of that page's lifetime even though everything else works.
2457
+ // localSyncKey/tenant feature — mounted() only calls
2458
+ // _loadLocalVersionsOnMount() once, at mount time. Without these
2459
+ // watchers, a key/tenant that starts empty (a host conditionally
2460
+ // passing `:local-sync-key="ready ? id : null"`, or a `tenant` only
2461
+ // known after an async "current organization" load) and later becomes
2462
+ // truthy would never load its version list, never promote a leftover
2463
+ // buffer, and never show the toolbar badge — the feature would look
2464
+ // "broken" for the rest of that page's lifetime even though everything
2465
+ // else works. Both share _reloadLocalSyncForKeyChange() since either one
2466
+ // changing means the effective storage key changed.
2429
2467
  localSyncKey(newKey, oldKey) {
2430
2468
  if (newKey === oldKey) return
2431
- this.localSyncAvailable = false
2432
- if (newKey) this._loadLocalVersionsOnMount()
2469
+ this._reloadLocalSyncForKeyChange()
2470
+ },
2471
+ tenant(newTenant, oldTenant) {
2472
+ if (newTenant === oldTenant) return
2473
+ this._reloadLocalSyncForKeyChange()
2433
2474
  }
2434
2475
  },
2435
2476
 
@@ -6423,9 +6464,19 @@ const ExcelGridComponent = {
6423
6464
 
6424
6465
  // =========================================================
6425
6466
  // LOCAL SYNC — save `data` as a local IndexedDB *version*, keyed by
6426
- // localSyncKey, only when the page is being left (not per-edit).
6467
+ // localSyncKey (optionally namespaced by tenant), only when the page is
6468
+ // being left (not per-edit).
6427
6469
  // =========================================================
6428
6470
 
6471
+ // Shared by the localSyncKey and tenant watchers above — either one
6472
+ // changing means effectiveSyncKey now points at a (possibly) different
6473
+ // version history, so the badge/version-list state must be reloaded
6474
+ // from scratch rather than left stale.
6475
+ _reloadLocalSyncForKeyChange() {
6476
+ this.localSyncAvailable = false
6477
+ if (this.effectiveSyncKey) this._loadLocalVersionsOnMount()
6478
+ },
6479
+
6429
6480
  // Internal, called once from mounted(): populates the toolbar "unseen
6430
6481
  // local versions" dot and emits local-sync-available if any versions
6431
6482
  // already exist for this key (e.g. saved in an earlier visit).
@@ -6433,7 +6484,7 @@ const ExcelGridComponent = {
6433
6484
  if (!this.localSyncKey) return
6434
6485
  await this._promoteBufferIfAny()
6435
6486
  try {
6436
- const versions = await listVersions(this.localSyncKey)
6487
+ const versions = await listVersions(this.effectiveSyncKey)
6437
6488
  if (!versions.length) return
6438
6489
  this.localSyncAvailable = true
6439
6490
  this.$emit('local-sync-available', {
@@ -6464,9 +6515,9 @@ const ExcelGridComponent = {
6464
6515
  // turns it into a real version next time the grid mounts.
6465
6516
  _scheduleBufferWrite(data) {
6466
6517
  if (!this.localSyncKey) return
6467
- const key = this.localSyncKey // captured now, not re-read 800ms later —
6468
- // a host that swaps localSyncKey mid-edit (rare, but now reactive, see
6469
- // the localSyncKey watcher above) must not have this land under the
6518
+ const key = this.effectiveSyncKey // captured now, not re-read 800ms later —
6519
+ // a host that swaps localSyncKey/tenant mid-edit (rare, but now
6520
+ // reactive, see the watchers below) must not have this land under the
6470
6521
  // NEW key with the OLD key's data.
6471
6522
  clearTimeout(this._bufferWriteTimer)
6472
6523
  this._bufferWriteTimer = setTimeout(() => { this._writeBufferNow(key, data) }, 800)
@@ -6489,13 +6540,13 @@ const ExcelGridComponent = {
6489
6540
  // like any other non-leave-signal path.
6490
6541
  async _promoteBufferIfAny() {
6491
6542
  try {
6492
- const buffered = await getBuffer(this.localSyncKey)
6543
+ const buffered = await getBuffer(this.effectiveSyncKey)
6493
6544
  if (!buffered) return
6494
6545
  const hash = await hashRowsAsync(buffered.data)
6495
6546
  const { version, overwritten } = await saveOrTouchVersion(
6496
- this.localSyncKey, buffered.data, hash, this.localSyncMaxVersions
6547
+ this.effectiveSyncKey, buffered.data, hash, this.localSyncMaxVersions
6497
6548
  )
6498
- await clearBuffer(this.localSyncKey)
6549
+ await clearBuffer(this.effectiveSyncKey)
6499
6550
  this.$emit('local-sync-save', {
6500
6551
  key: this.localSyncKey,
6501
6552
  id: version.id,
@@ -6565,12 +6616,12 @@ const ExcelGridComponent = {
6565
6616
  // the version-store write below is best-effort on top of it, reliable
6566
6617
  // for the common case (tab switch/background, page stays alive).
6567
6618
  clearTimeout(this._bufferWriteTimer)
6568
- this._writeBufferNow(this.localSyncKey, data)
6619
+ this._writeBufferNow(this.effectiveSyncKey, data)
6569
6620
  try {
6570
6621
  const hash = sync ? hashRows(data) : await hashRowsAsync(data)
6571
6622
  if (this.data !== data) return // data changed again mid-hash — a later flush will catch it
6572
6623
  const { version, overwritten } = await saveOrTouchVersion(
6573
- this.localSyncKey, data, hash, this.localSyncMaxVersions
6624
+ this.effectiveSyncKey, data, hash, this.localSyncMaxVersions
6574
6625
  )
6575
6626
  this._lastFlushedDataRef = data
6576
6627
  // The version store now has this content durably — the buffer's job
@@ -6578,7 +6629,7 @@ const ExcelGridComponent = {
6578
6629
  // doesn't complete before teardown, _promoteBufferIfAny() finds the
6579
6630
  // (now-redundant but harmless, dedup makes it a no-op touch) buffer
6580
6631
  // on next mount anyway.
6581
- clearBuffer(this.localSyncKey).catch(() => {})
6632
+ clearBuffer(this.effectiveSyncKey).catch(() => {})
6582
6633
  this.$emit('local-sync-save', {
6583
6634
  key: this.localSyncKey,
6584
6635
  id: version.id,
@@ -6608,7 +6659,7 @@ const ExcelGridComponent = {
6608
6659
  async listLocalVersions() {
6609
6660
  if (!this.localSyncKey) return []
6610
6661
  try {
6611
- const versions = await listVersions(this.localSyncKey)
6662
+ const versions = await listVersions(this.effectiveSyncKey)
6612
6663
  return versions.map(v => ({ id: v.id, createdAt: v.createdAt, updatedAt: v.updatedAt, rowCount: v.data.length }))
6613
6664
  } catch (error) {
6614
6665
  this.$emit('local-sync-error', { action: 'load', error })