@rebasepro/app 0.25.0 → 0.26.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 (38) hide show
  1. package/README.md +1 -1
  2. package/dist/RlsSimulatorPanel-DOfmVgM3.js +403 -0
  3. package/dist/RlsSimulatorPanel-DOfmVgM3.js.map +1 -0
  4. package/dist/collections/form-layout.d.ts +30 -27
  5. package/dist/components/LanguageToggle.d.ts +9 -0
  6. package/dist/components/LoginView/index.d.ts +7 -0
  7. package/dist/components/index.d.ts +1 -0
  8. package/dist/components/studio/RlsSimulatorBar.d.ts +39 -0
  9. package/dist/components/studio/RlsSimulatorPanel.d.ts +29 -0
  10. package/dist/contexts/RlsSimulationContext.d.ts +47 -0
  11. package/dist/contexts/index.d.ts +1 -0
  12. package/dist/core/effective_role_state.d.ts +9 -0
  13. package/dist/{de-BMgOgwue.js → de-3yzzpuZj.js} +175 -1
  14. package/dist/de-3yzzpuZj.js.map +1 -0
  15. package/dist/debug.js +96 -46
  16. package/dist/{es-DSOOSgPW.js → es-mnyTaRkK.js} +175 -1
  17. package/dist/es-mnyTaRkK.js.map +1 -0
  18. package/dist/{fr-CnXidmZf.js → fr-nJHADzlI.js} +175 -1
  19. package/dist/fr-nJHADzlI.js.map +1 -0
  20. package/dist/{hi-lTvNsFMr.js → hi-B9_iunnL.js} +175 -1
  21. package/dist/hi-B9_iunnL.js.map +1 -0
  22. package/dist/hooks/useBuildEffectiveRoleController.d.ts +9 -3
  23. package/dist/hooks/usePermissions.d.ts +4 -0
  24. package/dist/hooks/useUnsavedChangesDialog.d.ts +7 -1
  25. package/dist/i18n/RebaseI18nProvider.d.ts +11 -0
  26. package/dist/index.es.js +2814 -2555
  27. package/dist/index.es.js.map +1 -1
  28. package/dist/{it-BoT_vBlx.js → it-DoEtz-OK.js} +175 -1
  29. package/dist/it-DoEtz-OK.js.map +1 -0
  30. package/dist/{pt-D9mSchbY.js → pt-DT26AmBU.js} +175 -1
  31. package/dist/pt-DT26AmBU.js.map +1 -0
  32. package/package.json +7 -7
  33. package/dist/de-BMgOgwue.js.map +0 -1
  34. package/dist/es-DSOOSgPW.js.map +0 -1
  35. package/dist/fr-CnXidmZf.js.map +0 -1
  36. package/dist/hi-lTvNsFMr.js.map +0 -1
  37. package/dist/it-BoT_vBlx.js.map +0 -1
  38. package/dist/pt-D9mSchbY.js.map +0 -1
package/dist/debug.js CHANGED
@@ -2944,12 +2944,20 @@ var PRINCIPLES = [
2944
2944
  },
2945
2945
  {
2946
2946
  title: "Dense controls, generous containers.",
2947
- body: "Fields are 32px with 14px text and a 13px label; buttons in a toolbar are 32px. The card around them keeps 16\u201320px of padding and the form grid keeps 20px between rows. Density lives inside the container; air lives between containers.",
2947
+ body: "Buttons in a toolbar are 32px; a record-form field is a filled 64px box with its label inside and a 16px value. The card around them keeps 16\u201320px of padding and the form grid keeps 24px between rows. Density lives inside the container; air lives between containers.",
2948
2948
  specimen: /* @__PURE__ */ jsxs15(Card7, { className: "p-4 w-64", children: [
2949
- /* @__PURE__ */ jsx15(Typography13, { variant: "caption", className: "block text-[13px] font-medium mb-1.5", children: "Product name" }),
2950
- /* @__PURE__ */ jsx15(TextField2, { size: "small", value: "Italian coffee maker", onChange: () => {
2951
- } }),
2952
- /* @__PURE__ */ jsx15(Typography13, { variant: "caption", color: "disabled", className: "block mt-1.5", children: "Shown on the storefront and in receipts." })
2949
+ /* @__PURE__ */ jsx15(
2950
+ TextField2,
2951
+ {
2952
+ size: "large",
2953
+ value: "Italian coffee maker",
2954
+ onChange: () => {
2955
+ },
2956
+ inputClassName: "text-base",
2957
+ label: "Product name"
2958
+ }
2959
+ ),
2960
+ /* @__PURE__ */ jsx15(Typography13, { variant: "caption", color: "disabled", className: "block mt-1.5 ml-3.5", children: "Shown on the storefront and in receipts." })
2953
2961
  ] })
2954
2962
  },
