@fieldia/core 0.21.0 → 0.22.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 (127) hide show
  1. package/README.md +116 -1
  2. package/package.json +1 -1
  3. package/schema/page.schema.json +149 -1
  4. package/src/index.d.mts +2 -2
  5. package/src/index.d.ts +2 -2
  6. package/src/index.js +3 -1
  7. package/src/index.js.map +1 -1
  8. package/src/index.mjs +2 -2
  9. package/src/index.mjs.map +1 -1
  10. package/src/lib/format/check-page.d.mts +3 -2
  11. package/src/lib/format/check-page.d.ts +3 -2
  12. package/src/lib/format/check-page.js +9 -4
  13. package/src/lib/format/check-page.js.map +1 -1
  14. package/src/lib/format/check-page.mjs +10 -5
  15. package/src/lib/format/check-page.mjs.map +1 -1
  16. package/src/lib/format/field.d.mts +85 -0
  17. package/src/lib/format/field.d.ts +85 -0
  18. package/src/lib/format/field.js +14 -1
  19. package/src/lib/format/field.js.map +1 -1
  20. package/src/lib/format/field.mjs +13 -0
  21. package/src/lib/format/field.mjs.map +1 -1
  22. package/src/lib/format/layout.d.mts +142 -17
  23. package/src/lib/format/layout.d.ts +142 -17
  24. package/src/lib/format/layout.js +18 -1
  25. package/src/lib/format/layout.js.map +1 -1
  26. package/src/lib/format/layout.mjs +17 -0
  27. package/src/lib/format/layout.mjs.map +1 -1
  28. package/src/lib/format/layout.types.d.mts +6 -2
  29. package/src/lib/format/layout.types.d.ts +6 -2
  30. package/src/lib/format/page.d.mts +69 -10
  31. package/src/lib/format/page.d.ts +69 -10
  32. package/src/lib/format/page.js +4 -1
  33. package/src/lib/format/page.js.map +1 -1
  34. package/src/lib/format/page.mjs +5 -2
  35. package/src/lib/format/page.mjs.map +1 -1
  36. package/src/lib/format/references.d.mts +7 -0
  37. package/src/lib/format/references.d.ts +7 -0
  38. package/src/lib/format/references.js +46 -0
  39. package/src/lib/format/references.js.map +1 -1
  40. package/src/lib/format/references.mjs +46 -0
  41. package/src/lib/format/references.mjs.map +1 -1
  42. package/src/lib/format/translate.js +3 -2
  43. package/src/lib/format/translate.js.map +1 -1
  44. package/src/lib/format/translate.mjs +3 -2
  45. package/src/lib/format/translate.mjs.map +1 -1
  46. package/src/lib/format/upgrade.d.mts +41 -0
  47. package/src/lib/format/upgrade.d.ts +41 -0
  48. package/src/lib/format/upgrade.js +41 -0
  49. package/src/lib/format/upgrade.js.map +1 -0
  50. package/src/lib/format/upgrade.mjs +37 -0
  51. package/src/lib/format/upgrade.mjs.map +1 -0
  52. package/src/lib/format/validate.d.mts +2 -1
  53. package/src/lib/format/validate.d.ts +2 -1
  54. package/src/lib/format/validate.js +4 -2
  55. package/src/lib/format/validate.js.map +1 -1
  56. package/src/lib/format/validate.mjs +4 -2
  57. package/src/lib/format/validate.mjs.map +1 -1
  58. package/src/lib/format/version.d.mts +16 -1
  59. package/src/lib/format/version.d.ts +16 -1
  60. package/src/lib/format/version.js +39 -2
  61. package/src/lib/format/version.js.map +1 -1
  62. package/src/lib/format/version.mjs +36 -1
  63. package/src/lib/format/version.mjs.map +1 -1
  64. package/src/lib/record/data-source.d.mts +224 -10
  65. package/src/lib/record/data-source.d.ts +224 -10
  66. package/src/lib/record/data-source.js +29 -0
  67. package/src/lib/record/data-source.js.map +1 -1
  68. package/src/lib/record/data-source.mjs +25 -0
  69. package/src/lib/record/data-source.mjs.map +1 -1
  70. package/src/lib/record/form.d.mts +144 -5
  71. package/src/lib/record/form.d.ts +144 -5
  72. package/src/lib/record/form.js +792 -42
  73. package/src/lib/record/form.js.map +1 -1
  74. package/src/lib/record/form.mjs +791 -43
  75. package/src/lib/record/form.mjs.map +1 -1
  76. package/src/lib/record/locales/ar.js +10 -0
  77. package/src/lib/record/locales/ar.js.map +1 -1
  78. package/src/lib/record/locales/ar.mjs +10 -0
  79. package/src/lib/record/locales/ar.mjs.map +1 -1
  80. package/src/lib/record/locales/de.js +10 -0
  81. package/src/lib/record/locales/de.js.map +1 -1
  82. package/src/lib/record/locales/de.mjs +10 -0
  83. package/src/lib/record/locales/de.mjs.map +1 -1
  84. package/src/lib/record/locales/fr.js +10 -0
  85. package/src/lib/record/locales/fr.js.map +1 -1
  86. package/src/lib/record/locales/fr.mjs +10 -0
  87. package/src/lib/record/locales/fr.mjs.map +1 -1
  88. package/src/lib/record/memory-data-source.d.mts +40 -3
  89. package/src/lib/record/memory-data-source.d.ts +40 -3
  90. package/src/lib/record/memory-data-source.js +164 -20
  91. package/src/lib/record/memory-data-source.js.map +1 -1
  92. package/src/lib/record/memory-data-source.mjs +164 -20
  93. package/src/lib/record/memory-data-source.mjs.map +1 -1
  94. package/src/lib/record/messages.d.mts +21 -0
  95. package/src/lib/record/messages.d.ts +21 -0
  96. package/src/lib/record/messages.js +10 -0
  97. package/src/lib/record/messages.js.map +1 -1
  98. package/src/lib/record/messages.mjs +10 -0
  99. package/src/lib/record/messages.mjs.map +1 -1
  100. package/src/lib/record/run.d.mts +50 -7
  101. package/src/lib/record/run.d.ts +50 -7
  102. package/src/lib/record/run.js +67 -20
  103. package/src/lib/record/run.js.map +1 -1
  104. package/src/lib/record/run.mjs +67 -20
  105. package/src/lib/record/run.mjs.map +1 -1
  106. package/src/lib/record/upload-to.d.mts +50 -0
  107. package/src/lib/record/upload-to.d.ts +50 -0
  108. package/src/lib/record/upload-to.js +117 -0
  109. package/src/lib/record/upload-to.js.map +1 -0
  110. package/src/lib/record/upload-to.mjs +114 -0
  111. package/src/lib/record/upload-to.mjs.map +1 -0
  112. package/src/lib/record/uploads.d.mts +152 -0
  113. package/src/lib/record/uploads.d.ts +152 -0
  114. package/src/lib/record/uploads.js +345 -0
  115. package/src/lib/record/uploads.js.map +1 -0
  116. package/src/lib/record/uploads.mjs +337 -0
  117. package/src/lib/record/uploads.mjs.map +1 -0
  118. package/src/lib/record/values.d.mts +6 -0
  119. package/src/lib/record/values.d.ts +6 -0
  120. package/src/lib/record/values.js.map +1 -1
  121. package/src/lib/record/values.mjs.map +1 -1
  122. package/src/runtime.d.mts +10 -6
  123. package/src/runtime.d.ts +10 -6
  124. package/src/runtime.js +19 -2
  125. package/src/runtime.js.map +1 -1
  126. package/src/runtime.mjs +7 -3
  127. package/src/runtime.mjs.map +1 -1
