rl-core-front 0.14.3 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/_services/api/schema.d.ts +286 -5
- package/src/components/app-shell.tsx +26 -1
- package/src/components/ui/create-button.tsx +64 -0
- package/src/components/ui/data-table.tsx +120 -3
- package/src/components/ui/dialog.tsx +27 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/input.tsx +73 -16
- package/src/features/queues/hooks/use-queue-jobs.ts +17 -4
- package/src/features/queues/queues-screen.tsx +56 -6
- package/src/features/queues/services/queues.service.ts +25 -6
- package/src/features/shortcuts/components/shortcut-card.tsx +97 -0
- package/src/features/shortcuts/shortcuts-screen.tsx +96 -0
- package/src/features/users/users-screen.tsx +12 -6
- package/src/hooks/use-shortcut.ts +267 -0
- package/src/i18n/messages/en.ts +40 -0
- package/src/i18n/messages/pt.ts +41 -0
- package/src/index.ts +10 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
|
|
5
|
+
/** Janela entre as duas batidas, em milissegundos. */
|
|
6
|
+
const DOUBLE_PRESS_WINDOW_MS = 500;
|
|
7
|
+
|
|
8
|
+
/** Onde a tecla é texto, e não comando. */
|
|
9
|
+
const TYPING_TAGS = new Set(["INPUT", "TEXTAREA", "SELECT"]);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* As teclas que abrem o formulário de cadastro, em toda tela que tiver um.
|
|
13
|
+
*
|
|
14
|
+
* Moram aqui, e não em cada tela, porque atalho que muda de tela para tela não
|
|
15
|
+
* é atalho — é armadilha.
|
|
16
|
+
*
|
|
17
|
+
* São **duas** porque teclado não é um só: `\` fica em lugares diferentes
|
|
18
|
+
* conforme o layout (e em alguns exige combinação), enquanto `1` está na mesma
|
|
19
|
+
* posição em qualquer um. Quem tem a barra usa a barra; quem não tem, usa o
|
|
20
|
+
* número. Nenhuma das duas compete com atalho de navegador.
|
|
21
|
+
*/
|
|
22
|
+
export const CREATE_SHORTCUT_KEYS = ["1", "\\"] as const;
|
|
23
|
+
|
|
24
|
+
/** Como o atalho se apresenta ao usuário. */
|
|
25
|
+
export const CREATE_SHORTCUT_LABEL = "11";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A combinação que amplia e restaura o modal aberto: `Alt` + `Enter`.
|
|
29
|
+
*
|
|
30
|
+
* Foram descartadas, nesta ordem e por estes motivos:
|
|
31
|
+
*
|
|
32
|
+
* - **`+` sozinho** e **`Shift + E`**: produzem caractere. Dentro de um modal,
|
|
33
|
+
* que é feito de campos, ou o atalho some ou ele dispara junto com a
|
|
34
|
+
* digitação — não há terceira saída.
|
|
35
|
+
* - **`Ctrl + +` e `Ctrl + Shift + +`**: são a mesma combinação física do zoom
|
|
36
|
+
* do navegador (`+` sai de `Shift` + `=` nos teclados brasileiro e
|
|
37
|
+
* americano). O navegador resolve o zoom antes de a página ver a tecla, então
|
|
38
|
+
* a página não tem como vencer.
|
|
39
|
+
*
|
|
40
|
+
* `Alt + Enter` não escreve nada, não é atalho de navegador, e é a convenção de
|
|
41
|
+
* maximizar que as pessoas já conhecem de outros programas. E `Enter` chega
|
|
42
|
+
* como `"Enter"` em qualquer layout — não depende de onde o teclado põe o
|
|
43
|
+
* símbolo.
|
|
44
|
+
*/
|
|
45
|
+
export const EXPAND_SHORTCUT_KEY = "Enter";
|
|
46
|
+
|
|
47
|
+
/** Como ele se apresenta ao usuário. */
|
|
48
|
+
export const EXPAND_SHORTCUT_LABEL = "Alt + Enter";
|
|
49
|
+
|
|
50
|
+
export interface ShortcutOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Exige duas batidas seguidas dentro de meio segundo.
|
|
53
|
+
*
|
|
54
|
+
* É o que permite usar uma tecla comum (`\`) sem modificador: sozinha ela é
|
|
55
|
+
* caractere, e duas vezes seguidas fora de um campo de texto não é coisa que
|
|
56
|
+
* alguém digite sem querer.
|
|
57
|
+
*/
|
|
58
|
+
double?: boolean;
|
|
59
|
+
/** Desliga o atalho sem tirar o hook da tela — útil enquanto a lista carrega. */
|
|
60
|
+
enabled?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Exige `Alt` (ou `Option`, no Mac) junto.
|
|
63
|
+
*
|
|
64
|
+
* Ausente, o `Alt` é recusado — é tecla de menu do sistema, e um atalho de
|
|
65
|
+
* uma tecla só não deve disparar com ela pressionada.
|
|
66
|
+
*/
|
|
67
|
+
alt?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Exige `Ctrl` (ou `Cmd`, no Mac) junto.
|
|
70
|
+
*
|
|
71
|
+
* Aceita os dois porque é a mesma tecla na cabeça de quem usa — obrigar
|
|
72
|
+
* `Ctrl` no Mac faria o atalho parecer quebrado ali. Ausente, os dois são
|
|
73
|
+
* recusados: sem isso, `Ctrl + tecla` dispararia o atalho de uma tecla só.
|
|
74
|
+
*/
|
|
75
|
+
ctrl?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* O que fazer com o `Shift`: `true` exige, `false` recusa, ausente ignora.
|
|
78
|
+
*
|
|
79
|
+
* **Ignorar é o padrão, e é o certo para a maioria dos casos**, porque o
|
|
80
|
+
* caractere já carrega a informação: `+` no teclado brasileiro sai com
|
|
81
|
+
* `Shift`, no numérico sem — e nos dois `event.key` é `"+"`. Recusar o
|
|
82
|
+
* `Shift` bloquearia metade dos teclados; exigi-lo bloquearia a outra metade.
|
|
83
|
+
*
|
|
84
|
+
* Declare `true` só quando o modificador for parte do atalho (`Shift + E`), e
|
|
85
|
+
* `false` quando a tecla sem ele significar outra coisa.
|
|
86
|
+
*/
|
|
87
|
+
shift?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Deixa o atalho valer também com o cursor dentro de um campo.
|
|
90
|
+
*
|
|
91
|
+
* O padrão é ceder a vez: numa listagem, `11` tem de poder ser digitado. Mas
|
|
92
|
+
* o atalho que pertence ao modal precisa valer em qualquer lugar dele, como
|
|
93
|
+
* o `Esc` — e o modal é feito de campos.
|
|
94
|
+
*
|
|
95
|
+
* **A tecla não é engolida nesse caso.** `Esc` não produz caractere; `+`
|
|
96
|
+
* produz, e bloqueá-lo impediria de escrever `+55` num telefone. Aqui o
|
|
97
|
+
* atalho dispara *e* o caractere é digitado.
|
|
98
|
+
*/
|
|
99
|
+
allowWhileTyping?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Deixa o atalho valer **com** um modal aberto.
|
|
102
|
+
*
|
|
103
|
+
* O padrão é o contrário: com um formulário na tela, a tecla é dele. Isto é
|
|
104
|
+
* para o atalho que pertence ao próprio modal — ele nasce e morre junto do
|
|
105
|
+
* modal, então quem monta o hook já é quem tem o direito à tecla.
|
|
106
|
+
*/
|
|
107
|
+
allowInDialog?: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Atalho de teclado de uma tela.
|
|
112
|
+
*
|
|
113
|
+
* Contraparte do `Esc` que o modal já entende: se uma tecla fecha, outra abre.
|
|
114
|
+
* A tela diz qual tecla e o que fazer; o resto — quando **não** disparar — é
|
|
115
|
+
* daqui:
|
|
116
|
+
*
|
|
117
|
+
* - **Campo de texto ganha**, salvo com `allowWhileTyping`. Digitar `11` num
|
|
118
|
+
* input é digitar `11`, não abrir modal. Vale para `contenteditable` também.
|
|
119
|
+
* - **Modal aberto bloqueia.** Com um formulário na tela, a tecla pertence a
|
|
120
|
+
* ele — senão o atalho abriria um segundo por cima do primeiro.
|
|
121
|
+
* - **Modificador não pedido cancela.** `Ctrl`/`Cmd`/`Alt` + a tecla costuma ser
|
|
122
|
+
* atalho do navegador ou do sistema; quem quiser um deles declara `ctrl`.
|
|
123
|
+
*
|
|
124
|
+
* ```tsx
|
|
125
|
+
* // Na listagem: duas batidas abrem o cadastro.
|
|
126
|
+
* useShortcut(CREATE_SHORTCUT_KEYS, openCreate, { double: true });
|
|
127
|
+
*
|
|
128
|
+
* // Dentro do modal: a tecla é dele, então `allowInDialog`.
|
|
129
|
+
* useShortcut(EXPAND_SHORTCUT_KEY, alternarTamanho, {
|
|
130
|
+
* alt: true,
|
|
131
|
+
* allowInDialog: true,
|
|
132
|
+
* allowWhileTyping: true,
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export function useShortcut(
|
|
137
|
+
keys: string | readonly string[],
|
|
138
|
+
handler: () => void,
|
|
139
|
+
options: ShortcutOptions = {},
|
|
140
|
+
): void {
|
|
141
|
+
const {
|
|
142
|
+
double = false,
|
|
143
|
+
enabled = true,
|
|
144
|
+
alt = false,
|
|
145
|
+
ctrl = false,
|
|
146
|
+
shift,
|
|
147
|
+
allowInDialog = false,
|
|
148
|
+
allowWhileTyping = false,
|
|
149
|
+
} = options;
|
|
150
|
+
|
|
151
|
+
// Serializado para o efeito não se reinscrever a cada render quando a tela
|
|
152
|
+
// passa um array literal — `["1", "\\"]` é um objeto novo toda vez.
|
|
153
|
+
const keyList = typeof keys === "string" ? [keys] : keys;
|
|
154
|
+
const keySignature = keyList.join("\u0000");
|
|
155
|
+
|
|
156
|
+
// O handler entra por ref para o efeito não se reinscrever a cada render —
|
|
157
|
+
// a tela costuma passar uma arrow nova toda vez. A escrita vai num efeito
|
|
158
|
+
// próprio: mexer em ref durante o render é o que o React proíbe.
|
|
159
|
+
const handlerRef = useRef(handler);
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
handlerRef.current = handler;
|
|
163
|
+
}, [handler]);
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Qual tecla bateu por último, e quando.
|
|
167
|
+
*
|
|
168
|
+
* A tecla entra junto do instante porque o duplo é da **mesma** tecla: sem
|
|
169
|
+
* isso, digitar `1` e logo `\` valeria como duas batidas e abriria o modal
|
|
170
|
+
* sem ninguém ter pedido.
|
|
171
|
+
*/
|
|
172
|
+
const lastPressRef = useRef<{ key: string; at: number }>({ key: "", at: 0 });
|
|
173
|
+
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (!enabled) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const accepted = keySignature.split("\u0000");
|
|
180
|
+
|
|
181
|
+
const onKeyDown = (event: KeyboardEvent): void => {
|
|
182
|
+
if (!accepted.includes(event.key)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (event.altKey !== alt) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (event.ctrlKey || event.metaKey ? !ctrl : ctrl) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (shift !== undefined && event.shiftKey !== shift) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const typing = isTyping(event.target);
|
|
195
|
+
|
|
196
|
+
if (typing && !allowWhileTyping) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!allowInDialog && hasOpenDialog()) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (double) {
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
const previous = lastPressRef.current;
|
|
206
|
+
lastPressRef.current = { key: event.key, at: now };
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
previous.key !== event.key ||
|
|
210
|
+
now - previous.at > DOUBLE_PRESS_WINDOW_MS
|
|
211
|
+
) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Zera para a terceira batida não valer como um segundo disparo.
|
|
215
|
+
lastPressRef.current = { key: "", at: 0 };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Só depois de decidir que dispara: impedir o padrão antes disso
|
|
219
|
+
// engoliria a tecla de quem só queria digitá-la.
|
|
220
|
+
//
|
|
221
|
+
// Com modificador não há esse risco — `Alt + Enter` não escreve nada —, e
|
|
222
|
+
// aí engolir é necessário: sem isso o `Enter` ainda enviaria o formulário
|
|
223
|
+
// junto com o ampliar. Sem modificador e dentro de um campo, a tecla é
|
|
224
|
+
// das duas coisas ao mesmo tempo, e não se impede nada.
|
|
225
|
+
if (!typing || alt || ctrl) {
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
}
|
|
228
|
+
handlerRef.current();
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// **Fase de captura, e não de bolha.** Atalho global precisa ver a tecla
|
|
232
|
+
// antes de quem está no caminho: um componente entre o campo e a `window`
|
|
233
|
+
// que chame `stopPropagation()` no `keydown` — coisa comum em combobox,
|
|
234
|
+
// editor e tabela — engoliria o atalho, e o sintoma seria "funciona numa
|
|
235
|
+
// tela e não funciona na outra", que é o pior tipo de bug para achar.
|
|
236
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
237
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
238
|
+
}, [
|
|
239
|
+
keySignature,
|
|
240
|
+
double,
|
|
241
|
+
enabled,
|
|
242
|
+
alt,
|
|
243
|
+
ctrl,
|
|
244
|
+
shift,
|
|
245
|
+
allowInDialog,
|
|
246
|
+
allowWhileTyping,
|
|
247
|
+
]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const isTyping = (target: EventTarget | null): boolean => {
|
|
251
|
+
if (!(target instanceof HTMLElement)) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return TYPING_TAGS.has(target.tagName) || target.isContentEditable;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Há um modal aberto?
|
|
260
|
+
*
|
|
261
|
+
* Pela marca que o Radix deixa no DOM, e não por um contexto próprio: o modal
|
|
262
|
+
* pode estar em qualquer lugar da árvore (ele vive num portal), e um contexto
|
|
263
|
+
* obrigaria toda tela a envolver o conteúdo num provider só para o atalho
|
|
264
|
+
* saber disso.
|
|
265
|
+
*/
|
|
266
|
+
const hasOpenDialog = (): boolean =>
|
|
267
|
+
document.querySelector('[role="dialog"][data-state="open"]') !== null;
|
package/src/i18n/messages/en.ts
CHANGED
|
@@ -12,6 +12,8 @@ export const en: Messages = {
|
|
|
12
12
|
logs: "Logs",
|
|
13
13
|
audit: "Audit",
|
|
14
14
|
queues: "Queues",
|
|
15
|
+
shortcuts: "Shortcuts",
|
|
16
|
+
settings: "Settings",
|
|
15
17
|
},
|
|
16
18
|
logs: {
|
|
17
19
|
outcomeSuccess: "Success",
|
|
@@ -109,6 +111,41 @@ export const en: Messages = {
|
|
|
109
111
|
stateCompleted: "Completed",
|
|
110
112
|
stateFailed: "Failed",
|
|
111
113
|
stateDelayed: "Delayed",
|
|
114
|
+
queue: "Queue",
|
|
115
|
+
queueJobs: "General",
|
|
116
|
+
queueExports: "Reports",
|
|
117
|
+
payload: "Payload",
|
|
118
|
+
},
|
|
119
|
+
shortcuts: {
|
|
120
|
+
title: "Keyboard shortcuts",
|
|
121
|
+
subtitle:
|
|
122
|
+
"What you can do without leaving the keyboard. Shortcuts work on any screen that has the matching action.",
|
|
123
|
+
or: "or",
|
|
124
|
+
twice: "twice",
|
|
125
|
+
create: {
|
|
126
|
+
name: "Open the create form",
|
|
127
|
+
where: "On any listing with a create button.",
|
|
128
|
+
caveat: "Does not fire inside a text field or while a dialog is open",
|
|
129
|
+
},
|
|
130
|
+
expand: {
|
|
131
|
+
name: "Expand the dialog",
|
|
132
|
+
where:
|
|
133
|
+
"With a dialog open, toggles between normal and expanded size. Works anywhere in the dialog, like Esc.",
|
|
134
|
+
caveat: "Works in any field, and does not submit the form",
|
|
135
|
+
note: "On a Mac, Alt is the Option key (⌥) — most keyboards print both labels on it.",
|
|
136
|
+
},
|
|
137
|
+
submit: {
|
|
138
|
+
name: "Submit the form",
|
|
139
|
+
where: "With a create dialog open, saves without clicking.",
|
|
140
|
+
caveat: "Inside a long text field, Enter adds a line break",
|
|
141
|
+
},
|
|
142
|
+
close: {
|
|
143
|
+
name: "Close the dialog",
|
|
144
|
+
where: "Closes the open dialog, same as the close button.",
|
|
145
|
+
caveat: "A changed form asks for confirmation before leaving",
|
|
146
|
+
},
|
|
147
|
+
footer:
|
|
148
|
+
"Two keys open the create form because keyboards differ: the backslash moves around depending on the layout, while the number is always in the same place.",
|
|
112
149
|
},
|
|
113
150
|
table: {
|
|
114
151
|
columns: "Columns",
|
|
@@ -122,6 +159,8 @@ export const en: Messages = {
|
|
|
122
159
|
nextPage: "Next page",
|
|
123
160
|
empty: "No records",
|
|
124
161
|
emptyFiltered: "No records match this filter",
|
|
162
|
+
reorder: "Drag to reorder",
|
|
163
|
+
reorderSorted: "Clear the column sorting to drag rows",
|
|
125
164
|
},
|
|
126
165
|
filters: {
|
|
127
166
|
button: "Filters",
|
|
@@ -209,6 +248,7 @@ export const en: Messages = {
|
|
|
209
248
|
clear: "Clear",
|
|
210
249
|
no: "No",
|
|
211
250
|
actions: "Actions",
|
|
251
|
+
shortcutHint: "Shortcut: {keys}",
|
|
212
252
|
loading: "Loading...",
|
|
213
253
|
description: "Description",
|
|
214
254
|
language: "Language",
|
package/src/i18n/messages/pt.ts
CHANGED
|
@@ -10,6 +10,8 @@ export const pt = {
|
|
|
10
10
|
logs: "Logs",
|
|
11
11
|
audit: "Auditoria",
|
|
12
12
|
queues: "Filas",
|
|
13
|
+
shortcuts: "Atalhos",
|
|
14
|
+
settings: "Configurações",
|
|
13
15
|
},
|
|
14
16
|
logs: {
|
|
15
17
|
outcomeSuccess: "Sucesso",
|
|
@@ -111,6 +113,41 @@ export const pt = {
|
|
|
111
113
|
stateCompleted: "Concluídos",
|
|
112
114
|
stateFailed: "Falhos",
|
|
113
115
|
stateDelayed: "Agendados",
|
|
116
|
+
queue: "Fila",
|
|
117
|
+
queueJobs: "Geral",
|
|
118
|
+
queueExports: "Relatórios",
|
|
119
|
+
payload: "Conteúdo",
|
|
120
|
+
},
|
|
121
|
+
shortcuts: {
|
|
122
|
+
title: "Atalhos de teclado",
|
|
123
|
+
subtitle:
|
|
124
|
+
"O que dá para fazer sem tirar a mão do teclado. Os atalhos valem em qualquer tela que tenha a ação correspondente.",
|
|
125
|
+
or: "ou",
|
|
126
|
+
twice: "duas vezes",
|
|
127
|
+
create: {
|
|
128
|
+
name: "Abrir cadastro",
|
|
129
|
+
where: "Em qualquer listagem que tenha o botão de cadastrar.",
|
|
130
|
+
caveat: "Não dispara dentro de um campo de texto nem com um modal aberto",
|
|
131
|
+
},
|
|
132
|
+
expand: {
|
|
133
|
+
name: "Ampliar o modal",
|
|
134
|
+
where:
|
|
135
|
+
"Com um modal aberto, alterna entre o tamanho normal e o ampliado. Vale em qualquer lugar do modal, como o Esc.",
|
|
136
|
+
caveat: "Funciona em qualquer campo, e não envia o formulário junto",
|
|
137
|
+
note: "No Mac, o Alt é a tecla Option (⌥) — em boa parte dos teclados ela vem escrita das duas formas.",
|
|
138
|
+
},
|
|
139
|
+
submit: {
|
|
140
|
+
name: "Enviar o formulário",
|
|
141
|
+
where: "Com um modal de cadastro aberto, salva sem precisar clicar.",
|
|
142
|
+
caveat: "Dentro de um campo de texto longo, o Enter quebra a linha",
|
|
143
|
+
},
|
|
144
|
+
close: {
|
|
145
|
+
name: "Fechar o modal",
|
|
146
|
+
where: "Fecha o modal aberto, como o botão de fechar.",
|
|
147
|
+
caveat: "Um formulário alterado pede confirmação antes de sair",
|
|
148
|
+
},
|
|
149
|
+
footer:
|
|
150
|
+
"Duas teclas para abrir o cadastro porque o teclado não é um só: a barra invertida muda de lugar conforme o layout, e o número está sempre na mesma posição. Já o atalho de ampliar leva Alt porque precisa valer dentro dos campos — e uma tecla que escreve não pode servir de comando ali.",
|
|
114
151
|
},
|
|
115
152
|
table: {
|
|
116
153
|
columns: "Colunas",
|
|
@@ -124,6 +161,9 @@ export const pt = {
|
|
|
124
161
|
nextPage: "Próxima página",
|
|
125
162
|
empty: "Nenhum registro",
|
|
126
163
|
emptyFiltered: "Nenhum registro para este filtro",
|
|
164
|
+
reorder: "Arraste para reordenar",
|
|
165
|
+
reorderSorted:
|
|
166
|
+
"Limpe a ordenação por coluna para arrastar as linhas",
|
|
127
167
|
},
|
|
128
168
|
filters: {
|
|
129
169
|
button: "Filtros",
|
|
@@ -211,6 +251,7 @@ export const pt = {
|
|
|
211
251
|
clear: "Limpar",
|
|
212
252
|
no: "Não",
|
|
213
253
|
actions: "Ações",
|
|
254
|
+
shortcutHint: "Atalho: {keys}",
|
|
214
255
|
loading: "Carregando...",
|
|
215
256
|
description: "Descrição",
|
|
216
257
|
language: "Idioma",
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ export {
|
|
|
33
33
|
export { RbacScreen } from "#core/features/rbac/rbac-screen";
|
|
34
34
|
export { ForgotPasswordScreen } from "#core/features/recovery/forgot-password-screen";
|
|
35
35
|
export { ResetPasswordScreen } from "#core/features/recovery/reset-password-screen";
|
|
36
|
+
export { ShortcutsScreen } from "#core/features/shortcuts/shortcuts-screen";
|
|
36
37
|
export { UsersScreen } from "#core/features/users/users-screen";
|
|
37
38
|
|
|
38
39
|
// ---------------------------------------------------------------------------
|
|
@@ -70,6 +71,7 @@ export {
|
|
|
70
71
|
// ---------------------------------------------------------------------------
|
|
71
72
|
// Hooks de listagem, requisição e filtro
|
|
72
73
|
// ---------------------------------------------------------------------------
|
|
74
|
+
export type { CreateButtonProps } from "#core/components/ui/create-button";
|
|
73
75
|
export type { UseColumnVisibilityResult } from "#core/hooks/use-column-visibility";
|
|
74
76
|
export { useColumnVisibility } from "#core/hooks/use-column-visibility";
|
|
75
77
|
export type {
|
|
@@ -97,6 +99,14 @@ export { useLatestRequest } from "#core/hooks/use-latest-request";
|
|
|
97
99
|
export type { UseListQueryResult } from "#core/hooks/use-list-query";
|
|
98
100
|
export { useListQuery } from "#core/hooks/use-list-query";
|
|
99
101
|
export type { RunOptions, UseRequestResult } from "#core/hooks/use-request";
|
|
102
|
+
export type { ShortcutOptions } from "#core/hooks/use-shortcut";
|
|
103
|
+
export {
|
|
104
|
+
CREATE_SHORTCUT_KEYS,
|
|
105
|
+
CREATE_SHORTCUT_LABEL,
|
|
106
|
+
EXPAND_SHORTCUT_KEY,
|
|
107
|
+
EXPAND_SHORTCUT_LABEL,
|
|
108
|
+
useShortcut,
|
|
109
|
+
} from "#core/hooks/use-shortcut";
|
|
100
110
|
// RequestOperation é enum (valor, não só tipo): sem ele o projeto não consegue
|
|
101
111
|
// pedir o toast padrão de criado/alterado/removido que o core já traduz.
|
|
102
112
|
export { RequestOperation, useRequest } from "#core/hooks/use-request";
|