2955
2963
  {
@@ -3099,7 +3107,7 @@ var CONTROL_SIZES = [
3099
3107
  {
3100
3108
  size: "small",
3101
3109
  px: 32,
3102
- use: "record forms, toolbars, the reference density"
3110
+ use: "toolbars, dense chrome, the reference density"
3103
3111
  },
3104
3112
  {
3105
3113
  size: "medium",
@@ -3109,7 +3117,7 @@ var CONTROL_SIZES = [
3109
3117
  {
3110
3118
  size: "large",
3111
3119
  px: 48,
3112
- use: "the login screen and other one-field moments"
3120
+ use: "record forms (64px with the label inside), the login screen"
3113
3121
  }
3114
3122
  ];
3115
3123
  function ShapeSpaceSection() {
@@ -3165,19 +3173,30 @@ function ShapeSpaceSection() {
3165
3173
  /* @__PURE__ */ jsxs15("div", { children: [
3166
3174
  /* @__PURE__ */ jsx15(SpecimenLabel, { children: "a record-form field, assembled" }),
3167
3175
  /* @__PURE__ */ jsxs15("div", { className: "max-w-xs", children: [
3168
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5 font-medium leading-tight mb-1.5 text-[13px]", children: [
3169
- /* @__PURE__ */ jsx15("span", { className: "shrink-0 text-text-disabled dark:text-text-disabled-dark", children: /* @__PURE__ */ jsx15(FileTextIcon2, { size: 14 }) }),
3170
- /* @__PURE__ */ jsx15("span", { children: "SKU" }),
3171
- /* @__PURE__ */ jsx15("span", { className: "text-red-500 -ml-1", children: "*" })
3172
- ] }),
3173
- /* @__PURE__ */ jsx15(TextField2, { size: "small", value: "SKU-57032", onChange: () => {
3174
- } }),
3175
- /* @__PURE__ */ jsx15(Typography13, { variant: "caption", color: "disabled", className: "block mt-1.5 ml-0.5 leading-snug", children: "Stock keeping unit \u2014 unique product identifier" })
3176
+ /* @__PURE__ */ jsx15(
3177
+ TextField2,
3178
+ {
3179
+ size: "large",
3180
+ value: "SKU-57032",
3181
+ onChange: () => {
3182
+ },
3183
+ inputClassName: "text-base",
3184
+ label: /* @__PURE__ */ jsxs15("span", { className: "inline-flex items-center gap-2", children: [
3185
+ /* @__PURE__ */ jsx15(FileTextIcon2, { size: 20 }),
3186
+ /* @__PURE__ */ jsxs15("span", { children: [
3187
+ "SKU",
3188
+ /* @__PURE__ */ jsx15("span", { "aria-hidden": true, children: " *" })
3189
+ ] })
3190
+ ] })
3191
+ }
3192
+ ),
3193
+ /* @__PURE__ */ jsx15(Typography13, { variant: "caption", color: "disabled", className: "block mt-1.5 ml-3.5 leading-snug", children: "Stock keeping unit \u2014 unique product identifier" })
3176
3194
  ] }),
3177
3195
  /* @__PURE__ */ jsxs15(Typography13, { variant: "caption", color: "secondary", className: "block mt-3", children: [
3178
- "13px label in the primary ink with a muted 14px type icon, a 32px field with its hairline, an 11px note. Mirrors ",
3196
+ "A filled 64px box with no edge, the label and its type icon shrunk into the top edge, a 16px value, an 11px note indented to the value. Mirrors the panel\u2019s text field binding inside",
3197
+ " ",
3179
3198
  /* @__PURE__ */ jsx15("code", { className: "font-mono", children: "FieldBlock" }),
3180
- " in the panel."
3199
+ "."
3181
3200
  ] })
3182
3201
  ] })
3183
3202
  ] })
@@ -3541,7 +3560,7 @@ function MoreControlsSection() {
3541
3560
  maxRows: 6,
3542
3561
  value: notes,
3543
3562
  onChange: (e) => setNotes(e.target.value),
3544
- className: "w-full rounded-lg border border-hairline bg-surface-field px-3 py-2 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
3563
+ className: "w-full rounded-lg border border-transparent bg-surface-field px-3 py-2 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
3545
3564
  }
3546
3565
  )
3547
3566
  ] }),
@@ -3550,7 +3569,7 @@ function MoreControlsSection() {
3550
3569
  /* @__PURE__ */ jsx16(Label, { htmlFor: "ref-label-field", children: "Label, tied to its field" }),
3551
3570
  /* @__PURE__ */ jsx16(TextField3, { id: "ref-label-field", size: "small", placeholder: "Focus me through the label" }),
3552
3571
  /* @__PURE__ */ jsx16(Label, { border: true, children: "Label with a border" }),
3553
- /* @__PURE__ */ jsx16("div", { className: "relative h-10 border border-hairline rounded-lg", children: /* @__PURE__ */ jsx16(InputLabel, { shrink: true, children: "InputLabel (shrunk)" }) })
3572
+ /* @__PURE__ */ jsx16("div", { className: "relative h-10 bg-surface-field rounded-lg", children: /* @__PURE__ */ jsx16(InputLabel, { shrink: true, children: "InputLabel (shrunk)" }) })
3554
3573
  ] }),