@@ -35,6 +35,9 @@ exports.de = {
35
35
  fileType: '{label} muss eine {types}-Datei sein',
36
36
  minFiles: 'Fügen Sie {label} mindestens {min} Dateien hinzu',
37
37
  maxFiles: 'Zu viele Dateien für {label}: höchstens {max}',
38
+ notUploaded: '{name} wurde nicht hochgeladen: erneut versuchen oder entfernen',
39
+ notUploadedMany: '{n} Dateien wurden nicht hochgeladen: erneut versuchen oder entfernen',
40
+ fileRefused: '{name} wurde nicht angenommen: {reason}',
38
41
  minLength: '{label} muss mindestens {min} Zeichen haben',
39
42
  endsWith: '{label} muss auf {ending} enden',
40
43
  atLeast: 'Wählen Sie bei {label} mindestens {min} aus',
@@ -57,6 +60,13 @@ exports.de = {
57
60
  addressParts: 'Straße und Hausnummer|Adresszeile 2|Ort|Bundesland oder Region|Postleitzahl|Land',
58
61
  archiveConfirm: 'Möchten Sie diesen Datensatz wirklich archivieren?',
59
62
  deleteConfirm: 'Möchten Sie diesen Datensatz wirklich löschen?',
63
+ mayNotEdit: 'Sie können diesen Datensatz lesen, aber nicht ändern.',
64
+ mayNotArchive: 'Sie können diesen Datensatz nicht archivieren.',
65
+ mayNotDuplicate: 'Sie können diesen Datensatz nicht duplizieren.',
66
+ mayNotDelete: 'Sie können diesen Datensatz nicht löschen.',
67
+ theirsUnread: 'Die andere Fassung konnte nicht gelesen werden, darum wurde Ihre nicht darüber gespeichert. Versuchen Sie Meine behalten erneut, oder Neu laden.',
68
+ discardChanges: 'Ihre Änderungen verwerfen?',
69
+ recordReplaced: 'Jetzt wird ein anderer Datensatz angezeigt: die übrigen Schritte wurden nicht ausgeführt.',
60
70
  overBy: '{label} ist {over} Zeichen zu lang (höchstens {max}); kürzen Sie es zum Speichern',
61
71
  overByOne: '{label} ist 1 Zeichen zu lang (höchstens {max}); kürzen Sie es zum Speichern',
62
72
  postcode: '{label}: Postleitzahl für {country} mit {n} Ziffern, z. B. {example}',
@@ -1 +1 @@
1
- {"version":3,"file":"de.js","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/de.ts"],"names":[],"mappings":";;;AAEA,yCAAyC;AAC5B,QAAA,EAAE,GAAa;IAC1B,QAAQ,EAAE,0BAA0B;IACpC,SAAS,EAAE,qCAAqC;IAChD,OAAO,EAAE,wCAAwC;IACjD,IAAI,EAAE,wBAAwB;IAC9B,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,mCAAmC;IAC5C,GAAG,EAAE,oCAAoC;IACzC,GAAG,EAAE,mCAAmC;IACxC,QAAQ,EAAE,iDAAiD;IAC3D,WAAW,EAAE,4CAA4C;IACzD,WAAW,EAAE,iDAAiD;IAC9D,YAAY,EAAE,iDAAiD;IAC/D,MAAM,EAAE,mCAAmC;IAC3C,OAAO,EAAE,gCAAgC;IACzC,UAAU,EAAE,+CAA+C;IAC3D,WAAW,EAAE,yCAAyC;IACtD,cAAc,EAAE,kEAAkE;IAClF,eAAe,EAAE,yCAAyC;IAC1D,MAAM,EAAE,kCAAkC;IAC1C,aAAa,EAAE,6DAA6D;IAC5E,MAAM,EAAE,uCAAuC;IAC/C,SAAS,EAAE,yBAAyB;IACpC,UAAU,EAAE,wCAAwC;IACpD,OAAO,EAAE,2CAA2C;IACpD,MAAM,EAAE,iCAAiC;IACzC,OAAO,EAAE,8CAA8C;IACvD,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,+BAA+B;IACzC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,kDAAkD;IAC5D,QAAQ,EAAE,+CAA+C;IACzD,SAAS,EAAE,6CAA6C;IACxD,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,6CAA6C;IACtD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,0CAA0C;IACpD,UAAU,EAAE,oCAAoC;IAChD,KAAK,EAAE,8CAA8C;IACrD,QAAQ,EAAE,6DAA6D;IACvE,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,iDAAiD;IACvD,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,kDAAkD;IACvD,KAAK,EAAE,0DAA0D;IACjE,IAAI,EAAE,yCAAyC;IAC/C,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,2BAA2B;IAClC,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,0CAA0C;IACpD,QAAQ,EAAE,sCAAsC;IAChD,YAAY,EAAE,kFAAkF;IAChG,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,mFAAmF;IAC3F,SAAS,EAAE,8EAA8E;IACzF,QAAQ,EAAE,sEAAsE;IAChF,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,qCAAqC;IACrD,QAAQ,EAAE,iFAAiF;IAC3F,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,IAAI;CACb,CAAC"}
1
+ {"version":3,"file":"de.js","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/de.ts"],"names":[],"mappings":";;;AAEA,yCAAyC;AAC5B,QAAA,EAAE,GAAa;IAC1B,QAAQ,EAAE,0BAA0B;IACpC,SAAS,EAAE,qCAAqC;IAChD,OAAO,EAAE,wCAAwC;IACjD,IAAI,EAAE,wBAAwB;IAC9B,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,mCAAmC;IAC5C,GAAG,EAAE,oCAAoC;IACzC,GAAG,EAAE,mCAAmC;IACxC,QAAQ,EAAE,iDAAiD;IAC3D,WAAW,EAAE,4CAA4C;IACzD,WAAW,EAAE,iDAAiD;IAC9D,YAAY,EAAE,iDAAiD;IAC/D,MAAM,EAAE,mCAAmC;IAC3C,OAAO,EAAE,gCAAgC;IACzC,UAAU,EAAE,+CAA+C;IAC3D,WAAW,EAAE,yCAAyC;IACtD,cAAc,EAAE,kEAAkE;IAClF,eAAe,EAAE,yCAAyC;IAC1D,MAAM,EAAE,kCAAkC;IAC1C,aAAa,EAAE,6DAA6D;IAC5E,MAAM,EAAE,uCAAuC;IAC/C,SAAS,EAAE,yBAAyB;IACpC,UAAU,EAAE,wCAAwC;IACpD,OAAO,EAAE,2CAA2C;IACpD,MAAM,EAAE,iCAAiC;IACzC,OAAO,EAAE,8CAA8C;IACvD,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,+BAA+B;IACzC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,kDAAkD;IAC5D,QAAQ,EAAE,+CAA+C;IACzD,WAAW,EAAE,iEAAiE;IAC9E,eAAe,EAAE,uEAAuE;IACxF,WAAW,EAAE,yCAAyC;IACtD,SAAS,EAAE,6CAA6C;IACxD,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,6CAA6C;IACtD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,0CAA0C;IACpD,UAAU,EAAE,oCAAoC;IAChD,KAAK,EAAE,8CAA8C;IACrD,QAAQ,EAAE,6DAA6D;IACvE,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,iDAAiD;IACvD,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,kDAAkD;IACvD,KAAK,EAAE,0DAA0D;IACjE,IAAI,EAAE,yCAAyC;IAC/C,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,2BAA2B;IAClC,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,0CAA0C;IACpD,QAAQ,EAAE,sCAAsC;IAChD,YAAY,EAAE,kFAAkF;IAChG,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,gDAAgD;IAC/D,UAAU,EAAE,uDAAuD;IACnE,aAAa,EAAE,gDAAgD;IAC/D,eAAe,EAAE,gDAAgD;IACjE,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,kJAAkJ;IAChK,cAAc,EAAE,4BAA4B;IAC5C,cAAc,EAAE,2FAA2F;IAC3G,MAAM,EAAE,mFAAmF;IAC3F,SAAS,EAAE,8EAA8E;IACzF,QAAQ,EAAE,sEAAsE;IAChF,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,qCAAqC;IACrD,QAAQ,EAAE,iFAAiF;IAC3F,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,IAAI;CACb,CAAC"}
@@ -32,6 +32,9 @@ export const de = {
32
32
  fileType: '{label} muss eine {types}-Datei sein',
33
33
  minFiles: 'Fügen Sie {label} mindestens {min} Dateien hinzu',
34
34
  maxFiles: 'Zu viele Dateien für {label}: höchstens {max}',
35
+ notUploaded: '{name} wurde nicht hochgeladen: erneut versuchen oder entfernen',
36
+ notUploadedMany: '{n} Dateien wurden nicht hochgeladen: erneut versuchen oder entfernen',
37
+ fileRefused: '{name} wurde nicht angenommen: {reason}',
35
38
  minLength: '{label} muss mindestens {min} Zeichen haben',
36
39
  endsWith: '{label} muss auf {ending} enden',
37
40
  atLeast: 'Wählen Sie bei {label} mindestens {min} aus',
@@ -54,6 +57,13 @@ export const de = {
54
57
  addressParts: 'Straße und Hausnummer|Adresszeile 2|Ort|Bundesland oder Region|Postleitzahl|Land',
55
58
  archiveConfirm: 'Möchten Sie diesen Datensatz wirklich archivieren?',
56
59
  deleteConfirm: 'Möchten Sie diesen Datensatz wirklich löschen?',
60
+ mayNotEdit: 'Sie können diesen Datensatz lesen, aber nicht ändern.',
61
+ mayNotArchive: 'Sie können diesen Datensatz nicht archivieren.',
62
+ mayNotDuplicate: 'Sie können diesen Datensatz nicht duplizieren.',
63
+ mayNotDelete: 'Sie können diesen Datensatz nicht löschen.',
64
+ theirsUnread: 'Die andere Fassung konnte nicht gelesen werden, darum wurde Ihre nicht darüber gespeichert. Versuchen Sie Meine behalten erneut, oder Neu laden.',
65
+ discardChanges: 'Ihre Änderungen verwerfen?',
66
+ recordReplaced: 'Jetzt wird ein anderer Datensatz angezeigt: die übrigen Schritte wurden nicht ausgeführt.',
57
67
  overBy: '{label} ist {over} Zeichen zu lang (höchstens {max}); kürzen Sie es zum Speichern',
58
68
  overByOne: '{label} ist 1 Zeichen zu lang (höchstens {max}); kürzen Sie es zum Speichern',
59
69
  postcode: '{label}: Postleitzahl für {country} mit {n} Ziffern, z. B. {example}',
@@ -1 +1 @@
1
- {"version":3,"file":"de.mjs","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/de.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,CAAC,MAAM,EAAE,GAAa;IAC1B,QAAQ,EAAE,0BAA0B;IACpC,SAAS,EAAE,qCAAqC;IAChD,OAAO,EAAE,wCAAwC;IACjD,IAAI,EAAE,wBAAwB;IAC9B,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,mCAAmC;IAC5C,GAAG,EAAE,oCAAoC;IACzC,GAAG,EAAE,mCAAmC;IACxC,QAAQ,EAAE,iDAAiD;IAC3D,WAAW,EAAE,4CAA4C;IACzD,WAAW,EAAE,iDAAiD;IAC9D,YAAY,EAAE,iDAAiD;IAC/D,MAAM,EAAE,mCAAmC;IAC3C,OAAO,EAAE,gCAAgC;IACzC,UAAU,EAAE,+CAA+C;IAC3D,WAAW,EAAE,yCAAyC;IACtD,cAAc,EAAE,kEAAkE;IAClF,eAAe,EAAE,yCAAyC;IAC1D,MAAM,EAAE,kCAAkC;IAC1C,aAAa,EAAE,6DAA6D;IAC5E,MAAM,EAAE,uCAAuC;IAC/C,SAAS,EAAE,yBAAyB;IACpC,UAAU,EAAE,wCAAwC;IACpD,OAAO,EAAE,2CAA2C;IACpD,MAAM,EAAE,iCAAiC;IACzC,OAAO,EAAE,8CAA8C;IACvD,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,+BAA+B;IACzC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,kDAAkD;IAC5D,QAAQ,EAAE,+CAA+C;IACzD,SAAS,EAAE,6CAA6C;IACxD,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,6CAA6C;IACtD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,0CAA0C;IACpD,UAAU,EAAE,oCAAoC;IAChD,KAAK,EAAE,8CAA8C;IACrD,QAAQ,EAAE,6DAA6D;IACvE,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,iDAAiD;IACvD,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,kDAAkD;IACvD,KAAK,EAAE,0DAA0D;IACjE,IAAI,EAAE,yCAAyC;IAC/C,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,2BAA2B;IAClC,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,0CAA0C;IACpD,QAAQ,EAAE,sCAAsC;IAChD,YAAY,EAAE,kFAAkF;IAChG,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,mFAAmF;IAC3F,SAAS,EAAE,8EAA8E;IACzF,QAAQ,EAAE,sEAAsE;IAChF,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,qCAAqC;IACrD,QAAQ,EAAE,iFAAiF;IAC3F,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,IAAI;CACb,CAAC"}
1
+ {"version":3,"file":"de.mjs","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/de.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,CAAC,MAAM,EAAE,GAAa;IAC1B,QAAQ,EAAE,0BAA0B;IACpC,SAAS,EAAE,qCAAqC;IAChD,OAAO,EAAE,wCAAwC;IACjD,IAAI,EAAE,wBAAwB;IAC9B,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,mCAAmC;IAC5C,GAAG,EAAE,oCAAoC;IACzC,GAAG,EAAE,mCAAmC;IACxC,QAAQ,EAAE,iDAAiD;IAC3D,WAAW,EAAE,4CAA4C;IACzD,WAAW,EAAE,iDAAiD;IAC9D,YAAY,EAAE,iDAAiD;IAC/D,MAAM,EAAE,mCAAmC;IAC3C,OAAO,EAAE,gCAAgC;IACzC,UAAU,EAAE,+CAA+C;IAC3D,WAAW,EAAE,yCAAyC;IACtD,cAAc,EAAE,kEAAkE;IAClF,eAAe,EAAE,yCAAyC;IAC1D,MAAM,EAAE,kCAAkC;IAC1C,aAAa,EAAE,6DAA6D;IAC5E,MAAM,EAAE,uCAAuC;IAC/C,SAAS,EAAE,yBAAyB;IACpC,UAAU,EAAE,wCAAwC;IACpD,OAAO,EAAE,2CAA2C;IACpD,MAAM,EAAE,iCAAiC;IACzC,OAAO,EAAE,8CAA8C;IACvD,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,+BAA+B;IACzC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,kDAAkD;IAC5D,QAAQ,EAAE,+CAA+C;IACzD,WAAW,EAAE,iEAAiE;IAC9E,eAAe,EAAE,uEAAuE;IACxF,WAAW,EAAE,yCAAyC;IACtD,SAAS,EAAE,6CAA6C;IACxD,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,6CAA6C;IACtD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,0CAA0C;IACpD,UAAU,EAAE,oCAAoC;IAChD,KAAK,EAAE,8CAA8C;IACrD,QAAQ,EAAE,6DAA6D;IACvE,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,iDAAiD;IACvD,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,kDAAkD;IACvD,KAAK,EAAE,0DAA0D;IACjE,IAAI,EAAE,yCAAyC;IAC/C,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,2BAA2B;IAClC,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,0CAA0C;IACpD,QAAQ,EAAE,sCAAsC;IAChD,YAAY,EAAE,kFAAkF;IAChG,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,gDAAgD;IAC/D,UAAU,EAAE,uDAAuD;IACnE,aAAa,EAAE,gDAAgD;IAC/D,eAAe,EAAE,gDAAgD;IACjE,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,kJAAkJ;IAChK,cAAc,EAAE,4BAA4B;IAC5C,cAAc,EAAE,2FAA2F;IAC3G,MAAM,EAAE,mFAAmF;IAC3F,SAAS,EAAE,8EAA8E;IACzF,QAAQ,EAAE,sEAAsE;IAChF,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,qCAAqC;IACrD,QAAQ,EAAE,iFAAiF;IAC3F,aAAa,EAAE,gDAAgD;IAC/D,MAAM,EAAE,IAAI;CACb,CAAC"}
@@ -35,6 +35,9 @@ exports.fr = {
35
35
  fileType: '{label} doit être un fichier {types}',
36
36
  minFiles: 'Ajoutez au moins {min} fichiers à {label}',
37
37
  maxFiles: 'Trop de fichiers pour {label} : {max} au plus',
38
+ notUploaded: '{name} n’a pas été envoyé : réessayez, ou retirez-le',
39
+ notUploadedMany: '{n} fichiers n’ont pas été envoyés : réessayez, ou retirez-les',
40
+ fileRefused: '{name} n’a pas été accepté : {reason}',
38
41
  minLength: '{label} doit comporter au moins {min} caractères',
39
42
  endsWith: '{label} doit se terminer par {ending}',
40
43
  atLeast: 'Choisissez au moins {min} pour {label}',
@@ -57,6 +60,13 @@ exports.fr = {
57
60
  addressParts: 'Adresse|Complément d’adresse|Ville|État ou région|Code postal|Pays',
58
61
  archiveConfirm: 'Voulez-vous vraiment archiver cet enregistrement ?',
59
62
  deleteConfirm: 'Voulez-vous vraiment supprimer cet enregistrement ?',
63
+ mayNotEdit: 'Vous pouvez lire cet enregistrement, mais pas le modifier.',
64
+ mayNotArchive: 'Vous ne pouvez pas archiver cet enregistrement.',
65
+ mayNotDuplicate: 'Vous ne pouvez pas dupliquer cet enregistrement.',
66
+ mayNotDelete: 'Vous ne pouvez pas supprimer cet enregistrement.',
67
+ theirsUnread: 'Leur version n’a pas pu être lue : la vôtre n’a donc pas été enregistrée par-dessus. Réessayez Garder les miennes, ou Recharger.',
68
+ discardChanges: 'Abandonner vos modifications ?',
69
+ recordReplaced: 'Un autre enregistrement est affiché : le reste de ces étapes n’a pas été exécuté.',
60
70
  overBy: '{label} dépasse de {over} caractères la limite de {max} : raccourcissez-le pour enregistrer',
61
71
  overByOne: '{label} dépasse d’un caractère la limite de {max} : raccourcissez-le pour enregistrer',
62
72
  postcode: '{label} : code postal de {n} chiffres attendu pour {country}, par exemple {example}',
@@ -1 +1 @@
1
- {"version":3,"file":"fr.js","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/fr.ts"],"names":[],"mappings":";;;AAEA,yCAAyC;AAC5B,QAAA,EAAE,GAAa;IAC1B,QAAQ,EAAE,yBAAyB;IACnC,SAAS,EAAE,0CAA0C;IACrD,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,4BAA4B;IAClC,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,oCAAoC;IAC7C,GAAG,EAAE,kCAAkC;IACvC,GAAG,EAAE,iCAAiC;IACtC,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,sCAAsC;IACnD,WAAW,EAAE,4CAA4C;IACzD,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,sCAAsC;IAC9C,OAAO,EAAE,8BAA8B;IACvC,UAAU,EAAE,8CAA8C;IAC1D,WAAW,EAAE,6CAA6C;IAC1D,cAAc,EAAE,gEAAgE;IAChF,eAAe,EAAE,wBAAwB;IACzC,MAAM,EAAE,6BAA6B;IACrC,aAAa,EAAE,mDAAmD;IAClE,MAAM,EAAE,sCAAsC;IAC9C,SAAS,EAAE,0BAA0B;IACrC,UAAU,EAAE,oCAAoC;IAChD,OAAO,EAAE,sCAAsC;IAC/C,MAAM,EAAE,qCAAqC;IAC7C,OAAO,EAAE,+CAA+C;IACxD,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,wBAAwB;IAClC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,2CAA2C;IACrD,QAAQ,EAAE,+CAA+C;IACzD,SAAS,EAAE,kDAAkD;IAC7D,QAAQ,EAAE,uCAAuC;IACjD,OAAO,EAAE,wCAAwC;IACjD,MAAM,EAAE,uCAAuC;IAC/C,QAAQ,EAAE,iCAAiC;IAC3C,UAAU,EAAE,iCAAiC;IAC7C,KAAK,EAAE,kDAAkD;IACzD,QAAQ,EAAE,2DAA2D;IACrE,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,oDAAoD;IACzD,KAAK,EAAE,iEAAiE;IACxE,IAAI,EAAE,wCAAwC;IAC9C,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,8BAA8B;IACrC,OAAO,EAAE,sCAAsC;IAC/C,QAAQ,EAAE,kCAAkC;IAC5C,QAAQ,EAAE,8CAA8C;IACxD,YAAY,EAAE,oEAAoE;IAClF,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,qDAAqD;IACpE,MAAM,EAAE,6FAA6F;IACrG,SAAS,EAAE,uFAAuF;IAClG,QAAQ,EAAE,qFAAqF;IAC/F,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,oCAAoC;IACpD,QAAQ,EAAE,sFAAsF;IAChG,aAAa,EAAE,kDAAkD;IACjE,MAAM,EAAE,IAAI;CACb,CAAC"}
1
+ {"version":3,"file":"fr.js","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/fr.ts"],"names":[],"mappings":";;;AAEA,yCAAyC;AAC5B,QAAA,EAAE,GAAa;IAC1B,QAAQ,EAAE,yBAAyB;IACnC,SAAS,EAAE,0CAA0C;IACrD,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,4BAA4B;IAClC,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,oCAAoC;IAC7C,GAAG,EAAE,kCAAkC;IACvC,GAAG,EAAE,iCAAiC;IACtC,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,sCAAsC;IACnD,WAAW,EAAE,4CAA4C;IACzD,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,sCAAsC;IAC9C,OAAO,EAAE,8BAA8B;IACvC,UAAU,EAAE,8CAA8C;IAC1D,WAAW,EAAE,6CAA6C;IAC1D,cAAc,EAAE,gEAAgE;IAChF,eAAe,EAAE,wBAAwB;IACzC,MAAM,EAAE,6BAA6B;IACrC,aAAa,EAAE,mDAAmD;IAClE,MAAM,EAAE,sCAAsC;IAC9C,SAAS,EAAE,0BAA0B;IACrC,UAAU,EAAE,oCAAoC;IAChD,OAAO,EAAE,sCAAsC;IAC/C,MAAM,EAAE,qCAAqC;IAC7C,OAAO,EAAE,+CAA+C;IACxD,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,wBAAwB;IAClC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,2CAA2C;IACrD,QAAQ,EAAE,+CAA+C;IACzD,WAAW,EAAE,sDAAsD;IACnE,eAAe,EAAE,gEAAgE;IACjF,WAAW,EAAE,uCAAuC;IACpD,SAAS,EAAE,kDAAkD;IAC7D,QAAQ,EAAE,uCAAuC;IACjD,OAAO,EAAE,wCAAwC;IACjD,MAAM,EAAE,uCAAuC;IAC/C,QAAQ,EAAE,iCAAiC;IAC3C,UAAU,EAAE,iCAAiC;IAC7C,KAAK,EAAE,kDAAkD;IACzD,QAAQ,EAAE,2DAA2D;IACrE,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,oDAAoD;IACzD,KAAK,EAAE,iEAAiE;IACxE,IAAI,EAAE,wCAAwC;IAC9C,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,8BAA8B;IACrC,OAAO,EAAE,sCAAsC;IAC/C,QAAQ,EAAE,kCAAkC;IAC5C,QAAQ,EAAE,8CAA8C;IACxD,YAAY,EAAE,oEAAoE;IAClF,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,qDAAqD;IACpE,UAAU,EAAE,4DAA4D;IACxE,aAAa,EAAE,iDAAiD;IAChE,eAAe,EAAE,kDAAkD;IACnE,YAAY,EAAE,kDAAkD;IAChE,YAAY,EAAE,kIAAkI;IAChJ,cAAc,EAAE,gCAAgC;IAChD,cAAc,EAAE,mFAAmF;IACnG,MAAM,EAAE,6FAA6F;IACrG,SAAS,EAAE,uFAAuF;IAClG,QAAQ,EAAE,qFAAqF;IAC/F,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,oCAAoC;IACpD,QAAQ,EAAE,sFAAsF;IAChG,aAAa,EAAE,kDAAkD;IACjE,MAAM,EAAE,IAAI;CACb,CAAC"}
@@ -32,6 +32,9 @@ export const fr = {
32
32
  fileType: '{label} doit être un fichier {types}',
33
33
  minFiles: 'Ajoutez au moins {min} fichiers à {label}',
34
34
  maxFiles: 'Trop de fichiers pour {label} : {max} au plus',
35
+ notUploaded: '{name} n’a pas été envoyé : réessayez, ou retirez-le',
36
+ notUploadedMany: '{n} fichiers n’ont pas été envoyés : réessayez, ou retirez-les',
37
+ fileRefused: '{name} n’a pas été accepté : {reason}',
35
38
  minLength: '{label} doit comporter au moins {min} caractères',
36
39
  endsWith: '{label} doit se terminer par {ending}',
37
40
  atLeast: 'Choisissez au moins {min} pour {label}',
@@ -54,6 +57,13 @@ export const fr = {
54
57
  addressParts: 'Adresse|Complément d’adresse|Ville|État ou région|Code postal|Pays',
55
58
  archiveConfirm: 'Voulez-vous vraiment archiver cet enregistrement ?',
56
59
  deleteConfirm: 'Voulez-vous vraiment supprimer cet enregistrement ?',
60
+ mayNotEdit: 'Vous pouvez lire cet enregistrement, mais pas le modifier.',
61
+ mayNotArchive: 'Vous ne pouvez pas archiver cet enregistrement.',
62
+ mayNotDuplicate: 'Vous ne pouvez pas dupliquer cet enregistrement.',
63
+ mayNotDelete: 'Vous ne pouvez pas supprimer cet enregistrement.',
64
+ theirsUnread: 'Leur version n’a pas pu être lue : la vôtre n’a donc pas été enregistrée par-dessus. Réessayez Garder les miennes, ou Recharger.',
65
+ discardChanges: 'Abandonner vos modifications ?',
66
+ recordReplaced: 'Un autre enregistrement est affiché : le reste de ces étapes n’a pas été exécuté.',
57
67
  overBy: '{label} dépasse de {over} caractères la limite de {max} : raccourcissez-le pour enregistrer',
58
68
  overByOne: '{label} dépasse d’un caractère la limite de {max} : raccourcissez-le pour enregistrer',
59
69
  postcode: '{label} : code postal de {n} chiffres attendu pour {country}, par exemple {example}',
@@ -1 +1 @@
1
- {"version":3,"file":"fr.mjs","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/fr.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,CAAC,MAAM,EAAE,GAAa;IAC1B,QAAQ,EAAE,yBAAyB;IACnC,SAAS,EAAE,0CAA0C;IACrD,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,4BAA4B;IAClC,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,oCAAoC;IAC7C,GAAG,EAAE,kCAAkC;IACvC,GAAG,EAAE,iCAAiC;IACtC,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,sCAAsC;IACnD,WAAW,EAAE,4CAA4C;IACzD,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,sCAAsC;IAC9C,OAAO,EAAE,8BAA8B;IACvC,UAAU,EAAE,8CAA8C;IAC1D,WAAW,EAAE,6CAA6C;IAC1D,cAAc,EAAE,gEAAgE;IAChF,eAAe,EAAE,wBAAwB;IACzC,MAAM,EAAE,6BAA6B;IACrC,aAAa,EAAE,mDAAmD;IAClE,MAAM,EAAE,sCAAsC;IAC9C,SAAS,EAAE,0BAA0B;IACrC,UAAU,EAAE,oCAAoC;IAChD,OAAO,EAAE,sCAAsC;IAC/C,MAAM,EAAE,qCAAqC;IAC7C,OAAO,EAAE,+CAA+C;IACxD,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,wBAAwB;IAClC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,2CAA2C;IACrD,QAAQ,EAAE,+CAA+C;IACzD,SAAS,EAAE,kDAAkD;IAC7D,QAAQ,EAAE,uCAAuC;IACjD,OAAO,EAAE,wCAAwC;IACjD,MAAM,EAAE,uCAAuC;IAC/C,QAAQ,EAAE,iCAAiC;IAC3C,UAAU,EAAE,iCAAiC;IAC7C,KAAK,EAAE,kDAAkD;IACzD,QAAQ,EAAE,2DAA2D;IACrE,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,oDAAoD;IACzD,KAAK,EAAE,iEAAiE;IACxE,IAAI,EAAE,wCAAwC;IAC9C,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,8BAA8B;IACrC,OAAO,EAAE,sCAAsC;IAC/C,QAAQ,EAAE,kCAAkC;IAC5C,QAAQ,EAAE,8CAA8C;IACxD,YAAY,EAAE,oEAAoE;IAClF,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,qDAAqD;IACpE,MAAM,EAAE,6FAA6F;IACrG,SAAS,EAAE,uFAAuF;IAClG,QAAQ,EAAE,qFAAqF;IAC/F,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,oCAAoC;IACpD,QAAQ,EAAE,sFAAsF;IAChG,aAAa,EAAE,kDAAkD;IACjE,MAAM,EAAE,IAAI;CACb,CAAC"}
1
+ {"version":3,"file":"fr.mjs","sourceRoot":"","sources":["../../../../../../../libs/core/src/lib/record/locales/fr.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,CAAC,MAAM,EAAE,GAAa;IAC1B,QAAQ,EAAE,yBAAyB;IACnC,SAAS,EAAE,0CAA0C;IACrD,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,4BAA4B;IAClC,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,oCAAoC;IAC7C,GAAG,EAAE,kCAAkC;IACvC,GAAG,EAAE,iCAAiC;IACtC,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,sCAAsC;IACnD,WAAW,EAAE,4CAA4C;IACzD,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,sCAAsC;IAC9C,OAAO,EAAE,8BAA8B;IACvC,UAAU,EAAE,8CAA8C;IAC1D,WAAW,EAAE,6CAA6C;IAC1D,cAAc,EAAE,gEAAgE;IAChF,eAAe,EAAE,wBAAwB;IACzC,MAAM,EAAE,6BAA6B;IACrC,aAAa,EAAE,mDAAmD;IAClE,MAAM,EAAE,sCAAsC;IAC9C,SAAS,EAAE,0BAA0B;IACrC,UAAU,EAAE,oCAAoC;IAChD,OAAO,EAAE,sCAAsC;IAC/C,MAAM,EAAE,qCAAqC;IAC7C,OAAO,EAAE,+CAA+C;IACxD,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,8BAA8B;IACpC,QAAQ,EAAE,wBAAwB;IAClC,QAAQ,EAAE,sCAAsC;IAChD,QAAQ,EAAE,2CAA2C;IACrD,QAAQ,EAAE,+CAA+C;IACzD,WAAW,EAAE,sDAAsD;IACnE,eAAe,EAAE,gEAAgE;IACjF,WAAW,EAAE,uCAAuC;IACpD,SAAS,EAAE,kDAAkD;IAC7D,QAAQ,EAAE,uCAAuC;IACjD,OAAO,EAAE,wCAAwC;IACjD,MAAM,EAAE,uCAAuC;IAC/C,QAAQ,EAAE,iCAAiC;IAC3C,UAAU,EAAE,iCAAiC;IAC7C,KAAK,EAAE,kDAAkD;IACzD,QAAQ,EAAE,2DAA2D;IACrE,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,2DAA2D;IAClE,GAAG,EAAE,oDAAoD;IACzD,KAAK,EAAE,iEAAiE;IACxE,IAAI,EAAE,wCAAwC;IAC9C,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,8BAA8B;IACrC,OAAO,EAAE,sCAAsC;IAC/C,QAAQ,EAAE,kCAAkC;IAC5C,QAAQ,EAAE,8CAA8C;IACxD,YAAY,EAAE,oEAAoE;IAClF,cAAc,EAAE,oDAAoD;IACpE,aAAa,EAAE,qDAAqD;IACpE,UAAU,EAAE,4DAA4D;IACxE,aAAa,EAAE,iDAAiD;IAChE,eAAe,EAAE,kDAAkD;IACnE,YAAY,EAAE,kDAAkD;IAChE,YAAY,EAAE,kIAAkI;IAChJ,cAAc,EAAE,gCAAgC;IAChD,cAAc,EAAE,mFAAmF;IACnG,MAAM,EAAE,6FAA6F;IACrG,SAAS,EAAE,uFAAuF;IAClG,QAAQ,EAAE,qFAAqF;IAC/F,SAAS,EAAE,wDAAwD;IACnE,cAAc,EAAE,oCAAoC;IACpD,QAAQ,EAAE,sFAAsF;IAChG,aAAa,EAAE,kDAAkD;IACjE,MAAM,EAAE,IAAI;CACb,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { Option, PropertyDefinition } from '../format/field.mjs';
2
- import type { DataSource, SubmitRequest } from './data-source.mjs';
2
+ import type { DataSource, SubmitRequest, RecordPermissions, RecordVersion, UploadFile } from './data-source.mjs';
3
3
  import { type Scheduler } from './scheduler.mjs';
4
- import { type FileValue, type Values } from './values.mjs';
4
+ import { type FileValue, type RecordId, type Values } from './values.mjs';
5
5
  export interface MemoryDataSourceOptions {
6
6
  /** Records by model, then by id. */
7
7
  records?: Record<string, Record<string, Values>>;
@@ -44,7 +44,35 @@ export interface MemoryDataSourceOptions {
44
44
  attachments?: Record<string, FileValue[]>;
45
45
  /** The words after a copy's name, as a backend's copy adds them: " (copy)" unless said. */
46
46
  copySuffix?: string;
47
- /** Answer after this long, so a demo shows its loading states. */
47
+ /**
48
+ * Keep a version of each record, moved on by each save: a load gives it
49
+ * (with `loadedRecord`), and a save that carries an older one is refused
50
+ * with a `ConflictError`. `by` names whoever saves through this source;
51
+ * `changeElsewhere` changes a record as someone else would.
52
+ */
53
+ versions?: boolean | {
54
+ by?: string;
55
+ };
56
+ /**
57
+ * What the person may do with each record, by model: given with its load
58
+ * and its row in a list, and kept to as a backend would — a save, a
59
+ * delete, an archive or a copy it does not allow is refused, and hidden
60
+ * fields' values are left out.
61
+ */
62
+ can?: Record<string, (values: Values, id: RecordId) => RecordPermissions | undefined>;
63
+ /**
64
+ * A store as slow, or as unreliable, as a real one, for demos and tests of
65
+ * files stored as they are picked: `bytesPerSecond` paces each upload, its
66
+ * progress told every tenth of a second; `fails` says which tries fail —
67
+ * true for a failure partway that Retry may mend, words for the store
68
+ * refusing the file as it is (its kind, its size). Each file's tries are
69
+ * counted by its name and size, from 1.
70
+ */
71
+ storage?: {
72
+ bytesPerSecond?: number;
73
+ fails?: (file: UploadFile, attempt: number) => boolean | string | undefined;
74
+ };
75
+ /** Answer after this long, so a demo shows its loading states (an upload's progress, in four steps). */
48
76
  delayMs?: number;
49
77
  scheduler?: Scheduler;
50
78
  }
@@ -55,6 +83,15 @@ export interface MemoryDataSource extends Required<DataSource> {
55
83
  method: keyof DataSource;
56
84
  request: unknown;
57
85
  }[];
86
+ /**
87
+ * Change a stored record as someone else would, from another screen: its
88
+ * version moves on, named for them, so a page that opened it before is
89
+ * told of a conflict when it saves. Gives the new version.
90
+ */
91
+ changeElsewhere(model: string, id: RecordId, values: Values, who: {
92
+ by: string;
93
+ at?: string;
94
+ }): RecordVersion;
58
95
  }
59
96
  /**
60
97
  * A data source that keeps everything in memory. It implements the whole
@@ -1,7 +1,7 @@
1
1
  import type { Option, PropertyDefinition } from '../format/field';
2
- import type { DataSource, SubmitRequest } from './data-source';
2
+ import type { DataSource, SubmitRequest, RecordPermissions, RecordVersion, UploadFile } from './data-source';
3
3
  import { type Scheduler } from './scheduler';
4
- import { type FileValue, type Values } from './values';
4
+ import { type FileValue, type RecordId, type Values } from './values';
5
5
  export interface MemoryDataSourceOptions {
6
6
  /** Records by model, then by id. */
7
7
  records?: Record<string, Record<string, Values>>;
@@ -44,7 +44,35 @@ export interface MemoryDataSourceOptions {
44
44
  attachments?: Record<string, FileValue[]>;
45
45
  /** The words after a copy's name, as a backend's copy adds them: " (copy)" unless said. */
46
46
  copySuffix?: string;
47
- /** Answer after this long, so a demo shows its loading states. */
47
+ /**
48
+ * Keep a version of each record, moved on by each save: a load gives it
49
+ * (with `loadedRecord`), and a save that carries an older one is refused
50
+ * with a `ConflictError`. `by` names whoever saves through this source;
51
+ * `changeElsewhere` changes a record as someone else would.
52
+ */
53
+ versions?: boolean | {
54
+ by?: string;
55
+ };
56
+ /**
57
+ * What the person may do with each record, by model: given with its load
58
+ * and its row in a list, and kept to as a backend would — a save, a
59
+ * delete, an archive or a copy it does not allow is refused, and hidden
60
+ * fields' values are left out.
61
+ */
62
+ can?: Record<string, (values: Values, id: RecordId) => RecordPermissions | undefined>;
63
+ /**
64
+ * A store as slow, or as unreliable, as a real one, for demos and tests of
65
+ * files stored as they are picked: `bytesPerSecond` paces each upload, its
66
+ * progress told every tenth of a second; `fails` says which tries fail —
67
+ * true for a failure partway that Retry may mend, words for the store
68
+ * refusing the file as it is (its kind, its size). Each file's tries are
69
+ * counted by its name and size, from 1.
70
+ */
71
+ storage?: {
72
+ bytesPerSecond?: number;
73
+ fails?: (file: UploadFile, attempt: number) => boolean | string | undefined;
74
+ };
75
+ /** Answer after this long, so a demo shows its loading states (an upload's progress, in four steps). */
48
76
  delayMs?: number;
49
77
  scheduler?: Scheduler;
50
78
  }
@@ -55,6 +83,15 @@ export interface MemoryDataSource extends Required<DataSource> {
55
83
  method: keyof DataSource;
56
84
  request: unknown;
57
85
  }[];
86
+ /**
87
+ * Change a stored record as someone else would, from another screen: its
88
+ * version moves on, named for them, so a page that opened it before is
89
+ * told of a conflict when it saves. Gives the new version.
90
+ */
91
+ changeElsewhere(model: string, id: RecordId, values: Values, who: {
92
+ by: string;
93
+ at?: string;
94
+ }): RecordVersion;
58
95
  }
59
96
  /**
60
97
  * A data source that keeps everything in memory. It implements the whole
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createMemoryDataSource = createMemoryDataSource;
4
4
  const input_rules_1 = require("./input-rules");
5
+ const data_source_1 = require("./data-source");
5
6
  const filter_1 = require("./filter");
6
7
  const scheduler_1 = require("./scheduler");
7
8
  const values_1 = require("./values");
@@ -17,6 +18,43 @@ function createMemoryDataSource(options = {}) {
17
18
  /** Properties added in place, by the list and the definitions the app gave for the record they were added to. */
18
19
  const addedDefinitions = new Map();
19
20
  let lineIds = 1000;
21
+ let fileIds = 0;
22
+ /** Each file's tries at the store, by its name and size: what `storage.fails` is told. */
23
+ const tries = new Map();
24
+ /** Each record's version, by `model:id`, given when first asked. */
25
+ const versions = new Map();
26
+ let stamps = 0;
27
+ const versionOf = (model, id) => {
28
+ if (!options.versions)
29
+ return undefined;
30
+ const key = `${model}:${id}`;
31
+ if (!versions.has(key))
32
+ versions.set(key, { token: String(++stamps) });
33
+ return versions.get(key);
34
+ };
35
+ const moveOn = (model, id, by, at = new Date().toISOString()) => {
36
+ const version = { token: String(++stamps), ...(by ? { by } : {}), at };
37
+ versions.set(`${model}:${id}`, version);
38
+ return version;
39
+ };
40
+ const me = typeof options.versions === 'object' ? options.versions.by : undefined;
41
+ const permissions = (model, id) => {
42
+ const stored = table(model)[String(id)];
43
+ return stored ? options.can?.[model]?.((0, values_1.structuredCopy)(stored), id) : undefined;
44
+ };
45
+ /** A record as this person may read it: without the fields hidden from them. */
46
+ const readable = (values, can) => {
47
+ for (const name of can?.hiddenFields ?? [])
48
+ delete values[name];
49
+ return values;
50
+ };
51
+ /** Refused, as a backend refuses what the person may not do. */
52
+ const allowed = (can, what) => {
53
+ if (can?.[what] === false)
54
+ throw (0, data_source_1.saveRefused)({ kind: 'rule', message: can.reason ?? `You may not ${what} this record` });
55
+ };
56
+ /** A version and permissions, where this source keeps them. */
57
+ const told = (version, can) => ({ ...(version ? { version } : {}), ...(can ? { can } : {}) });
20
58
  const pause = () => (options.delayMs ? (0, scheduler_1.wait)(options.delayMs, options.scheduler) : Promise.resolve());
21
59
  const table = (model) => (records[model] ??= {});
22
60
  const labelOf = (model, id) => {
@@ -56,6 +94,8 @@ function createMemoryDataSource(options = {}) {
56
94
  const asId = (key) => (Number.isFinite(Number(key)) ? Number(key) : key);
57
95
  /** A record as a filter reads it: its values and its own `id`, which a field of its own named id comes before. */
58
96
  const withId = (key, values) => ({ id: asId(key), ...values });
97
+ /** The stored records a filter keeps. */
98
+ const matchingRows = (model, filter) => Object.entries(table(model)).filter(([key, values]) => (0, filter_1.matchesFilter)(withId(key, values), filter)).map(([, values]) => values);
59
99
  function applyLines(current, ops) {
60
100
  let lines = [...current];
61
101
  for (const op of ops) {
@@ -91,13 +131,22 @@ function createMemoryDataSource(options = {}) {
91
131
  records,
92
132
  responses,
93
133
  calls,
134
+ changeElsewhere(model, id, values, who) {
135
+ const stored = table(model)[String(id)];
136
+ if (!stored)
137
+ throw new Error(`No ${model} record with id ${id}`);
138
+ Object.assign(stored, (0, values_1.structuredCopy)(values));
139
+ return moveOn(model, id, who.by, who.at);
140
+ },
94
141
  async load(request) {
95
142
  calls.push({ method: 'load', request });
96
143
  await pause();
97
144
  const stored = table(request.model)[String(request.id)];
98
145
  if (!stored)
99
146
  throw new Error(`No ${request.model} record with id ${request.id}`);
100
- const values = (0, values_1.structuredCopy)(stored);
147
+ const can = permissions(request.model, request.id);
148
+ const version = versionOf(request.model, request.id);
149
+ const values = readable((0, values_1.structuredCopy)(stored), can);
101
150
  // Its links, with what their models show besides their names.
102
151
  if (options.shows) {
103
152
  for (const [name, def] of Object.entries(request.fields)) {
@@ -108,11 +157,24 @@ function createMemoryDataSource(options = {}) {
108
157
  values[name] = value.map((record) => shown(def.relation, record));
109
158
  }
110
159
  }
111
- return values;
160
+ // Bare values, as ever, from a source that keeps no versions and no permissions.
161
+ return version || can ? (0, data_source_1.loadedRecord)(values, told(version, can)) : values;
112
162
  },
113
163
  async save(request) {
114
164
  calls.push({ method: 'save', request });
115
165
  await pause();
166
+ if (request.id !== null && table(request.model)[String(request.id)]) {
167
+ const can = permissions(request.model, request.id);
168
+ allowed(can, 'edit');
169
+ const locked = Object.keys(request.changes.values).filter((name) => can?.readonlyFields?.includes(name) || can?.hiddenFields?.includes(name));
170
+ if (locked.length)
171
+ throw (0, data_source_1.saveRefused)({ kind: 'fields', message: 'You may not change these fields', fields: Object.fromEntries(locked.map((name) => [name, 'You may not change this field'])) });
172
+ const now = versionOf(request.model, request.id);
173
+ // A save that says which version it was opened at is checked; one that says none is not.
174
+ if (now && request.version && request.version.token !== now.token) {
175
+ throw new data_source_1.ConflictError({ version: now, theirs: readable((0, values_1.structuredCopy)(table(request.model)[String(request.id)]), can) });
176
+ }
177
+ }
116
178
  const id = request.id ?? nextId(request.model);
117
179
  const stored = { ...(table(request.model)[String(id)] ?? {}), ...(0, values_1.structuredCopy)(request.changes.values) };
118
180
  for (const [name, ops] of Object.entries(request.changes.lines)) {
@@ -122,7 +184,9 @@ function createMemoryDataSource(options = {}) {
122
184
  stored[name] = applyLinks(stored[name] ?? [], ops, relationOf(request.fields, name));
123
185
  }
124
186
  table(request.model)[String(id)] = stored;
125
- return { id, values: (0, values_1.structuredCopy)(stored) };
187
+ const version = options.versions ? moveOn(request.model, id, me) : undefined;
188
+ const can = permissions(request.model, id);
189
+ return { id, values: readable((0, values_1.structuredCopy)(stored), can), ...told(version, can) };
126
190
  },
127
191
  async onchange(request) {
128
192
  calls.push({ method: 'onchange', request });
@@ -168,28 +232,64 @@ function createMemoryDataSource(options = {}) {
168
232
  });
169
233
  return {
170
234
  total: matching.length,
171
- records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => ({
172
- id,
173
- values: Object.fromEntries(request.fields.map((field) => [field, (0, values_1.structuredCopy)(values[field] ?? null)])),
174
- })),
235
+ records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => {
236
+ const can = permissions(request.model, id);
237
+ const shownValues = readable(Object.fromEntries(request.fields.map((field) => [field, (0, values_1.structuredCopy)(values[field] ?? null)])), can);
238
+ return { id, values: shownValues, ...told(versionOf(request.model, id), can) };
239
+ }),
240
+ ...(request.allIds ? { allIds: matching.map(({ id }) => id) } : {}),
175
241
  };
176
242
  },
177
243
  async groups(request) {
178
244
  calls.push({ method: 'groups', request });
179
245
  await pause();
180
- const counted = new Map();
181
- for (const [id, values] of Object.entries(table(request.model))) {
182
- if (!(0, filter_1.matchesFilter)(withId(id, values), request.filter))
183
- continue;
184
- const raw = values[request.field] ?? null;
185
- const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? raw : null;
186
- const value = (link ? link.id : raw);
187
- const key = JSON.stringify(value);
188
- const group = counted.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0 };
189
- group.count++;
190
- counted.set(key, group);
246
+ return groupRows(matchingRows(request.model, request.filter), request.field).map(({ rows: _rows, ...group }) => group);
247
+ },
248
+ async totals(request) {
249
+ calls.push({ method: 'totals', request });
250
+ await pause();
251
+ const rows = matchingRows(request.model, request.filter);
252
+ const result = { count: rows.length, totals: totalsOver(rows, request.totals) };
253
+ if (request.groupBy)
254
+ result.groups = groupRows(rows, request.groupBy).map(({ rows: under, ...group }) => ({ ...group, totals: totalsOver(under, request.totals) }));
255
+ return result;
256
+ },
257
+ async upload(file, request) {
258
+ calls.push({ method: 'upload', request: { ...request, file } });
259
+ const stopped = () => Object.assign(new Error('The upload was stopped'), { name: 'AbortError' });
260
+ // A store slow or failing as `storage` says: a refusal at once, a failure partway, the bytes paced as they go.
261
+ const tried = `${file.name}:${file.size}`;
262
+ tries.set(tried, (tries.get(tried) ?? 0) + 1);
263
+ const failure = options.storage?.fails?.(file, tries.get(tried));
264
+ if (typeof failure === 'string')
265
+ throw (0, data_source_1.saveRefused)({ kind: 'rule', message: failure });
266
+ const pace = options.storage?.bytesPerSecond;
267
+ if (pace) {
268
+ const each = Math.max(1, Math.round(pace / 10));
269
+ for (let sent = 0; sent < file.size;) {
270
+ await (0, scheduler_1.wait)(100, options.scheduler);
271
+ if (request.signal?.aborted)
272
+ throw stopped();
273
+ sent = Math.min(file.size, sent + each);
274
+ if (failure && sent >= file.size / 2)
275
+ throw new Error('The store stopped answering: the upload failed partway');
276
+ request.onProgress?.(sent, file.size);
277
+ }
191
278
  }
192
- return [...counted.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);
279
+ // In four steps when it is slowed for a demo, so its progress shows.
280
+ const steps = options.delayMs && !pace ? 4 : 1;
281
+ for (let step = 1; step <= steps && !pace; step++) {
282
+ if (options.delayMs)
283
+ await (0, scheduler_1.wait)(options.delayMs / steps, options.scheduler);
284
+ if (request.signal?.aborted)
285
+ throw stopped();
286
+ request.onProgress?.(Math.round((file.size * step) / steps), file.size);
287
+ }
288
+ if (failure)
289
+ throw new Error('The store stopped answering: the upload failed');
290
+ // Kept as a data address, so a preview needs nothing else.
291
+ const type = file.type || 'application/octet-stream';
292
+ return { fileId: ++fileIds, url: `data:${type};base64,${base64(new Uint8Array(await file.arrayBuffer()))}`, name: file.name, size: file.size, type };
193
293
  },
194
294
  async create(request) {
195
295
  calls.push({ method: 'create', request });
@@ -211,6 +311,7 @@ function createMemoryDataSource(options = {}) {
211
311
  const stored = table(request.model)[String(request.id)];
212
312
  if (!stored)
213
313
  throw new Error(`No ${request.model} record with id ${request.id}`);
314
+ allowed(permissions(request.model, request.id), 'archive');
214
315
  stored['active'] = !request.archive;
215
316
  },
216
317
  async copy(request) {
@@ -219,6 +320,7 @@ function createMemoryDataSource(options = {}) {
219
320
  const stored = table(request.model)[String(request.id)];
220
321
  if (!stored)
221
322
  throw new Error(`No ${request.model} record with id ${request.id}`);
323
+ allowed(permissions(request.model, request.id), 'duplicate');
222
324
  const id = nextId(request.model);
223
325
  const copy = (0, values_1.structuredCopy)(stored);
224
326
  const name = options.labelField?.[request.model] ?? 'name';
@@ -231,13 +333,15 @@ function createMemoryDataSource(options = {}) {
231
333
  }
232
334
  }
233
335
  table(request.model)[String(id)] = copy;
234
- return { id, values: (0, values_1.structuredCopy)(copy) };
336
+ const can = permissions(request.model, id);
337
+ return { id, values: readable((0, values_1.structuredCopy)(copy), can), ...told(versionOf(request.model, id), can) };
235
338
  },
236
339
  async delete(request) {
237
340
  calls.push({ method: 'delete', request });
238
341
  await pause();
239
342
  if (!table(request.model)[String(request.id)])
240
343
  throw new Error(`No ${request.model} record with id ${request.id}`);
344
+ allowed(permissions(request.model, request.id), 'delete');
241
345
  delete table(request.model)[String(request.id)];
242
346
  },
243
347
  async attachments(request) {
@@ -291,4 +395,44 @@ function compareValues(a, b) {
291
395
  return { result: x - y, empty: false };
292
396
  return { result: String(x).localeCompare(String(y)), empty: false };
293
397
  }
398
+ /** Records under each value of a field: a link's by its record, nothing as its own group, last; the rest by their labels. */
399
+ function groupRows(rows, field) {
400
+ const grouped = new Map();
401
+ for (const values of rows) {
402
+ const raw = values[field] ?? null;
403
+ const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? raw : null;
404
+ const value = (link ? link.id : raw);
405
+ const key = JSON.stringify(value);
406
+ const group = grouped.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0, rows: [] };
407
+ group.count++;
408
+ group.rows.push(values);
409
+ grouped.set(key, group);
410
+ }
411
+ return [...grouped.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);
412
+ }
413
+ /** Each field's totals over these records: of its numbers, and a count of those holding any value. */
414
+ function totalsOver(rows, asked) {
415
+ const totals = {};
416
+ for (const [field, kinds] of Object.entries(asked)) {
417
+ const numbers = rows.map((values) => values[field]).filter((v) => typeof v === 'number' && Number.isFinite(v));
418
+ const sum = numbers.reduce((a, b) => a + b, 0);
419
+ const of = {
420
+ sum,
421
+ avg: numbers.length ? sum / numbers.length : null,
422
+ min: numbers.length ? numbers.reduce((a, b) => Math.min(a, b)) : null,
423
+ max: numbers.length ? numbers.reduce((a, b) => Math.max(a, b)) : null,
424
+ count: rows.filter((values) => !blankValue(values[field])).length,
425
+ };
426
+ totals[field] = Object.fromEntries(kinds.map((kind) => [kind, of[kind]]));
427
+ }
428
+ return totals;
429
+ }
430
+ const blankValue = (v) => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0);
431
+ /** Bytes as base64, by the host's `btoa` (a browser's, or Node's). */
432
+ function base64(bytes) {
433
+ let text = '';
434
+ for (let at = 0; at < bytes.length; at += 0x8000)
435
+ text += String.fromCharCode(...bytes.subarray(at, at + 0x8000));
436
+ return globalThis.btoa(text);
437
+ }
294
438
  //# sourceMappingURL=memory-data-source.js.map