@brightspot/ui 6.4.3-pr.366.2026.10.5 → 6.5.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.
Files changed (19) hide show
  1. package/dist/storybook/project.json +1 -1
  2. package/dist/util/rtc.js +1 -1
  3. package/dist/util/rtc.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/legacy/tool-ui/src/ContentEditDrawer.ts +28 -18
  6. package/src/legacy/tool-ui/src/Global.d.ts +1 -0
  7. package/src/legacy/tool-ui/src/LinkTable.css +3 -1
  8. package/src/legacy/tool-ui/src/SearchFields.css +10 -0
  9. package/src/legacy/tool-ui/src/form/SearchInput/index.ts +4 -0
  10. package/src/legacy/tool-ui/src/main/webapp/dist/{RTEProseMirror.e4cbe3b9e2e8f938cf1a.js → RTEProseMirror.beb34ef615bdd5b46ab0.js} +5 -5
  11. package/src/legacy/tool-ui/src/main/webapp/dist/{v4.56e25b6f00e10789ff37.js → v4.fee133dfaae516995f6c.js} +6 -5
  12. package/src/legacy/tool-ui/src/main/webapp/dist/{v5.22ce1a2b135f2c813878.css → v5.450b0b8178c9222bafab.css} +1 -1
  13. package/src/legacy/tool-ui/src/main/webapp/dist/{v5.85bedd855e1e6f2c2caa.js → v5.c52683421261f109dd30.js} +6 -5
  14. package/src/legacy/tool-ui/src/rtc/Socket.ts +24 -7
  15. package/src/legacy/tool-ui/src/rtc/index.ts +16 -3
  16. package/src/legacy/tool-ui/src/v5.ts +5 -2
  17. /package/src/legacy/tool-ui/src/main/webapp/dist/{RTEProseMirror.e4cbe3b9e2e8f938cf1a.js.LICENSE.txt → RTEProseMirror.beb34ef615bdd5b46ab0.js.LICENSE.txt} +0 -0
  18. /package/src/legacy/tool-ui/src/main/webapp/dist/{v4.56e25b6f00e10789ff37.js.LICENSE.txt → v4.fee133dfaae516995f6c.js.LICENSE.txt} +0 -0
  19. /package/src/legacy/tool-ui/src/main/webapp/dist/{v5.85bedd855e1e6f2c2caa.js.LICENSE.txt → v5.c52683421261f109dd30.js.LICENSE.txt} +0 -0