3555
3574
  /* @__PURE__ */ jsxs16("div", { className: "col-span-12 sm:col-span-6 flex flex-col gap-3", children: [
3556
3575
  /* @__PURE__ */ jsx16(SpecimenLabel, { children: "RadioGroup \xB7 RadioGroupItem, one disabled" }),
@@ -3762,7 +3781,7 @@ function UIReferenceView() {
3762
3781
  /* @__PURE__ */ jsx17(PrinciplesSection, {}),
3763
3782
  /* @__PURE__ */ jsxs17(SectionBlock, { id: "surfaces", title: "Surfaces \u2014 theme.css, styles.ts", children: [
3764
3783
  /* @__PURE__ */ jsxs17(Typography15, { variant: "body2", color: "secondary", className: "mb-4", children: [
3765
- "A surface is named by role and the theme decides the value. Frame, sheet and card each sit one step lighter than the one below; above the card, raised and field are grey on both themes. A hairline marks an object (a card, a field, a floating panel), never a region (a tile, a row, a track), with one exception: the sheet edge against the frame, where the step alone is too small to read. See ",
3784
+ "A surface is named by role and the theme decides the value. Frame, sheet and card each sit one step lighter than the one below; above the card, raised and field are grey on both themes. A hairline marks an object (a card, a floating panel), never a region (a tile, a row, a track), with one exception: the sheet edge against the frame, where the step alone is too small to read. A field has no edge at all: it is a filled box, and its fill is the edge. See ",
3766
3785
  /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "packages/ui/DESIGN.md" }),
3767
3786
  "."
3768
3787
  ] }),
@@ -4126,7 +4145,7 @@ function UIReferenceView() {
4126
4145
  " for the message and a ",
4127
4146
  /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "Button" }),
4128
4147
  " with ",
4129
- /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "AddIcon" }),
4148
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "PlusIcon" }),
4130
4149
  " for the primary action. Sources: ",
4131
4150
  /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "CollectionPropertiesEditorForm" }),
4132
4151
  ", ",
@@ -4234,40 +4253,71 @@ function UIReferenceView() {
4234
4253
  ] }),
4235
4254
  /* @__PURE__ */ jsxs17(SectionBlock, { id: "inputs", title: "Form Inputs", children: [
4236
4255
  /* @__PURE__ */ jsxs17(Typography15, { variant: "body2", color: "secondary", className: "mb-4 max-w-[68ch]", children: [
4237
- "Two ways to label a field. A record form puts the label ",
4238
- /* @__PURE__ */ jsx17("em", { children: "above" }),
4239
- " the control (",
4240
- /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "FieldBlock" }),
4241
- ": 13px, primary ink, muted type icon) and the control is",
4256
+ "A field is a filled box with no edge. ",
4257
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "TextField" }),
4258
+ ",",
4242
4259
  " ",
4243
- /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "large" }),
4244
- ", 48px. A dialog or a standalone control carries its label",
4260
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "DateTimeField" }),
4261
+ " and a labelled switch carry their label",
4245
4262
  " ",
4246
4263
  /* @__PURE__ */ jsx17("em", { children: "inside" }),
4247
- " as the floating ",
4264
+ " \u2014 the floating ",
4248
4265
  /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "label" }),
4249
- " prop and is",
4266
+ " prop, shrunk into the top edge once there is a value; a standalone ",
4267
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "Select" }),
4268
+ " labels above. A record form sets every one-line field at ",
4269
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "large" }),
4270
+ " with the label inside, single selects included: 64px and a 16px value. A multi-select, whose chips wrap, keeps its label",
4250
4271
  " ",
4272
+ /* @__PURE__ */ jsx17("em", { children: "above" }),
4273
+ " (",
4274
+ /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "FieldBlock" }),
4275
+ ": 13px, primary ink, muted type icon) over a 48px box. A dialog or a standalone control is ",
4251
4276
  /* @__PURE__ */ jsx17("code", { className: "font-mono text-xs", children: "medium" }),
4252
- ", 40px. Every field has its hairline."
4277
+ ", 40px."
4253
4278
  ] }),
