@omniloy/sofia-sdk 1.0.11 → 1.0.12

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.
@@ -5145,7 +5145,7 @@ const {
5145
5145
  create: create$1,
5146
5146
  } = axios;
5147
5147
 
5148
- const version$2 = "1.0.11";
5148
+ const version$2 = "1.0.12";
5149
5149
 
5150
5150
  const handleApiError$1 = async (error) => {
5151
5151
  return Promise.reject(error);
@@ -5903,6 +5903,11 @@ const ar = {
5903
5903
  "Generation failed": "فشل الإنشاء",
5904
5904
  "Could not generate {category}. Please try again.": "تعذّر إنشاء {category}. يرجى المحاولة مرة أخرى.",
5905
5905
  "The new note is waiting for this review — apply or cancel to continue.": "الملاحظة الجديدة في انتظار هذه المراجعة — طبّق أو ألغِ للمتابعة.",
5906
+ " +{count} more": " +{count} أخرى",
5907
+ "{count} mandatory fields missing in this group": "{count, plural, zero {# حقل إلزامي ناقص} one {# حقل إلزامي ناقص} two {حقلان إلزاميان ناقصان} few {# حقول إلزامية ناقصة} many {# حقلاً إلزامياً ناقصاً} other {# حقل إلزامي ناقص}} في هذه المجموعة",
5908
+ "{group} · row {row}": "{group} · الصف {row}",
5909
+ "{group} · row {row} · {field}": "{group} · الصف {row} · {field}",
5910
+ "{count} rows need a type selected in this group": "{count, plural, zero {# صف يحتاج} one {# صف يحتاج} two {صفّان يحتاجان} few {# صفوف تحتاج} many {# صفاً يحتاج} other {# صف يحتاج}} إلى تحديد النوع في هذه المجموعة",
5906
5911
  };
5907
5912
 
5908
5913
  const Add$b = "Afegir";
@@ -6273,6 +6278,11 @@ const ca = {
6273
6278
  "Generation failed": "La generació ha fallat",
6274
6279
  "Could not generate {category}. Please try again.": "No s'ha pogut generar {category}. Torna-ho a provar.",
6275
6280
  "The new note is waiting for this review — apply or cancel to continue.": "La nova nota està esperant aquesta revisió: aplica o cancel·la per continuar.",
6281
+ " +{count} more": " +{count} més",
6282
+ "{count} mandatory fields missing in this group": "{count, plural, one {Falta # camp obligatori} other {Falten # camps obligatoris}} en aquest grup",
6283
+ "{group} · row {row}": "{group} · fila {row}",
6284
+ "{group} · row {row} · {field}": "{group} · fila {row} · {field}",
6285
+ "{count} rows need a type selected in this group": "{count, plural, one {# fila necessita} other {# files necessiten}} que se seleccioni un tipus en aquest grup",
6276
6286
  };
6277
6287
 
6278
6288
  const Add$a = "Afegir";
@@ -6643,6 +6653,11 @@ const ca_valencia = {
6643
6653
  "Generation failed": "La generació ha fallat",
6644
6654
  "Could not generate {category}. Please try again.": "No s'ha pogut generar {category}. Torna-ho a provar.",
6645
6655
  "The new note is waiting for this review — apply or cancel to continue.": "La nova nota està esperant aquesta revisió: aplica o cancel·la per continuar.",
6656
+ " +{count} more": " +{count} més",
6657
+ "{count} mandatory fields missing in this group": "{count, plural, one {Falta # camp obligatori} other {Falten # camps obligatoris}} en este grup",
6658
+ "{group} · row {row}": "{group} · fila {row}",
6659
+ "{group} · row {row} · {field}": "{group} · fila {row} · {field}",
6660
+ "{count} rows need a type selected in this group": "{count, plural, one {# fila necessita} other {# files necessiten}} que se seleccione un tipus en este grup",
6646
6661
  };
6647
6662
 
6648
6663
  const Add$9 = "Přidat";
@@ -7013,6 +7028,11 @@ const cs = {
7013
7028
  "Generation failed": "Generování se nezdařilo",
7014
7029
  "Could not generate {category}. Please try again.": "Nepodařilo se vygenerovat {category}. Zkuste to znovu.",
7015
7030
  "The new note is waiting for this review — apply or cancel to continue.": "Nová poznámka čeká na tuto kontrolu — potvrďte ji, nebo ji zrušte, aby mohla pokračovat.",
7031
+ " +{count} more": " +{count} dalších",
7032
+ "{count} mandatory fields missing in this group": "{count, plural, one {Chybí # povinné pole} few {Chybí # povinná pole} other {Chybí # povinných polí}} v této skupině",
7033
+ "{group} · row {row}": "{group} · řádek {row}",
7034
+ "{group} · row {row} · {field}": "{group} · řádek {row} · {field}",
7035
+ "{count} rows need a type selected in this group": "{count, plural, one {U # řádku} few {U # řádků} other {U # řádků}} v této skupině je třeba vybrat typ",
7016
7036
  };
7017
7037
 
7018
7038
  const Add$8 = "Add";
@@ -7383,6 +7403,11 @@ const en_GB = {
7383
7403
  "Generation failed": "Generation failed",
7384
7404
  "Could not generate {category}. Please try again.": "Could not generate {category}. Please try again.",
7385
7405
  "The new note is waiting for this review — apply or cancel to continue.": "The new note is waiting for this review — apply or cancel to continue.",
7406
+ " +{count} more": " +{count} more",
7407
+ "{count} mandatory fields missing in this group": "{count, plural, one {# mandatory field missing} other {# mandatory fields missing}} in this group",
7408
+ "{group} · row {row}": "{group} · row {row}",
7409
+ "{group} · row {row} · {field}": "{group} · row {row} · {field}",
7410
+ "{count} rows need a type selected in this group": "{count, plural, one {# row needs} other {# rows need}} a type selected in this group",
7386
7411
  };
7387
7412
 
7388
7413
  const Add$7 = "Add";
@@ -7754,6 +7779,11 @@ const en_US = {
7754
7779
  "Generation failed": "Generation failed",
7755
7780
  "Could not generate {category}. Please try again.": "Could not generate {category}. Please try again.",
7756
7781
  "The new note is waiting for this review — apply or cancel to continue.": "The new note is waiting for this review — apply or cancel to continue.",
7782
+ " +{count} more": " +{count} more",
7783
+ "{count} mandatory fields missing in this group": "{count, plural, one {# mandatory field missing} other {# mandatory fields missing}} in this group",
7784
+ "{group} · row {row}": "{group} · row {row}",
7785
+ "{group} · row {row} · {field}": "{group} · row {row} · {field}",
7786
+ "{count} rows need a type selected in this group": "{count, plural, one {# row needs} other {# rows need}} a type selected in this group",
7757
7787
  };
7758
7788
 
7759
7789
  const Add$6 = "Añadir";
@@ -8137,6 +8167,11 @@ const es = {
8137
8167
  "{name} has expressly refused the use of AI, so recording and report generation are unavailable in this consultation.": "{name} ha rechazado expresamente el uso de IA, así que no se puede grabar ni generar informes en esta consulta.",
8138
8168
  "{name} expressly refused the use of AI on {date}, so recording and report generation are unavailable in this consultation.": "{name} rechazó expresamente el uso de IA el {date}, así que no se puede grabar ni generar informes en esta consulta.",
8139
8169
  "this patient": "este paciente",
8170
+ " +{count} more": " +{count} más",
8171
+ "{count} mandatory fields missing in this group": "{count, plural, one {Falta # campo obligatorio} other {Faltan # campos obligatorios}} en este grupo",
8172
+ "{group} · row {row}": "{group} · fila {row}",
8173
+ "{group} · row {row} · {field}": "{group} · fila {row} · {field}",
8174
+ "{count} rows need a type selected in this group": "{count, plural, one {# fila necesita} other {# filas necesitan}} que se seleccione un tipo en este grupo",
8140
8175
  };
8141
8176
 
8142
8177
  const Add$5 = "Ajouter";
@@ -8507,6 +8542,11 @@ const fr = {
8507
8542
  "Generation failed": "Échec de la génération",
8508
8543
  "Could not generate {category}. Please try again.": "Impossible de générer {category}. Veuillez réessayer.",
8509
8544
  "The new note is waiting for this review — apply or cancel to continue.": "La nouvelle note attend cette révision : appliquez ou annulez pour continuer.",
8545
+ " +{count} more": " +{count} de plus",
8546
+ "{count} mandatory fields missing in this group": "{count, plural, one {# champ obligatoire manquant} other {# champs obligatoires manquants}} dans ce groupe",
8547
+ "{group} · row {row}": "{group} · ligne {row}",
8548
+ "{group} · row {row} · {field}": "{group} · ligne {row} · {field}",
8549
+ "{count} rows need a type selected in this group": "{count, plural, one {# ligne nécessite} other {# lignes nécessitent}} la sélection d'un type dans ce groupe",
8510
8550
  };
8511
8551
 
8512
8552
  const Add$4 = "जोड़ें";
@@ -8856,6 +8896,11 @@ const hi = {
8856
8896
  "Generation failed": "जनरेशन विफल रहा",
8857
8897
  "Could not generate {category}. Please try again.": "{category} जनरेट नहीं किया जा सका। कृपया पुनः प्रयास करें।",
8858
8898
  "The new note is waiting for this review — apply or cancel to continue.": "नई नोट इस समीक्षा की प्रतीक्षा कर रही है — जारी रखने के लिए लागू करें या रद्द करें।",
8899
+ " +{count} more": " +{count} और",
8900
+ "{count} mandatory fields missing in this group": "इस समूह में {count, plural, one {# अनिवार्य फ़ील्ड खाली है} other {# अनिवार्य फ़ील्ड खाली हैं}}",
8901
+ "{group} · row {row}": "{group} · पंक्ति {row}",
8902
+ "{group} · row {row} · {field}": "{group} · पंक्ति {row} · {field}",
8903
+ "{count} rows need a type selected in this group": "इस समूह में {count, plural, one {# पंक्ति के लिए} other {# पंक्तियों के लिए}} प्रकार चुनना आवश्यक है",
8859
8904
  };
8860
8905
 
8861
8906
  const Add$3 = "Tambahkan";
@@ -9204,6 +9249,11 @@ const id = {
9204
9249
  "Generation failed": "Pembuatan gagal",
9205
9250
  "Could not generate {category}. Please try again.": "Tidak dapat membuat {category}. Silakan coba lagi.",
9206
9251
  "The new note is waiting for this review — apply or cancel to continue.": "Catatan baru menunggu tinjauan ini — terapkan atau batalkan untuk melanjutkan.",
9252
+ " +{count} more": " +{count} lainnya",
9253
+ "{count} mandatory fields missing in this group": "{count, plural, other {# bidang wajib belum diisi}} di grup ini",
9254
+ "{group} · row {row}": "{group} · baris {row}",
9255
+ "{group} · row {row} · {field}": "{group} · baris {row} · {field}",
9256
+ "{count} rows need a type selected in this group": "{count, plural, other {# baris perlu dipilih jenisnya}} di grup ini",
9207
9257
  };
9208
9258
 
9209
9259
  const Add$2 = "ਸ਼ਾਮਲ ਕਰੋ";
@@ -9574,6 +9624,11 @@ const pa = {
9574
9624
  "Generation failed": "ਜਨਰੇਸ਼ਨ ਅਸਫਲ ਰਹੀ",
9575
9625
  "Could not generate {category}. Please try again.": "{category} ਜਨਰੇਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
9576
9626
  "The new note is waiting for this review — apply or cancel to continue.": "ਨਵਾਂ ਨੋਟ ਇਸ ਸਮੀਖਿਆ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ — ਜਾਰੀ ਰੱਖਣ ਲਈ ਲਾਗੂ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।",
9627
+ " +{count} more": " +{count} ਹੋਰ",
9628
+ "{count} mandatory fields missing in this group": "ਇਸ ਸਮੂਹ ਵਿੱਚ {count, plural, one {# ਲਾਜ਼ਮੀ ਖੇਤਰ ਖਾਲੀ ਹੈ} other {# ਲਾਜ਼ਮੀ ਖੇਤਰ ਖਾਲੀ ਹਨ}}",
9629
+ "{group} · row {row}": "{group} · ਕਤਾਰ {row}",
9630
+ "{group} · row {row} · {field}": "{group} · ਕਤਾਰ {row} · {field}",
9631
+ "{count} rows need a type selected in this group": "ਇਸ ਸਮੂਹ ਵਿੱਚ {count, plural, one {# ਕਤਾਰ ਲਈ} other {# ਕਤਾਰਾਂ ਲਈ}} ਕਿਸਮ ਚੁਣਨੀ ਲਾਜ਼ਮੀ ਹੈ",
9577
9632
  };
9578
9633
 
9579
9634
  const Add$1 = "Lägg till";
@@ -9944,6 +9999,11 @@ const sv = {
9944
9999
  "Generation failed": "Genereringen misslyckades",
9945
10000
  "Could not generate {category}. Please try again.": "Det gick inte att generera {category}. Försök igen.",
9946
10001
  "The new note is waiting for this review — apply or cancel to continue.": "Den nya anteckningen väntar på den här granskningen — tillämpa eller avbryt för att fortsätta.",
10002
+ " +{count} more": " +{count} till",
10003
+ "{count} mandatory fields missing in this group": "{count, plural, one {# obligatoriskt fält saknas} other {# obligatoriska fält saknas}} i den här gruppen",
10004
+ "{group} · row {row}": "{group} · rad {row}",
10005
+ "{group} · row {row} · {field}": "{group} · rad {row} · {field}",
10006
+ "{count} rows need a type selected in this group": "{count, plural, one {# rad behöver} other {# rader behöver}} en vald typ i den här gruppen",
9947
10007
  };
9948
10008
 
9949
10009
  const Add = "شامل کریں";
@@ -10315,6 +10375,11 @@ const ur = {
10315
10375
  "Generation failed": "تخلیق ناکام ہو گئی",
10316
10376
  "Could not generate {category}. Please try again.": "{category} تیار نہیں کیا جا سکا۔ براہ کرم دوبارہ کوشش کریں۔",
10317
10377
  "The new note is waiting for this review — apply or cancel to continue.": "نیا نوٹ اس جائزے کا منتظر ہے — جاری رکھنے کے لیے لاگو کریں یا منسوخ کریں۔",
10378
+ " +{count} more": " +{count} مزید",
10379
+ "{count} mandatory fields missing in this group": "اس گروپ میں {count, plural, one {# لازمی خانہ خالی ہے} other {# لازمی خانے خالی ہیں}}",
10380
+ "{group} · row {row}": "{group} · قطار {row}",
10381
+ "{group} · row {row} · {field}": "{group} · قطار {row} · {field}",
10382
+ "{count} rows need a type selected in this group": "اس گروپ میں {count, plural, one {# قطار کے لیے} other {# قطاروں کے لیے}} قسم منتخب کرنا ضروری ہے",
10318
10383
  };
10319
10384
 
10320
10385
  var LanguageCode = /* @__PURE__ */ ((LanguageCode2) => {
@@ -11078,19 +11143,177 @@ const useVadCoverage = () => {
11078
11143
  };
11079
11144
  };
11080
11145
 
11081
- const FAMILIES = [
11146
+ const KNOWN_SDK_EVENT_NAMES = [
11147
+ "recording.started",
11148
+ "recording.stopped",
11149
+ "recording.audio_lost",
11150
+ "recording.microphone_disconnected",
11151
+ "recording.heartbeat",
11152
+ "activity.interaction",
11153
+ "activity.typing",
11154
+ "report.generation_started",
11155
+ "report.settled",
11156
+ "lifecycle.ready",
11157
+ "lifecycle.closed"
11158
+ ];
11159
+ const SDK_EVENT_FAMILIES = [
11082
11160
  "recording",
11083
11161
  "activity",
11084
11162
  "report",
11085
11163
  "lifecycle"
11086
11164
  ];
11165
+ const FAMILIES = SDK_EVENT_FAMILIES;
11087
11166
  const familyOf = (name) => {
11088
11167
  const prefix = name.split(".")[0];
11089
11168
  return FAMILIES.includes(prefix) ? prefix : "lifecycle";
11090
11169
  };
11091
11170
 
11092
- const compileSubscription = (patterns) => {
11093
- if (!patterns || patterns.length === 0) return () => false;
11171
+ const KNOWN_NAMES = new Set(KNOWN_SDK_EVENT_NAMES);
11172
+ const KNOWN_FAMILIES = new Set(SDK_EVENT_FAMILIES);
11173
+ const distance = (a, b) => {
11174
+ const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
11175
+ for (let i = 1; i <= a.length; i++) {
11176
+ let corner = prev[0];
11177
+ prev[0] = i;
11178
+ for (let j = 1; j <= b.length; j++) {
11179
+ const next = Math.min(
11180
+ prev[j] + 1,
11181
+ prev[j - 1] + 1,
11182
+ corner + (a[i - 1] === b[j - 1] ? 0 : 1)
11183
+ );
11184
+ corner = prev[j];
11185
+ prev[j] = next;
11186
+ }
11187
+ }
11188
+ return prev[b.length];
11189
+ };
11190
+ const describeEntry = (entry) => {
11191
+ try {
11192
+ return JSON.stringify(entry) ?? `<${typeof entry}>`;
11193
+ } catch {
11194
+ return `<unserializable ${typeof entry}>`;
11195
+ }
11196
+ };
11197
+ const suggest = (value, candidates) => {
11198
+ let best = null;
11199
+ let bestScore = Infinity;
11200
+ for (const candidate of candidates) {
11201
+ const score = distance(value, candidate);
11202
+ if (score < bestScore) {
11203
+ bestScore = score;
11204
+ best = candidate;
11205
+ }
11206
+ }
11207
+ return best !== null && bestScore <= Math.max(3, best.length / 3) ? ` Did you mean "${best}"?` : "";
11208
+ };
11209
+ const REJECTED_KEY_CHARS = 40;
11210
+ const scanSubscriptions = (input) => {
11211
+ if (input === void 0 || input === null) {
11212
+ return { patterns: [], rejected: [], unusable: false, key: "" };
11213
+ }
11214
+ const raw = typeof input === "string" ? [input] : input;
11215
+ if (!Array.isArray(raw)) {
11216
+ return {
11217
+ patterns: [],
11218
+ rejected: [],
11219
+ unusable: true,
11220
+ key: `!${typeof input}`
11221
+ };
11222
+ }
11223
+ const patterns = [];
11224
+ const rejected = [];
11225
+ for (const entry of raw) {
11226
+ if (typeof entry !== "string") {
11227
+ rejected.push(entry);
11228
+ continue;
11229
+ }
11230
+ const pattern = entry.trim();
11231
+ if (pattern === "" || patterns.includes(pattern)) continue;
11232
+ patterns.push(pattern);
11233
+ }
11234
+ const key = JSON.stringify(patterns) + (rejected.length > 0 ? `!${rejected.map((entry) => describeEntry(entry).slice(0, REJECTED_KEY_CHARS)).join(",")}` : "");
11235
+ return { patterns, rejected, unusable: false, key };
11236
+ };
11237
+ const normalizeSubscriptions = (input) => {
11238
+ const { patterns, rejected, unusable, key } = scanSubscriptions(input);
11239
+ const problems = [];
11240
+ const warnings = [];
11241
+ if (unusable) {
11242
+ problems.push(
11243
+ `eventSubscriptions must be an array of strings, received ${typeof input}. No events will be delivered.`
11244
+ );
11245
+ return { patterns, key, problems, warnings };
11246
+ }
11247
+ for (const entry of rejected) {
11248
+ problems.push(
11249
+ `eventSubscriptions entry ${describeEntry(entry)} is not a string and was ignored.`
11250
+ );
11251
+ }
11252
+ for (const pattern of patterns) {
11253
+ if (pattern === "*" || KNOWN_NAMES.has(pattern)) continue;
11254
+ if (pattern.endsWith(".*")) {
11255
+ const family = pattern.slice(0, -2);
11256
+ if (!KNOWN_FAMILIES.has(family)) {
11257
+ const hint2 = suggest(family, KNOWN_FAMILIES);
11258
+ (hint2 ? problems : warnings).push(
11259
+ `"${pattern}" is not a known event family.${hint2}`
11260
+ );
11261
+ }
11262
+ continue;
11263
+ }
11264
+ const hint = suggest(pattern, KNOWN_NAMES);
11265
+ (hint ? problems : warnings).push(
11266
+ `"${pattern}" is not an event this SDK version emits.${hint}`
11267
+ );
11268
+ }
11269
+ const present = input !== void 0 && input !== null;
11270
+ if (present && patterns.length === 0 && problems.length === 0) {
11271
+ problems.push(
11272
+ 'eventSubscriptions is empty, so onEvent will never fire. Pass e.g. ["recording.*", "activity.*"] or ["*"].'
11273
+ );
11274
+ }
11275
+ return { patterns, key, problems, warnings };
11276
+ };
11277
+ const reported = /* @__PURE__ */ new Set();
11278
+ const VALID_VALUES = `Valid values are "*", a family wildcard (${SDK_EVENT_FAMILIES.map((f) => `"${f}.*"`).join(", ")}), or an exact name (${KNOWN_SDK_EVENT_NAMES.join(", ")}).`;
11279
+ const reportOnce = (level, signature, message) => {
11280
+ if (reported.has(signature)) return;
11281
+ reported.add(signature);
11282
+ if (level === "error") logger.configError(message);
11283
+ else logger.warn(message);
11284
+ };
11285
+ const reportSubscriptionProblems = ({
11286
+ key,
11287
+ problems,
11288
+ warnings
11289
+ }) => {
11290
+ if (problems.length > 0) {
11291
+ reportOnce(
11292
+ "error",
11293
+ `error:${key}:${problems.join("|")}`,
11294
+ `[Sofia SDK] eventSubscriptions: ${problems.join(" ")} ${VALID_VALUES}`
11295
+ );
11296
+ }
11297
+ if (warnings.length > 0) {
11298
+ reportOnce(
11299
+ "warn",
11300
+ `warn:${key}:${warnings.join("|")}`,
11301
+ `[Sofia SDK] eventSubscriptions: ${warnings.join(" ")} ${VALID_VALUES}`
11302
+ );
11303
+ }
11304
+ };
11305
+ const reportHandlerWithoutSubscriptions = () => {
11306
+ reportOnce(
11307
+ "error",
11308
+ "onEvent:no-subscriptions",
11309
+ "[Sofia SDK] onEvent: onEvent was provided without eventSubscriptions, so no events will be delivered. " + VALID_VALUES
11310
+ );
11311
+ };
11312
+ const compileSubscription = (input) => {
11313
+ const normalized = normalizeSubscriptions(input);
11314
+ reportSubscriptionProblems(normalized);
11315
+ const { patterns } = normalized;
11316
+ if (patterns.length === 0) return () => false;
11094
11317
  if (patterns.includes("*")) return () => true;
11095
11318
  const exact = /* @__PURE__ */ new Set();
11096
11319
  const families = /* @__PURE__ */ new Set();
@@ -11105,7 +11328,7 @@ const compileSubscription = (patterns) => {
11105
11328
  return dot > 0 && families.has(name.slice(0, dot));
11106
11329
  };
11107
11330
  };
11108
- const subscriptionKey = (patterns) => patterns ? patterns.join("|") : "";
11331
+ const subscriptionKey = (input) => scanSubscriptions(input).key;
11109
11332
 
11110
11333
  const QUEUE_CAP = 200;
11111
11334
  let handler = null;
@@ -22871,18 +23094,22 @@ const useReportPreviewState = ({
22871
23094
  }),
22872
23095
  [entries, selectedKeys, selectedRows, filledScalarGaps]
22873
23096
  );
22874
- const blockingMandatoryCount = React__default.useMemo(() => {
22875
- let count = 0;
23097
+ const blockingGaps = React__default.useMemo(() => {
23098
+ const out = [];
22876
23099
  for (const g of scalarGaps) {
22877
23100
  if (!g.mandatory) continue;
22878
23101
  const filled = filledScalarGaps.get(g.key);
22879
- if (isEmptyValue(filled)) count++;
23102
+ if (isEmptyValue(filled)) {
23103
+ out.push({ scope: "field", key: g.key, label: g.descriptor.label });
23104
+ }
22880
23105
  }
22881
23106
  for (const e of entries) {
22882
23107
  if (!selectedKeys.has(e.key)) continue;
22883
23108
  if (e.descriptor.kind !== "array-of-objects" && e.descriptor.mandatory) {
22884
23109
  const v = edits.has(e.key) ? edits.get(e.key) : e.value;
22885
- if (isEmptyValue(v)) count++;
23110
+ if (isEmptyValue(v)) {
23111
+ out.push({ scope: "field", key: e.key, label: e.descriptor.label });
23112
+ }
22886
23113
  }
22887
23114
  if (e.descriptor.kind !== "array-of-objects") continue;
22888
23115
  const rows = e.value ?? [];
@@ -22890,16 +23117,32 @@ const useReportPreviewState = ({
22890
23117
  if (!selectedRows.has(`${e.key}#${idx}`)) return;
22891
23118
  const row = mergeRowEdits(e.key, idx, rawRow, edits);
22892
23119
  if (e.descriptor.discriminator && !pickBranch(e.descriptor, row)) {
22893
- count++;
23120
+ out.push({
23121
+ scope: "row",
23122
+ key: e.key,
23123
+ groupLabel: e.descriptor.label,
23124
+ rowIndex: idx,
23125
+ label: null,
23126
+ fieldKey: e.descriptor.discriminator.propertyName
23127
+ });
22894
23128
  return;
22895
23129
  }
22896
- const mandatoryItemKeys = effectiveItemFields(e.descriptor, row).filter((f) => f.mandatory).map((f) => f.key);
22897
- for (const mk of mandatoryItemKeys) {
22898
- if (isEmptyValue(row[mk])) count++;
23130
+ for (const f of effectiveItemFields(e.descriptor, row)) {
23131
+ if (!f.mandatory) continue;
23132
+ if (isEmptyValue(row[f.key])) {
23133
+ out.push({
23134
+ scope: "row",
23135
+ key: e.key,
23136
+ groupLabel: e.descriptor.label,
23137
+ rowIndex: idx,
23138
+ label: f.label,
23139
+ fieldKey: f.key
23140
+ });
23141
+ }
22899
23142
  }
22900
23143
  });
22901
23144
  }
22902
- return count;
23145
+ return out;
22903
23146
  }, [
22904
23147
  entries,
22905
23148
  scalarGaps,
@@ -22908,9 +23151,11 @@ const useReportPreviewState = ({
22908
23151
  edits,
22909
23152
  filledScalarGaps
22910
23153
  ]);
23154
+ const blockingMandatoryCount = blockingGaps.length;
22911
23155
  return {
22912
23156
  entries,
22913
23157
  scalarGaps,
23158
+ blockingGaps,
22914
23159
  rowGaps,
22915
23160
  selectedKeys,
22916
23161
  selectedRows,
@@ -23634,13 +23879,41 @@ const InsertionPreviewModal = ({
23634
23879
  ]
23635
23880
  }
23636
23881
  ),
23637
- (state.scalarGaps.length > 0 || state.blockingMandatoryCount > 0) && /* @__PURE__ */ jsx$2("p", { className: "omniscribe_insertion-preview__sub", children: state.blockingMandatoryCount > 0 ? /* @__PURE__ */ jsx$2("strong", { className: "omniscribe_insertion-preview__sub--blocking", children: formatMessage(
23638
- {
23639
- id: "{count} mandatory fields must be filled before applying",
23640
- defaultMessage: "{count, plural, one {# mandatory field} other {# mandatory fields}} must be filled before applying"
23641
- },
23642
- { count: state.blockingMandatoryCount }
23643
- ) }) : formatMessage(
23882
+ (state.scalarGaps.length > 0 || state.blockingMandatoryCount > 0) && /* @__PURE__ */ jsx$2("p", { className: "omniscribe_insertion-preview__sub", children: state.blockingMandatoryCount > 0 ? /* @__PURE__ */ jsxs("strong", { className: "omniscribe_insertion-preview__sub--blocking", children: [
23883
+ formatMessage(
23884
+ {
23885
+ id: "{count} mandatory fields must be filled before applying",
23886
+ defaultMessage: "{count, plural, one {# mandatory field} other {# mandatory fields}} must be filled before applying"
23887
+ },
23888
+ { count: state.blockingMandatoryCount }
23889
+ ),
23890
+ ": ",
23891
+ state.blockingGaps.slice(0, BLOCKING_GAPS_SHOWN).map(
23892
+ (g) => g.scope === "field" ? g.label : g.label === null ? formatMessage(
23893
+ {
23894
+ id: "{group} · row {row}",
23895
+ defaultMessage: "{group} · row {row}"
23896
+ },
23897
+ { group: g.groupLabel, row: g.rowIndex + 1 }
23898
+ ) : formatMessage(
23899
+ {
23900
+ id: "{group} · row {row} · {field}",
23901
+ defaultMessage: "{group} · row {row} · {field}"
23902
+ },
23903
+ {
23904
+ group: g.groupLabel,
23905
+ row: g.rowIndex + 1,
23906
+ field: g.label
23907
+ }
23908
+ )
23909
+ ).join(", "),
23910
+ state.blockingGaps.length > BLOCKING_GAPS_SHOWN && formatMessage(
23911
+ { id: " +{count} more", defaultMessage: " +{count} more" },
23912
+ {
23913
+ count: state.blockingGaps.length - BLOCKING_GAPS_SHOWN
23914
+ }
23915
+ )
23916
+ ] }) : formatMessage(
23644
23917
  {
23645
23918
  id: "{count} fields need your attention",
23646
23919
  defaultMessage: "{count, plural, one {# field needs} other {# fields need}} your attention"
@@ -23826,14 +24099,44 @@ const EntrySection = ({
23826
24099
  classNames
23827
24100
  }) => {
23828
24101
  const { formatMessage } = useIntl();
23829
- const hasMandatoryRowGap = React.useMemo(() => {
23830
- const gaps = state.rowGaps.get(entry.key);
23831
- return !!gaps?.some((g) => g.mandatoryMissingKeys.length > 0);
23832
- }, [state.rowGaps, entry.key]);
24102
+ const blockingRows = React.useMemo(
24103
+ () => state.blockingGaps.filter((g) => g.scope === "row" && g.key === entry.key),
24104
+ [state.blockingGaps, entry.key]
24105
+ );
24106
+ const hasMandatoryRowGap = blockingRows.length > 0;
24107
+ const missingFieldCount = blockingRows.filter(
24108
+ (g) => g.scope === "row" && g.label !== null
24109
+ ).length;
24110
+ const untypedRowCount = blockingRows.length - missingFieldCount;
24111
+ const groupGapSummary = [
24112
+ missingFieldCount > 0 && formatMessage(
24113
+ {
24114
+ id: "{count} mandatory fields missing in this group",
24115
+ defaultMessage: "{count, plural, one {# mandatory field missing} other {# mandatory fields missing}} in this group"
24116
+ },
24117
+ { count: missingFieldCount }
24118
+ ),
24119
+ untypedRowCount > 0 && formatMessage(
24120
+ {
24121
+ id: "{count} rows need a type selected in this group",
24122
+ defaultMessage: "{count, plural, one {# row needs} other {# rows need}} a type selected in this group"
24123
+ },
24124
+ { count: untypedRowCount }
24125
+ )
24126
+ ].filter(Boolean).join(" · ");
23833
24127
  const [expanded, setExpanded] = React.useState(hasMandatoryRowGap);
23834
24128
  React.useEffect(() => {
23835
24129
  if (hasMandatoryRowGap) setExpanded(true);
23836
24130
  }, [hasMandatoryRowGap]);
24131
+ const missingKeysOfRow = (idx) => {
24132
+ const keys = new Set(
24133
+ state.rowGaps.get(entry.key)?.find((g) => g.index === idx)?.missingKeys
24134
+ );
24135
+ for (const g of blockingRows) {
24136
+ if (g.scope === "row" && g.rowIndex === idx) keys.add(g.fieldKey);
24137
+ }
24138
+ return [...keys];
24139
+ };
23837
24140
  if (entry.descriptor.kind === "array-of-objects") {
23838
24141
  const rows = entry.value;
23839
24142
  return /* @__PURE__ */ jsxs(
@@ -23859,7 +24162,23 @@ const EntrySection = ({
23859
24162
  /* @__PURE__ */ jsx$2("div", { className: "omniscribe_insertion-preview__row-body", children: /* @__PURE__ */ jsxs("div", { className: "omniscribe_insertion-preview__row-label", children: [
23860
24163
  entry.descriptor.label,
23861
24164
  " · ",
23862
- rows.length
24165
+ rows.length,
24166
+ hasMandatoryRowGap && // `role="img"` + `aria-label`: a `title` alone is not exposed
24167
+ // reliably, so a screen reader announced only "star 1".
24168
+ /* @__PURE__ */ jsxs(
24169
+ "span",
24170
+ {
24171
+ className: "omniscribe_insertion-preview__group-count--gap",
24172
+ role: "img",
24173
+ title: groupGapSummary,
24174
+ "aria-label": groupGapSummary,
24175
+ children: [
24176
+ " ",
24177
+ "★ ",
24178
+ blockingRows.length
24179
+ ]
24180
+ }
24181
+ )
23863
24182
  ] }) })
23864
24183
  ] }),
23865
24184
  /* @__PURE__ */ jsx$2(
@@ -23880,7 +24199,7 @@ const EntrySection = ({
23880
24199
  row,
23881
24200
  descriptor: entry.descriptor,
23882
24201
  state,
23883
- missingKeys: state.rowGaps.get(entry.key)?.find((g) => g.index === idx)?.missingKeys ?? [],
24202
+ missingKeys: missingKeysOfRow(idx),
23884
24203
  classNames
23885
24204
  },
23886
24205
  idx
@@ -24046,6 +24365,7 @@ const RowItem = ({
24046
24365
  }
24047
24366
  );
24048
24367
  };
24368
+ const BLOCKING_GAPS_SHOWN = 3;
24049
24369
  const ScalarGapRow = ({
24050
24370
  descriptor,
24051
24371
  value,
@@ -156953,6 +157273,7 @@ const useBrowserCapabilityCheck = () => {
156953
157273
  }, []);
156954
157274
  };
156955
157275
 
157276
+ const MISSING_SUBSCRIPTIONS_GRACE_MS = 1e3;
156956
157277
  const BrowserCapabilityProbe = () => {
156957
157278
  useBrowserCapabilityCheck();
156958
157279
  return null;
@@ -157053,13 +157374,15 @@ const Omniscribe = ({
157053
157374
  if (!hasEventHandler) return;
157054
157375
  return SdkEventBus.setHandler((event) => onEventRef.current?.(event));
157055
157376
  }, [hasEventHandler]);
157377
+ const hasSubscriptionsProp = eventSubscriptions !== void 0 && eventSubscriptions !== null;
157056
157378
  React.useEffect(() => {
157057
- if (hasEventHandler && !eventSubscriptions?.length) {
157058
- logger.warn(
157059
- '[Sofia SDK] onEvent was provided without eventSubscriptions, so no events will be delivered. Pass e.g. ["recording.*", "activity.*"].'
157060
- );
157061
- }
157062
- }, [hasEventHandler, eventSubscriptions]);
157379
+ if (!hasEventHandler || hasSubscriptionsProp) return;
157380
+ const timer = setTimeout(
157381
+ reportHandlerWithoutSubscriptions,
157382
+ MISSING_SUBSCRIPTIONS_GRACE_MS
157383
+ );
157384
+ return () => clearTimeout(timer);
157385
+ }, [hasEventHandler, hasSubscriptionsProp]);
157063
157386
  React.useEffect(() => {
157064
157387
  if (apikey && apikey.trim() !== "") {
157065
157388
  setEncryptionSeed(apikey);