@@ -7,10 +7,14 @@ export default class Socket {
7
7
  private _requests: {
8
8
  message: { type: string; [key: string]: unknown }
9
9
  callback?: (data?: unknown) => void
10
- wait?: boolean
11
10
  }[]
12
11
  private _sending = false
13
12
  private _sessionId?: string
13
+
14
+ // Kept when _sessionId is cleared, for sendFinal. Navigating away aborts the event stream, and the error
15
+ // that follows resets the connection, so by the time the page reports that it is going the live session is
16
+ // already gone and the tab would have no way left to say it had left.
17
+ private _closingSessionId?: string
14
18
  private _onConnect: () => void = () => {}
15
19
  private _onReceive: (data: JSONObject) => void | (() => void) = () => {}
16
20
  private _ensureConnectionInterval?: number
@@ -29,10 +33,9 @@ export default class Socket {
29
33
  send(
30
34
  message: { type: string; [key: string]: unknown },
31
35
  callback?: (data?: unknown) => void,
32
- wait?: boolean,
33
36
  ) {
34
37
  if (message) {
35
- this._requests.push({ message, callback, wait })
38
+ this._requests.push({ message, callback })
36
39
 
37
40
  if (!this._sending) {
38
41
  this._sending = true
@@ -60,7 +63,7 @@ export default class Socket {
60
63
  return
61
64
  }
62
65
 
63
- const { message, callback, wait } = request
66
+ const { message, callback } = request
64
67
 
65
68
  // Query string only used for logging.
66
69
  const body = new URLSearchParams()
@@ -94,11 +97,24 @@ export default class Socket {
94
97
  .finally(() => {
95
98
  this._processRequests()
96
99
  })
100
+ }
97
101
 
98
- if (wait) {
99
- const start = +Date.now()
100
- while (Date.now() - start < 500) {}
102
+ // Sends a message while the page is going away. A normal request is cancelled as the page unloads, so the
103
+ // server never hears that this tab left and keeps whatever it had locked. A beacon is handed to the browser
104
+ // to deliver on its own, after the page is gone.
105
+ sendFinal(message: { type: string; [key: string]: unknown }) {
106
+ const sessionId = this._sessionId || this._closingSessionId
107
+
108
+ if (!message || !sessionId || !navigator.sendBeacon) {
109
+ return false
101
110
  }
111
+
112
+ const body = new URLSearchParams()
113
+
114
+ body.append('sessionId', sessionId)
115
+ body.append('message', JSON.stringify(message))
116
+
117
+ return navigator.sendBeacon(this._url, body)
102
118
  }
103
119
 
104
120
  // Connects to the server for receiving messages.
@@ -139,6 +155,7 @@ export default class Socket {
139
155
  if (data._first) {
140
156
  if (typeof data.sessionId === 'string') {
141
157
  this._sessionId = data.sessionId
158
+ this._closingSessionId = data.sessionId
142
159
  }
143
160
 
144
161
  if (this._receiver) {
@@ -37,7 +37,7 @@ if (window.DISABLE_RTC || !document.documentElement.dataset.userId) {
37
37
  const BROADCAST = 'broadcast'
38
38
  const CALLBACK = 'callback'
39
39
  const CONNECT = 'connect'
40
- const DISCONNECT = 'connect'
40
+ const DISCONNECT = 'disconnect'
41
41
  const EXECUTE = 'execute'
42
42
  const RESTORE = 'restore'
43
43
 
@@ -220,7 +220,20 @@ if (window.DISABLE_RTC || !document.documentElement.dataset.userId) {
220
220
  ) {
221
221
  rtc.restore(state, data, callback)
222
222
 
223
- window.addEventListener('unload', () => {
223
+ // pagehide, not unload: a request started from unload is cancelled as the page goes away, so the tab
224
+ // was rarely able to say it had left and kept hold of its locks.
225
+ let sent = false
226
+
227
+ window.addEventListener('pagehide', (event) => {
228
+ // A page entering the back/forward cache is not leaving, and may well come back. Disconnecting here
229
+ // would drop the locks of someone who then navigates straight back, and would use up the one
230
+ // disconnect this tab gets to send when it really does go.
231
+ if (event.persisted || sent) {
232
+ return
233
+ }
234
+
235
+ sent = true
236
+
224
237
  const message = {
225
238
  type: 'disconnect',
226
239
  className: state,
@@ -228,7 +241,7 @@ if (window.DISABLE_RTC || !document.documentElement.dataset.userId) {
228
241
  }
229
242
 
230
243
  if (socket) {
231
- socket.send(message, callback, true)
244
+ socket.sendFinal(message)
232
245
  } else {
233
246
  // Send the action to the leader at [LS].
234
247
  channel.postMessage({ type: DISCONNECT, message })
@@ -1192,10 +1192,13 @@ const renderCETitle = (title: HTMLElement) => {
1192
1192
  }
1193
1193
  }
1194
1194
 
1195
- // If status name is empty, default to either "New" or "Published"
1195
+ // If status name is empty, default to either "New", "Published" or "Saved"
1196
1196
  if (!newStatus.innerText || newStatus.innerText == '') {
1197
1197
  if (editPage.classList.contains('is-notNew')) {
1198
- newStatus.innerText = window.BRIGHTSPOT?.ui.workflow.published
1198
+ // Save-only types (no `is-publish`) are never published.
1199
+ newStatus.innerText = editPage.classList.contains('is-publish')
1200
+ ? window.BRIGHTSPOT?.ui.workflow.published
1201
+ : window.BRIGHTSPOT?.ui.workflow.saved ?? 'Saved'
1199
1202
  }
1200
1203
  if (editPage.classList.contains('is-new')) {
1201
1204
  newStatus.innerText = window.BRIGHTSPOT?.ui.tooltips.new