4254
4279
  /* @__PURE__ */ jsxs17("div", { className: "grid grid-cols-12 gap-4", children: [
4255
4280
  /* @__PURE__ */ jsxs17("div", { className: "col-span-12 sm:col-span-6", children: [
4256
- /* @__PURE__ */ jsx17(Typography15, { variant: "caption", color: "secondary", className: "block mb-2 font-mono", children: 'record form \xB7 size="large", label above' }),
4257
- /* @__PURE__ */ jsx17("div", { className: "flex flex-col gap-5 mb-6", children: [
4258
- ["Product name", "Italian coffee maker", "Shown on the storefront and in receipts.", false, false],
4259
- ["SKU", "SKU-57032", "Stock keeping unit \u2014 unique product identifier", true, false],
4260
- ["Brand", "Alessi", void 0, false, true]
4261
- ].map(([label, value, help, required, disabled]) => /* @__PURE__ */ jsxs17("div", { className: "flex flex-col min-w-0", children: [
4262
- /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1.5 font-medium leading-tight mb-1.5 text-[13px]", children: [
4263
- /* @__PURE__ */ jsx17("span", { className: "shrink-0 text-text-disabled dark:text-text-disabled-dark", children: /* @__PURE__ */ jsx17(FileTextIcon3, { size: 14 }) }),
4264
- /* @__PURE__ */ jsx17("span", { className: "truncate", children: label }),
4265
- required && /* @__PURE__ */ jsx17("span", { className: "text-red-500 dark:text-red-500 -ml-1", children: "*" })
4266
- ] }),
4267
- /* @__PURE__ */ jsx17(TextField4, { size: "large", value, disabled, onChange: () => {
4268
- } }),
4269
- help && /* @__PURE__ */ jsx17(Typography15, { variant: "caption", color: "disabled", className: "mt-1.5 ml-0.5 leading-snug", children: help })
4270
- ] }, label)) }),
4281
+ /* @__PURE__ */ jsx17(Typography15, { variant: "caption", color: "secondary", className: "block mb-2 font-mono", children: 'record form \xB7 size="large", label inside' }),
4282
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-6 mb-6", children: [
4283
+ [
4284
+ ["Product name", "Italian coffee maker", "Shown on the storefront and in receipts.", false, false],
4285
+ ["SKU", "SKU-57032", "Stock keeping unit \u2014 unique product identifier", true, false],
4286
+ ["Brand", "Alessi", void 0, false, true]
4287
+ ].map(([label, value, help, required, disabled]) => /* @__PURE__ */ jsxs17("div", { className: "flex flex-col min-w-0", children: [
4288
+ /* @__PURE__ */ jsx17(
4289
+ TextField4,
4290
+ {
4291
+ size: "large",
4292
+ value,
4293
+ disabled,
4294
+ onChange: () => {
4295
+ },
4296
+ inputClassName: "text-base",
4297
+ label: /* @__PURE__ */ jsxs17("span", { className: "inline-flex items-center gap-2", children: [
4298
+ /* @__PURE__ */ jsx17(FileTextIcon3, { size: 20 }),
4299
+ /* @__PURE__ */ jsxs17("span", { children: [
4300
+ label,
4301
+ required && /* @__PURE__ */ jsx17("span", { "aria-hidden": true, children: " *" })
4302
+ ] })
4303
+ ] })
4304
+ }
4305
+ ),
4306
+ help && /* @__PURE__ */ jsx17(Typography15, { variant: "caption", color: "disabled", className: "mt-1.5 ml-3.5 leading-snug", children: help })
4307
+ ] }, label)),
4308
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col min-w-0", children: [
4309
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1.5 font-medium leading-tight mb-1.5 text-[13px]", children: [
4310
+ /* @__PURE__ */ jsx17("span", { className: "shrink-0 text-text-disabled dark:text-text-disabled-dark", children: /* @__PURE__ */ jsx17(FileTextIcon3, { size: 14 }) }),
4311
+ /* @__PURE__ */ jsx17("span", { className: "truncate", children: "Available locales" })
4312
+ ] }),
4313
+ /* @__PURE__ */ jsxs17(MultiSelect, { size: "large", value: ["es", "fr", "it"], onValueChange: () => {
4314
+ }, "aria-label": "Available locales", children: [
4315
+ /* @__PURE__ */ jsx17(MultiSelectItem, { value: "es", children: "Spanish" }),
4316
+ /* @__PURE__ */ jsx17(MultiSelectItem, { value: "fr", children: "French" }),
4317
+ /* @__PURE__ */ jsx17(MultiSelectItem, { value: "it", children: "Italian" })
4318
+ ] })
4319
+ ] })
4320
+ ] }),
4271
4321
  /* @__PURE__ */ jsx17(Typography15, { variant: "caption", color: "secondary", className: "block mb-2 font-mono", children: 'TextField \xB7 floating label, size="medium" (dialogs)' }),
4272
4322
  /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-3", children: [
4273
4323
  /* @__PURE__ */ jsx17(TextField4, { size: "medium", label: "Default", placeholder: "Type something\u2026" }),
