forlogic-core 1.16.11 → 1.17.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/.note/memory/features/crud-defaults-batteries-included.md +14 -0
- package/.note/memory/patterns/alias-url-resolution.md +39 -0
- package/.note/memory/patterns/doc-sync-rule.md +4 -1
- package/.note/memory/patterns/dynamic-supabase-config.md +4 -0
- package/.note/memory/patterns/environment-detection-logic.md +35 -0
- package/dist/auth/components/AliasRouteGuard.d.ts +25 -0
- package/dist/auth/services/AuthService.d.ts +1 -1
- package/dist/auth/services/TokenManager.d.ts +6 -0
- package/dist/config/index.d.ts +8 -0
- package/dist/crud/components/ColumnSettingsPopover.d.ts +2 -1
- package/dist/crud/components/CrudTable.d.ts +3 -1
- package/dist/crud/hooks/useColumnManager.d.ts +2 -0
- package/dist/hooks/useAliasFromUrl.d.ts +33 -0
- package/dist/hooks/useSidebarResize.d.ts +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/leadership/components/LeadershipPage.d.ts +12 -1
- package/dist/leadership/index.d.ts +0 -1
- package/dist/leadership/types.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/linkHelpers.d.ts +5 -0
- package/package.json +2 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Memory: features/crud-defaults-batteries-included
|
|
2
|
+
|
|
3
|
+
Todos os CRUDs (CrudTable, createCrudPage) agora incluem por padrão:
|
|
4
|
+
- **Column resize** (`enableColumnResize=true`) — já era default
|
|
5
|
+
- **Column manager** (`enableColumnManager=true`) — botão ⋮ no header da coluna "Ações"
|
|
6
|
+
- **Sort** — já era suportado via `sortable` nas colunas
|
|
7
|
+
- **Busca** — por padrão usa a busca global do header (não a action bar). Para busca na action bar, usar `showSearch=true`
|
|
8
|
+
- **Storage keys** — `createCrudPage` gera automaticamente `columnManagerStorageKey` e `resizeStorageKey` a partir do `entityName`
|
|
9
|
+
|
|
10
|
+
**NÃO vem por padrão:**
|
|
11
|
+
- **Agrupamento** (`enableGrouping=false`) — precisa ser habilitado explicitamente com `enableGrouping={true}`
|
|
12
|
+
- **Busca na action bar** (`showSearch=false`) — padrão é busca no header
|
|
13
|
+
|
|
14
|
+
**Paginação:** padrão de 25 itens por página.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Alias via URL — Resolução de Unidade por Rota
|
|
2
|
+
|
|
3
|
+
## Padrão
|
|
4
|
+
|
|
5
|
+
O alias da unidade ativa deve **sempre** estar presente na URL como primeiro segmento de rota (`/:alias/...`). O `AliasRouteGuard` garante sincronização bidirecional entre URL e sessão.
|
|
6
|
+
|
|
7
|
+
## Componentes
|
|
8
|
+
|
|
9
|
+
### `useAliasFromUrl(options?)`
|
|
10
|
+
Hook que extrai o alias do param de rota e valida contra `companies` do `useAuth()`.
|
|
11
|
+
|
|
12
|
+
Retorna: `{ urlAlias, isAliasMismatch, isValidAlias, isMissing, matchedCompany }`
|
|
13
|
+
|
|
14
|
+
### `AliasRouteGuard`
|
|
15
|
+
Wrapper de rota que sincroniza alias da URL com a sessão. Comportamento:
|
|
16
|
+
|
|
17
|
+
| Cenário | Ação |
|
|
18
|
+
|---------|------|
|
|
19
|
+
| Alias ausente na URL | Redireciona para `/{aliasAtivo}/{path}` |
|
|
20
|
+
| Alias diferente do ativo | Chama `switchUnit()` + loading |
|
|
21
|
+
| Alias correto | Renderiza children |
|
|
22
|
+
| Alias inválido | Redireciona para `/{aliasDefault}/{path}` |
|
|
23
|
+
| Troca via seletor de unidades | Atualiza URL automaticamente |
|
|
24
|
+
|
|
25
|
+
## Uso nos Consumidores
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<Route element={<ProtectedRoute><AliasRouteGuard><Outlet /></AliasRouteGuard></ProtectedRoute>}>
|
|
29
|
+
<Route path="/:alias/documents" element={<DocumentsPage />} />
|
|
30
|
+
<Route path="/:alias/documents/:id" element={<DocumentDetailPage />} />
|
|
31
|
+
</Route>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Regras
|
|
35
|
+
- Guard só age após `isLoading=false && isAuthenticated=true`
|
|
36
|
+
- Usa `replace: true` para evitar poluir o histórico
|
|
37
|
+
- Se `switchUnit` falha, mantém alias atual (sem loop)
|
|
38
|
+
- `switchUnit` já faz `queryClient.clear()` — cache é limpo automaticamente
|
|
39
|
+
- Navegação inter-módulos já usa `{alias}` nas URLs (`modulesData.ts`)
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
Sempre que modificar qualquer arquivo em `lib/`, verificar se existe documentação correspondente em `src/design-system/docs/`.
|
|
6
6
|
|
|
7
|
+
**Esta regra é obrigatória e deve ser aplicada em toda alteração de componente, sem exceção.**
|
|
8
|
+
|
|
7
9
|
## Ações obrigatórias
|
|
8
10
|
|
|
9
11
|
### 1. Componente/hook existente com doc existente
|
|
10
|
-
- Atualizar props, exemplos e descrições no `*Doc.tsx` correspondente para refletir a mudança
|
|
12
|
+
- Atualizar props, exemplos, hierarquias e descrições no `*Doc.tsx` correspondente para refletir a mudança
|
|
13
|
+
- Atualizar previews interativos para que reflitam o comportamento atual do componente
|
|
11
14
|
|
|
12
15
|
### 2. Componente/hook novo sem doc
|
|
13
16
|
- Criar `*Doc.tsx` usando `ComponentDocTemplate` (com prop `usage` obrigatória)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# Memory: patterns/dynamic-supabase-config
|
|
2
|
+
Updated: 2026-03-24
|
|
3
|
+
|
|
4
|
+
As credenciais do Supabase vêm exclusivamente do `.env` (auto-populado pelo Lovable ao trocar banco). O Vite injeta automaticamente variáveis `VITE_*` em `import.meta.env` — não há bloco `define` manual nem extração de `client.ts`. O `vite.config.ts` usa `loadEnv()` apenas para ler o project ID no contexto Node (CSP headers). O `SupabaseSingleton` lê `import.meta.env.VITE_SUPABASE_URL` e `VITE_SUPABASE_PUBLISHABLE_KEY` em runtime no browser.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Memory: patterns/environment-detection-logic
|
|
2
|
+
Updated: 2026-03-24
|
|
3
|
+
|
|
4
|
+
O sistema separa duas preocupações independentes de ambiente:
|
|
5
|
+
|
|
6
|
+
## 1. Método de autenticação (`shouldUseDevTokens()` / `isLovablePreview()`)
|
|
7
|
+
Detecta se o app roda em contexto de desenvolvimento (preview Lovable via iframe, `*.lovable.dev`, localhost ou `import.meta.env.DEV`). Quando true, usa a edge function `dev-tokens` do Supabase conectado para autenticar. Quando false (app publicado), usa OAuth padrão do Qualiex.
|
|
8
|
+
|
|
9
|
+
## 2. Qual API usar (`getEnvironmentConfig()` / `isDevSupabaseProject()`)
|
|
10
|
+
Compara o project ID do Supabase conectado com `PROD_PROJECT_ID` (`ccjfvpnndclajkleyqkc`). Se igual → config PROD (API prod, OAuth prod). Se diferente → config DEV (API dev, OAuth dev).
|
|
11
|
+
|
|
12
|
+
## Fonte de verdade do Project ID
|
|
13
|
+
O project ID vem do `.env` (auto-populado pelo Lovable ao trocar banco), que o Vite injeta automaticamente em `import.meta.env.VITE_SUPABASE_PROJECT_ID`. **Não** é extraído de `src/integrations/supabase/client.ts`. O `vite.config.ts` usa `loadEnv()` apenas no contexto Node para configurar CSP headers.
|
|
14
|
+
|
|
15
|
+
## Tabela de regras
|
|
16
|
+
|
|
17
|
+
| Cenário | API | Auth |
|
|
18
|
+
|------------------------------|------|------------|
|
|
19
|
+
| Preview + Prod Supabase | Prod | dev-tokens |
|
|
20
|
+
| Preview + Dev Supabase | Dev | dev-tokens |
|
|
21
|
+
| Publicado + Prod Supabase | Prod | OAuth |
|
|
22
|
+
| Publicado + Dev Supabase | Dev | OAuth |
|
|
23
|
+
|
|
24
|
+
## Guard de troca de projeto (`TokenManager.checkProjectMismatch()`)
|
|
25
|
+
Ao inicializar (`AuthService.initialize()`), o sistema compara `import.meta.env.VITE_SUPABASE_PROJECT_ID` com o valor armazenado em `localStorage('supabase_project_id')`. Se diferente, limpa todos os tokens stale automaticamente antes de qualquer chamada a `validate-token`, evitando 401 desnecessários. Após a limpeza, armazena o novo project ID. Isso garante transição limpa ao trocar de banco Supabase sem erros ou blank screen.
|
|
26
|
+
|
|
27
|
+
## Funções (lib/config/index.ts)
|
|
28
|
+
- `isLovablePreview()` — detecta contexto de preview/localhost
|
|
29
|
+
- `shouldUseDevTokens()` — wrapper semântico sobre `isLovablePreview()`
|
|
30
|
+
- `isDevEnvironment` — alias deprecated, mantido para compatibilidade
|
|
31
|
+
- `getEnvironmentConfig()` — retorna config PROD ou DEV baseado no project ID
|
|
32
|
+
- `isDevSupabaseProject()` — true se project ID ≠ PROD_PROJECT_ID
|
|
33
|
+
|
|
34
|
+
## Funções (lib/auth/services/TokenManager.ts)
|
|
35
|
+
- `checkProjectMismatch()` — detecta troca de projeto Supabase e limpa tokens stale
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface AliasRouteGuardProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
/** Nome do param de rota (default: "alias") */
|
|
5
|
+
paramName?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Guard de rota que sincroniza o alias da URL com a sessão de autenticação.
|
|
9
|
+
*
|
|
10
|
+
* Comportamento:
|
|
11
|
+
* - **Alias ausente na URL** → Redireciona para `/{aliasAtivo}/{restoDoPath}` (replace)
|
|
12
|
+
* - **Alias presente mas diferente do ativo** → Chama `switchUnit()` + loading
|
|
13
|
+
* - **Alias presente e correto** → Renderiza children
|
|
14
|
+
* - **Alias inválido (não existe em companies)** → Redireciona para `/{aliasDefault}/{restoDoPath}`
|
|
15
|
+
* - **Troca via seletor de unidades** → Atualiza URL automaticamente
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <Route element={<AliasRouteGuard><Outlet /></AliasRouteGuard>}>
|
|
20
|
+
* <Route path="/:alias/documents" element={<DocumentsPage />} />
|
|
21
|
+
* <Route path="/:alias/documents/:id" element={<DocumentDetailPage />} />
|
|
22
|
+
* </Route>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function AliasRouteGuard({ children, paramName }: AliasRouteGuardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -16,6 +16,12 @@ export declare const TokenManager: {
|
|
|
16
16
|
generateOAuthState: () => string;
|
|
17
17
|
generateOAuthNonce: () => string;
|
|
18
18
|
hasAllTokens: () => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Detecta troca de projeto Supabase e limpa tokens stale automaticamente.
|
|
21
|
+
* Deve ser chamado ANTES de qualquer validação de token.
|
|
22
|
+
* Retorna true se houve troca (tokens foram limpos).
|
|
23
|
+
*/
|
|
24
|
+
checkProjectMismatch: () => boolean;
|
|
19
25
|
setSupabaseToken: (token: string) => void;
|
|
20
26
|
areAllTokensValid: () => boolean;
|
|
21
27
|
clearExpiredTokens: () => boolean;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -19,6 +19,14 @@ export declare const CRUD_CONFIG: {
|
|
|
19
19
|
export declare const SEARCH_CONFIG: {
|
|
20
20
|
readonly debounceDelay: 500;
|
|
21
21
|
};
|
|
22
|
+
export declare const isLovablePreview: () => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Determines auth method: true → use dev-tokens edge function, false → use OAuth.
|
|
25
|
+
* This is independent of which API environment (prod/dev) is used — that's decided
|
|
26
|
+
* by getEnvironmentConfig() based on the Supabase project ID.
|
|
27
|
+
*/
|
|
28
|
+
export declare const shouldUseDevTokens: () => boolean;
|
|
29
|
+
/** @deprecated Use `isLovablePreview()` or `shouldUseDevTokens()` instead */
|
|
22
30
|
export declare const isDevEnvironment: () => boolean;
|
|
23
31
|
export { isDevSupabaseProject } from './environments';
|
|
24
32
|
export declare const getQualiexApiUrl: () => string;
|
|
@@ -5,6 +5,7 @@ export interface ColumnSettingsPopoverProps<T> {
|
|
|
5
5
|
isColumnHidden: (key: string) => boolean;
|
|
6
6
|
toggleColumn: (key: string) => void;
|
|
7
7
|
showAllColumns: () => void;
|
|
8
|
+
resetColumns?: () => void;
|
|
8
9
|
reorderColumns: (fromIndex: number, toIndex: number) => void;
|
|
9
10
|
/** @deprecated Use groupByColumns + addGroupByColumn + removeGroupByColumn */
|
|
10
11
|
groupByColumn?: string | null;
|
|
@@ -14,4 +15,4 @@ export interface ColumnSettingsPopoverProps<T> {
|
|
|
14
15
|
addGroupByColumn?: (key: string) => void;
|
|
15
16
|
removeGroupByColumn?: (key: string) => void;
|
|
16
17
|
}
|
|
17
|
-
export declare function ColumnSettingsPopover<T extends BaseEntity>({ columns, columnOrder, isColumnHidden, toggleColumn, showAllColumns, reorderColumns, groupByColumn, setGroupByColumn, groupByColumns, addGroupByColumn, removeGroupByColumn, }: ColumnSettingsPopoverProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function ColumnSettingsPopover<T extends BaseEntity>({ columns, columnOrder, isColumnHidden, toggleColumn, showAllColumns, reorderColumns, groupByColumn, setGroupByColumn, groupByColumns, addGroupByColumn, removeGroupByColumn, resetColumns, }: ColumnSettingsPopoverProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -40,6 +40,8 @@ export interface CrudTableProps<T extends BaseEntity & {
|
|
|
40
40
|
resizeStorageKey?: string;
|
|
41
41
|
enableColumnManager?: boolean;
|
|
42
42
|
columnManagerStorageKey?: string;
|
|
43
|
+
/** Habilita agrupamento de colunas (GroupDropZone + opções de grupo no ColumnSettings). Default: false */
|
|
44
|
+
enableGrouping?: boolean;
|
|
43
45
|
}
|
|
44
|
-
export declare const CrudTable: <T extends BaseEntity>({ manager, columns, onEdit, onView, onToggleStatus, onDelete, renderActions, customRowActions, enableBulkActions, rowActionsVariant, onNew, newButtonLabel, showNewButton, customActions, hideActionBar, showActionBar, showSearch, searchValue, onSearchChange, searchPlaceholder, bulkActions, onBulkDelete, filters, viewMode, onViewModeChange, showViewToggle, enableColumnResize, resizeStorageKey, enableColumnManager, columnManagerStorageKey, }: CrudTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export declare const CrudTable: <T extends BaseEntity>({ manager, columns, onEdit, onView, onToggleStatus, onDelete, renderActions, customRowActions, enableBulkActions, rowActionsVariant, onNew, newButtonLabel, showNewButton, customActions, hideActionBar, showActionBar, showSearch, searchValue, onSearchChange, searchPlaceholder, bulkActions, onBulkDelete, filters, viewMode, onViewModeChange, showViewToggle, enableColumnResize, resizeStorageKey, enableColumnManager, columnManagerStorageKey, enableGrouping, }: CrudTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
45
47
|
export default CrudTable;
|
|
@@ -20,6 +20,8 @@ export interface UseColumnManagerReturn<T> {
|
|
|
20
20
|
toggleColumn: (key: string) => void;
|
|
21
21
|
/** Show all columns */
|
|
22
22
|
showAllColumns: () => void;
|
|
23
|
+
/** Reset columns to default order and visibility */
|
|
24
|
+
resetColumns: () => void;
|
|
23
25
|
/** Current column order (keys) */
|
|
24
26
|
columnOrder: string[];
|
|
25
27
|
/** Reorder columns */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface UseAliasFromUrlOptions {
|
|
2
|
+
/** Nome do param de rota (default: "alias") */
|
|
3
|
+
paramName?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface UseAliasFromUrlReturn {
|
|
6
|
+
/** Alias extraído da URL (ou null se ausente) */
|
|
7
|
+
urlAlias: string | null;
|
|
8
|
+
/** true se há alias na URL e é diferente do alias ativo */
|
|
9
|
+
isAliasMismatch: boolean;
|
|
10
|
+
/** true se o alias da URL existe nas companies do usuário */
|
|
11
|
+
isValidAlias: boolean;
|
|
12
|
+
/** true se não há alias na URL */
|
|
13
|
+
isMissing: boolean;
|
|
14
|
+
/** Company correspondente ao alias da URL (ou null) */
|
|
15
|
+
matchedCompany: {
|
|
16
|
+
id: string;
|
|
17
|
+
alias: string;
|
|
18
|
+
name: string;
|
|
19
|
+
} | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Hook para extrair e validar o alias da URL contra as companies do usuário.
|
|
23
|
+
*
|
|
24
|
+
* Lê o param `:alias` do React Router e verifica se é um alias válido
|
|
25
|
+
* (presente na lista de companies do token de autenticação).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* // Rota: /:alias/documents
|
|
30
|
+
* const { urlAlias, isAliasMismatch, isValidAlias, isMissing } = useAliasFromUrl();
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function useAliasFromUrl(options?: UseAliasFromUrlOptions): UseAliasFromUrlReturn;
|
|
@@ -9,7 +9,7 @@ interface UseSidebarResizeProps {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function useSidebarResize({ direction, minWidth, // 14rem
|
|
11
11
|
maxWidth, // 24rem
|
|
12
|
-
defaultWidth, //
|
|
12
|
+
defaultWidth, // ~17.5rem
|
|
13
13
|
storageKey, onResize, isOpen }?: UseSidebarResizeProps): {
|
|
14
14
|
width: number;
|
|
15
15
|
isDragging: boolean;
|