@@ -204,6 +204,30 @@ var es = {
204
204
  error_firestore_index: "Se requiere un índice de Firestore para esta consulta.",
205
205
  realtime_connection_lost_title: "Actualizaciones en directo en pausa",
206
206
  realtime_connection_lost_body: "Se ha perdido la conexión con el servidor, así que lo que ves puede estar desactualizado. Se actualizará en cuanto vuelva la conexión.",
207
+ rls_simulate_access: "Simular acceso",
208
+ rls_simulate_access_description: "Mira cada colección como la vería un rol, un usuario o una clave de servicio: se omiten las filas y los campos que su seguridad a nivel de fila oculta.",
209
+ rls_simulate_tab_role: "Rol",
210
+ rls_simulate_tab_user: "Usuario",
211
+ rls_simulate_tab_api_key: "Clave de API",
212
+ rls_simulate_user_id_optional: "Como id de usuario (opcional)",
213
+ rls_simulate_apply: "Simular",
214
+ rls_simulate_stop: "Dejar de simular",
215
+ rls_simulate_search_users: "Buscar usuarios",
216
+ rls_simulate_no_users: "No se encontraron usuarios.",
217
+ rls_simulate_no_api_keys: "No hay claves de servicio activas.",
218
+ rls_simulate_options_error: "No se pudo cargar qué se puede simular: {{message}}",
219
+ rls_simulate_users_error: "No se pudieron cargar los usuarios: {{message}}",
220
+ rls_simulation_viewing_as_role: "Viendo como el rol {{role}}",
221
+ rls_simulation_viewing_as_role_user: "Viendo como {{user}} con el rol {{role}}",
222
+ rls_simulation_viewing_as_user: "Viendo como el usuario {{user}}",
223
+ rls_simulation_viewing_as_api_key: "Viendo como la clave de API {{name}} ({{prefix}}…)",
224
+ rls_simulation_hidden_collections: "{{count}} colecciones ocultas",
225
+ rls_simulation_hidden_collections_one: "1 colección oculta",
226
+ rls_simulation_masked_columns: "{{count}} columnas enmascaradas por RLS",
227
+ rls_simulation_masked_columns_one: "1 columna enmascarada por RLS",
228
+ rls_simulation_counting: "Contando lo que esta identidad puede leer…",
229
+ rls_simulation_count_failed: "No se pudo contar lo que esta identidad puede leer: {{message}}",
230
+ rls_simulation_note: "Las vistas de datos muestran solo las filas y los campos que esta identidad puede leer. La edición está desactivada durante la simulación: detén la simulación para hacer cambios. Las actualizaciones en directo están en pausa.",
207
231
  create_index: "Crear índice",
208
232
  value_is_not_reference: "El valor no es una referencia.",
209
233
  click_to_edit: "Haz clic para editar",
@@ -965,6 +989,7 @@ var es = {
965
989
  studio_policy_help_step4_title: "4. Expresión WITH CHECK",
966
990
  studio_policy_help_step4_desc: "Una condición SQL que debe evaluarse como verdadera para que se guarden las filas nuevas o modificadas (INSERT, UPDATE).",
967
991
  studio_policy_help_step4_example: "Suele coincidir con la expresión USING cuando los usuarios solo pueden insertar o editar sus propios datos.",
992
+ studio_policy_help_example: "Ejemplo:",
968
993
  studio_policy_help_auth_vars_title: "Variables de autenticación de Rebase",
969
994
  studio_policy_help_auth_vars_desc: "Rebase ofrece funciones auxiliares nativas que puedes usar en tus expresiones:",
970
995
  studio_policy_help_auth_uid: "Devuelve el ID del usuario actual como texto. Ejemplo:",
@@ -1027,12 +1052,69 @@ var es = {
1027
1052
  studio_collections_editor_pick: "Selecciona una colección o crea una nueva para empezar a editar.",
1028
1053
  studio_collections_editor_read_only: "Las colecciones no se pueden editar en este servidor.",
1029
1054
  studio_collections_editor_unsaved: "Hay cambios sin guardar en esta colección.",
1055
+ schema_change_title_review: "Revisar el cambio de esquema",
1056
+ schema_change_title_applied: "Cambio de esquema aplicado",
1057
+ schema_change_title_committed: "Se hizo commit del cambio de esquema",
1058
+ schema_change_verdict_safe_title: "Listo para aplicar",
1059
+ schema_change_verdict_safe_body: "Cada cambio de aquí se puede hacer sobre la base de datos en ejecución.",
1060
+ schema_change_verdict_diverges_title: "Esto dejaría la base de datos desfasada",
1061
+ schema_change_verdict_diverges_body: "El cambio se puede escribir, pero la base de datos no acabará coincidiendo con él. Los detalles de abajo indican qué parte, y qué haría falta para poder aplicarlo.",
1062
+ schema_change_verdict_migration_title: "Esto necesita una migración",
1063
+ schema_change_verdict_migration_body: "Parte de esto no se puede hacer en una base de datos en ejecución: elimina o reescribe algo, y eso corresponde a una migración que alguien haya leído.",
1064
+ schema_change_commit_only_title: "Listo para hacer commit",
1065
+ schema_change_commit_only_body: "Ahora no se ejecuta nada en la base de datos. Cada cambio de abajo indica qué hace y cuándo surte efecto.",
1066
+ schema_change_commit_only_body_no_changes: "Esto cambia lo que declara tu proyecto. No se ejecuta nada en la base de datos: no hay ningún cambio de esquema que hacer.",
1067
+ schema_change_chip_safe: "seguro",
1068
+ schema_change_chip_diverges: "diverge",
1069
+ schema_change_chip_migration: "requiere migración",
1070
+ schema_change_follow_up_one: "Una cosa que hacer después",
1071
+ schema_change_follow_up: "Para hacer después",
1072
+ schema_change_withheld_one: "Una restricción no se aplicará",
1073
+ schema_change_withheld_many: "{{count}} restricciones no se aplicarán",
1074
+ schema_change_db_not_changed: "La base de datos no se modificó",
1075
+ schema_change_db_maybe_changed: "Es posible que la base de datos se haya modificado en parte",
1076
+ schema_change_statements_partial: "Se ejecutaron {{ran}} de {{total}} sentencias y luego una falló",
1077
+ schema_change_commit_holds: "El commit está en {{branch}} de todos modos, así que lo que no se ejecutó se aplicará en el próximo arranque.",
1078
+ schema_change_committed: "Commit hecho",
1079
+ schema_change_committed_on: "{{sha}} en {{branch}}",
1080
+ schema_change_plan_failed: "No se pudo planificar el cambio",
1081
+ schema_change_planning: "Calculando qué haría este cambio…",
1082
+ schema_change_source_only_changes: "Nada de esto cambia la forma de tus datos. Solo cambia el código fuente de la colección, y se hace commit de él.",
1083
+ schema_change_source_only_title: "Editar solo el código fuente: hacer commit de la colección y dejar la base de datos",
1084
+ schema_change_preview_only: "Puedes previsualizar este cambio, pero no aplicarlo",
1085
+ schema_change_statements: "Sentencias que se ejecutarán",
1086
+ schema_change_files: "Archivos de los que se hará commit",
1087
+ schema_change_message: "Mensaje del commit",
1088
+ schema_change_edit_source_only: "Editar solo el código fuente",
1089
+ schema_change_committing: "Haciendo commit…",
1090
+ schema_change_applying: "Aplicando…",
1091
+ schema_change_commit: "Hacer commit",
1092
+ schema_change_commit_and_apply: "Hacer commit y aplicar",
1093
+ studio_api_explorer_spec_refused_title: "Esta sesión no puede leer la especificación de la API",
1094
+ studio_api_explorer_spec_failed_title: "No se pudo cargar la especificación de la API",
1095
+ studio_api_explorer_spec_refused_body: "Se rechazó el acceso de la consola a la API de este proyecto. Normalmente significa que la sesión ha caducado (vuelve a iniciar sesión) o que el acceso de la consola se ha desactivado para este proyecto en Ajustes.",
1096
+ studio_api_explorer_spec_failed_body: "El proyecto respondió, pero no con una especificación que este explorador pueda leer. Su API no se ve afectada; solo esta página.",
1030
1097
  db_column_type: "Tipo de columna de base de datos",
1031
1098
  primary_key_unique_id: "Clave primaria / ID único",
1032
1099
  spread_children_as_columns: "Expandir hijos como columnas",
1033
1100
  mode: "Modo",
1034
1101
  timezone: "Zona horaria",
1035
1102
  target_collection: "Colección destino",
1103
+ column_type_default: "Predeterminado ({{type}})",
1104
+ column_type_uuid_forced: "uuid (impuesto por la clave primaria)",
1105
+ column_type_varchar: "varchar (longitud variable)",
1106
+ column_type_text: "text (ilimitado)",
1107
+ column_type_char: "char (longitud fija)",
1108
+ column_type_timestamp: "timestamp (con zona horaria)",
1109
+ column_type_caption_string: "Opcional: otro tipo de columna en la base de datos para este campo de texto.",
1110
+ column_type_caption_number: "Opcional: otro tipo de columna en la base de datos para este campo numérico.",
1111
+ column_type_caption_date: "Opcional: otro tipo de columna en la base de datos para este campo de fecha.",
1112
+ primary_key_manual: "Sí (entrada manual)",
1113
+ primary_key_generated_string: "Sí (UUID/cadena generada automáticamente)",
1114
+ primary_key_identity: "Sí (autoincremento/identity)",
1115
+ primary_key_increment: "Sí (incremento)",
1116
+ primary_key_strategy: "Sí ({{strategy}})",
1117
+ primary_key_caption: "Definir como clave primaria y configurar cómo se generan los ID.",
1036
1118
  storage_file_name: "Nombre del archivo",
1037
1119
  storage_path: "Ruta de almacenamiento",
1038
1120
  storage_max_size: "Tamaño máximo (en bytes)",
@@ -1048,6 +1130,14 @@ var es = {
1048
1130
  storage_include_bucket_url: "Incluir URL del bucket (s3://...) en el valor guardado",
1049
1131
  storage_save_url: "Guardar URL en lugar de la ruta de almacenamiento",
1050
1132
  datetime_automatic_value: "Valor automático",
1133
+ datetime_mode_date_time: "Fecha/hora",
1134
+ datetime_mode_date: "Fecha",
1135
+ datetime_auto_value_none: "Ninguno",
1136
+ datetime_auto_value_on_create: "Al crear",
1137
+ datetime_auto_value_on_update: "En cada actualización",
1138
+ datetime_auto_value_caption: "Actualiza este campo automáticamente al crear o actualizar el registro",
1139
+ datetime_timezone_local: "Zona horaria local",
1140
+ datetime_timezone_caption: "Zona horaria para mostrar e introducir fechas. Los valores siempre se guardan en UTC.",
1051
1141
  markdown_paste_behavior: "Comportamiento al pegar",
1052
1142
  entity_saved: "Guardado",
1053
1143
  more_actions: "Más acciones",
@@ -1323,6 +1413,61 @@ var es = {
1323
1413
  studio_rls_nothing_changed: "No ha cambiado nada, así que no se ha guardado nada.",
1324
1414
  studio_branches_unavailable_title: "Las ramas de base de datos no están disponibles",
1325
1415
  studio_branches_unavailable_body: "Las ramas necesitan un backend Postgres con una conexión de administrador. Define ADMIN_CONNECTION_STRING en el entorno del backend.",
1416
+ studio_branch_diff_tab_schema: "Esquema y políticas RLS",
1417
+ studio_branch_diff_tab_data: "Cambios de datos",
1418
+ studio_branch_diff_tab_details: "Detalles",
1419
+ studio_branch_diff_merge: "Fusionar en {{target}}",
1420
+ studio_branch_diff_failed: "No se ha podido comparar esta rama",
1421
+ studio_branch_diff_denied_title: "No puedes revisar esta rama",
1422
+ studio_branch_diff_denied_hint: "Revisar una rama requiere el permiso database:write: su diff muestra filas de ambas bases de datos, leídas fuera de la seguridad a nivel de fila.",
1423
+ studio_branch_diff_unreadable: "El servidor respondió con algo que no es un diff de rama.",
1424
+ studio_branch_diff_no_api: "Este panel no tiene una dirección de backend desde la que leer el diff de la rama.",
1425
+ studio_branch_diff_fork_unknown: "No se ha podido leer el momento en que se creó esta rama, así que cada fila distinta cuenta como cambio de la rama. Una fusión desharía también lo que {{target}} cambió desde entonces.",
1426
+ studio_branch_diff_schema_empty: "No hay cambios de esquema ni de políticas respecto a {{target}}.",
1427
+ studio_branch_diff_schema_not_merged: "Los cambios de esquema y de políticas se muestran para revisarlos. Una fusión nunca los aplica: pertenecen a tus colecciones y sus migraciones.",
1428
+ studio_branch_diff_object_table: "Tabla",
1429
+ studio_branch_diff_object_column: "Columna",
1430
+ studio_branch_diff_object_policy: "Política",
1431
+ studio_branch_diff_object_rls: "Seguridad a nivel de fila",
1432
+ studio_branch_diff_object_constraint: "Restricción",
1433
+ studio_branch_diff_object_index: "Índice",
1434
+ studio_branch_diff_object_trigger: "Trigger",
1435
+ studio_branch_diff_object_enum: "Tipo enum",
1436
+ studio_branch_diff_object_view: "Vista",
1437
+ studio_branch_diff_object_function: "Función",
1438
+ studio_branch_diff_change_added: "Añadido",
1439
+ studio_branch_diff_change_dropped: "Eliminado",
1440
+ studio_branch_diff_change_altered: "Modificado",
1441
+ studio_branch_diff_data_empty: "La rama no ha cambiado ninguna fila respecto a {{target}}.",
1442
+ studio_branch_diff_row_inserted: "Insertada",
1443
+ studio_branch_diff_row_updated: "Actualizada",
1444
+ studio_branch_diff_row_deleted: "Borrada",
1445
+ studio_branch_diff_row_conflict: "Conflicto",
1446
+ studio_branch_diff_conflicts: "{{count}} conflictos",
1447
+ studio_branch_diff_target_changes: "{{count}} filas cambiaron solo en {{target}} desde que se creó la rama. Una fusión las conserva.",
1448
+ studio_branch_diff_target_changes_referencing: "{{count}} filas cambiaron solo en {{target}} desde que se creó la rama. {{reached}} de ellas hacen referencia a filas que la rama eliminó: un merge las conserva salvo que la rama gane ese conflicto.",
1449
+ studio_branch_diff_referenced_by: "Filas que {{target}} escribió desde que se creó la rama siguen haciendo referencia a filas que la rama eliminó aquí: {{tables}}. Cada una cuenta como un conflicto.",
1450
+ studio_branch_diff_row_counts: "Filas: {{targetCount}} en {{target}}, {{branchCount}} en la rama.",
1451
+ studio_branch_diff_column_change: "Cambio",
1452
+ studio_branch_diff_column_key: "Clave primaria",
1453
+ studio_branch_diff_column_values: "Valores",
1454
+ studio_branch_diff_samples_shown: "Se muestran {{shown}} de {{total}} filas cambiadas.",
1455
+ studio_branch_diff_merge_title: "Fusionar {{branch}} en {{target}}",
1456
+ studio_branch_diff_merge_writes: "Esto escribe las filas de la rama en {{target}}: {{inserted}} insertadas, {{updated}} actualizadas y {{deleted}} borradas.",
1457
+ studio_branch_diff_merge_target_kept: "No se toca nada de lo que {{target}} cambió desde que se creó la rama.",
1458
+ studio_branch_diff_merge_target_kept_count: "Las {{count}} filas que {{target}} cambió desde que se creó la rama se conservan tal cual.",
1459
+ studio_branch_diff_merge_schema_skipped: "Los {{count}} cambios de esquema y de políticas no se fusionan. Aplícalos con tus migraciones (rebase db push).",
1460
+ studio_branch_diff_merge_conflicts: "{{count}} filas cambiaron en ambos lados. ¿Qué versión gana?",
1461
+ studio_branch_diff_merge_referenced_conflicts: "Algunas son filas que la rama eliminó y a las que aún hacen referencia {{count}} filas que {{target}} escribió desde entonces: {{tables}}. Conservar la de {{target}} conserva esas filas y las que las referencian.",
1462
+ studio_branch_diff_merge_referenced_reached: "Si gana la rama, se eliminan filas a las que aún hacen referencia {{count}} filas que {{target}} escribió desde entonces, y las claves foráneas alcanzan esas filas: {{tables}}. Las demás filas que {{target}} cambió se conservan tal cual.",
1463
+ studio_branch_diff_conflict_abort: "Ninguna: no fusionar nada",
1464
+ studio_branch_diff_conflict_branch: "La de la rama ({{branch}})",
1465
+ studio_branch_diff_conflict_target: "La de {{target}}: dejarla como está",
1466
+ studio_branch_diff_merge_blocked: "{{count}} tablas con filas cambiadas no se pueden fusionar:",
1467
+ studio_branch_diff_merge_skip_blocked: "Fusionar las demás tablas y dejar estas como están",
1468
+ studio_branch_diff_merge_atomic: "Todo se escribe en una sola transacción, o nada. Si alguna de las dos bases de datos cambió desde que se leyó este diff, no se escribe nada y el diff se recarga.",
1469
+ studio_branch_diff_merge_confirm: "Fusionar",
1470
+ studio_branch_diff_merged: "Se fusionaron {{count}} filas en {{target}}",
1326
1471
  studio_backups_not_configured_title: "Las copias de seguridad no están configuradas",
1327
1472
  studio_backups_not_configured_body: "Define BACKUP_DESTINATION como una ruta local o una URL s3:// o gs://, y crea una copia con `rebase db backup` o un cron programado.",
1328
1473
  studio_cron_empty_title: "No hay tareas cron registradas",
@@ -1414,6 +1559,34 @@ var es = {
1414
1559
  studio_storage_folder_exists: "La carpeta «{{name}}» ya existe",
1415
1560
  studio_storage_folder_created: "Carpeta «{{name}}» creada",
1416
1561
  studio_storage_create_folder_failed: "No se ha podido crear la carpeta",
1562
+ studio_branches_empty: "Todavía no hay ramas. Crea una para trabajar con una copia aislada de la base de datos.",
1563
+ studio_branches_create_action: "Crear rama",
1564
+ studio_branches_empty_detail: "Crea una rama para empezar",
1565
+ studio_branches_select_prompt: "Selecciona una rama para ver sus detalles",
1566
+ studio_branches_list_from: "desde {{parent}} · {{when}}",
1567
+ studio_branches_created_from: "Creada desde",
1568
+ studio_branches_branch_name: "Nombre de la rama",
1569
+ studio_branches_source_database: "Base de datos de origen",
1570
+ studio_branches_created: "Creada",
1571
+ studio_branches_size: "Tamaño",
1572
+ studio_branches_usage_title: "Cómo usar esta rama",
1573
+ studio_branches_usage_switch: "Apunta este checkout a ella. Todos los comandos posteriores la usan:",
1574
+ studio_branches_usage_off: "Vuelve a la base de datos principal con:",
1575
+ studio_branches_usage_isolated: "Los cambios hechos en esta rama no afectan a la base de datos principal.",
1576
+ studio_branches_connection_details: "Detalles de conexión",
1577
+ studio_branches_row_database: "Base de datos:",
1578
+ studio_branches_row_connect: "Conectar con:",
1579
+ studio_branches_row_branched_from: "Ramificada desde:",
1580
+ studio_branches_row_created_at: "Creada el:",
1581
+ studio_branches_create_title: "Crear nueva rama",
1582
+ studio_branches_create_body: "Crea una copia aislada de la base de datos. La rama será un clon completo de la base de datos de origen en este momento.",
1583
+ studio_branches_name_placeholder: "p. ej. feature-auth, staging, preview-pr-42",
1584
+ studio_branches_source_main: "Predeterminada (base de datos principal)",
1585
+ studio_branches_creating: "Creando…",
1586
+ studio_branches_delete_title: "Eliminar rama",
1587
+ studio_branches_delete_body: "¿Seguro que quieres eliminar permanentemente la rama «{{name}}»? Esta acción no se puede deshacer y se perderán todos los datos de esta rama.",
1588
+ studio_branches_created_snackbar: "Rama «{{name}}» creada correctamente",
1589
+ studio_branches_deleted_snackbar: "Rama «{{name}}» eliminada",
1417
1590
  insights_period_last_days: "Últimos {{count}} días",
1418
1591
  insights_period_last_days_one: "Último día",
1419
1592
  insights_previous_period_value: "{{count}} días anteriores: {{value}}",
@@ -1433,10 +1606,11 @@ var es = {
1433
1606
  copy_column_name: "Copiar nombre de la columna",
1434
1607
  generate_sql_templates: "Generar plantillas SQL",
1435
1608
  select_row: "Seleccionar {{id}}",
1609
+ relation_open_record: "Abrir {{label}}",
1436
1610
  select: "Seleccionar",
1437
1611
  open_view: "Abrir vista"
1438
1612
  };
1439
1613
  //#endregion
1440
1614
  export { es };
1441
1615
 
1442
- //# sourceMappingURL=es-DSOOSgPW.js.map
1616
+ //# sourceMappingURL=es-mnyTaRkK.js.map