diff --git a/README.md b/README.md
index 3bfe9f0..c797c37 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,8 @@ This template equips you with a foundational React application integrated with A
- **Authentication**: Setup with Amazon Cognito for secure user authentication with email login.
- More info on how to setup and configuration option: https://docs.amplify.aws/react/build-a-backend/auth/set-up-auth/
- **Storage**: Configured with multiple S3 buckets and granular access controls. The sample is configured with
- - Default storage bucket with public, admin, and private access paths
- - Secondary storage bucket with separate backup paths.
+ - Default `frauden-bucket` storage bucket with `doctrina`, `medios`, `jurisprudencia`, and `legislacion` access paths for authenticated readers and admin read/write/delete access.
+ - Secondary `frauden-expedientes` storage bucket with `publico`, `confidencial`, and owner-scoped `privado/{entity_id}` access paths, including delete permissions wherever write access is granted.
- More info on how to setup : https://docs.amplify.aws/react/build-a-backend/storage/set-up-storage/#building-your-storage-backend
- **UI Components**: Pre-integrated Amplify UI React components including:
- Authenticator for sign-in/sign-up flows
diff --git a/amplify/auth/resource.ts b/amplify/auth/resource.ts
index 8bbd191..e10a2e5 100644
--- a/amplify/auth/resource.ts
+++ b/amplify/auth/resource.ts
@@ -8,5 +8,5 @@ export const auth = defineAuth({
loginWith: {
email: true,
},
- groups: ['admin']
+ groups: ['admin', 'eliminadores'],
});
diff --git a/amplify/backend.ts b/amplify/backend.ts
index 032938d..0c49596 100644
--- a/amplify/backend.ts
+++ b/amplify/backend.ts
@@ -2,12 +2,21 @@ import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { storage, secondaryStorage } from './storage/resource';
-
/**
* @see https://docs.amplify.aws/react/build-a-backend/ to add storage, functions, and more
*/
-defineBackend({
+const backend = defineBackend({
auth,
- storage,
- secondaryStorage
+ storage,
+ secondaryStorage,
});
+
+// Do not override cfnBucket.bucketName here. S3 bucket names are globally unique,
+// and Amplify's generated physical names avoid collisions during deployments.
+
+const { cfnUserPool } = backend.auth.resources.cfnResources;
+
+cfnUserPool.adminCreateUserConfig = {
+ ...cfnUserPool.adminCreateUserConfig,
+ allowAdminCreateUserOnly: true,
+};
diff --git a/amplify/storage/resource.ts b/amplify/storage/resource.ts
index 62d6340..a31485c 100644
--- a/amplify/storage/resource.ts
+++ b/amplify/storage/resource.ts
@@ -1,39 +1,46 @@
import { defineStorage } from '@aws-amplify/backend';
export const storage = defineStorage({
- name: 'myStorageBucket',
+ name: 'frauden',
isDefault: true,
- access: (allow) => ({
- 'public/*': [
- allow.guest.to(['read', 'write']),
- allow.authenticated.to(['read', 'write', 'delete']),
+ access: (allow) => ({
+ 'doctrina/*': [
+ allow.authenticated.to(['read']),
+ allow.groups(['admin']).to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
],
- 'admin/*': [
- allow.groups(['admin']).to(['read', 'write', 'delete']),
- allow.authenticated.to(['read'])
+ 'medios/*': [
+ allow.authenticated.to(['read']),
+ allow.groups(['admin']).to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
],
- 'private/{entity_id}/*': [
- allow.entity('identity').to(['read', 'write', 'delete'])
- ]
- })
+ 'jurisprudencia/*': [
+ allow.authenticated.to(['read']),
+ allow.groups(['admin']).to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
+ ],
+ 'legislacion/*': [
+ allow.authenticated.to(['read']),
+ allow.groups(['admin']).to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
+ ],
+ }),
});
export const secondaryStorage = defineStorage({
- name: 'mySecondaryStorageBucket',
- access: (allow) => ({
- 'backup_public/*': [
- allow.guest.to(['read', 'write']),
- allow.authenticated.to(['read', 'write', 'delete']),
+ name: 'frauden-expedientes',
+ access: (allow) => ({
+ 'publico/*': [
+ allow.authenticated.to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
+ ],
+ 'confidencial/*': [
+ allow.groups(['admin']).to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
],
- 'backup_admin/*': [
- allow.groups(['admin']).to(['read', 'write', 'delete']),
- allow.authenticated.to(['read'])
+ 'privado/{entity_id}/*': [
+ allow.entity('identity').to(['read', 'write']),
+ allow.groups(['eliminadores']).to(['delete']),
],
- 'backup_private/{entity_id}/*': [
- allow.entity('identity').to(['read', 'write', 'delete'])
- ]
- })
+ }),
});
-
-
-
diff --git a/index.html b/index.html
index 1a96360..a929ef2 100644
--- a/index.html
+++ b/index.html
@@ -1,9 +1,9 @@
-
+
- Amplify Storage Browser Sample
+ Frauden | Gestor documental
diff --git a/src/App.css b/src/App.css
index 5bbce99..605fc59 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,11 +1,341 @@
+:root {
+ color-scheme: light;
+ font-family:
+ Inter,
+ ui-sans-serif,
+ system-ui,
+ -apple-system,
+ BlinkMacSystemFont,
+ 'Segoe UI',
+ sans-serif;
+ --frauden-navy: #101936;
+ --frauden-navy-soft: #1f2d5f;
+ --frauden-blue: #26366f;
+ --frauden-silver: #c9ccd1;
+ --frauden-silver-dark: #8e939b;
+ --frauden-ink: #171b26;
+ --frauden-muted: #667085;
+ --frauden-surface: rgba(255, 255, 255, 0.9);
+ --frauden-border: rgba(16, 25, 54, 0.12);
+ --frauden-shadow: 0 24px 70px rgba(16, 25, 54, 0.14);
+
+ --amplify-colors-brand-primary-10: #eef1f8;
+ --amplify-colors-brand-primary-20: #d8ddeb;
+ --amplify-colors-brand-primary-40: #9fa9cd;
+ --amplify-colors-brand-primary-60: #53639b;
+ --amplify-colors-brand-primary-80: var(--frauden-blue);
+ --amplify-colors-brand-primary-90: var(--frauden-navy-soft);
+ --amplify-colors-brand-primary-100: var(--frauden-navy);
+ --amplify-colors-font-primary: var(--frauden-ink);
+ --amplify-colors-font-secondary: var(--frauden-muted);
+ --amplify-colors-border-primary: var(--frauden-border);
+ --amplify-radii-small: 0.65rem;
+ --amplify-radii-medium: 0.95rem;
+ --amplify-radii-large: 1.4rem;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ min-width: 320px;
+ min-height: 100vh;
+ margin: 0;
+ color: var(--frauden-ink);
+ background:
+ radial-gradient(circle at top left, rgba(201, 204, 209, 0.48), transparent 34rem),
+ linear-gradient(135deg, #f8fafc 0%, #eef1f6 47%, #fdfdfd 100%);
+}
+
+body::before {
+ position: fixed;
+ inset: 0;
+ z-index: -1;
+ pointer-events: none;
+ content: '';
+ background:
+ linear-gradient(115deg, transparent 0 62%, rgba(16, 25, 54, 0.08) 62% 100%),
+ radial-gradient(circle at 86% 10%, rgba(38, 54, 111, 0.14), transparent 20rem);
+}
+
#root {
+ width: 100%;
+ min-height: 100vh;
+}
+
+.app-shell {
+ width: min(1440px, 100%);
+ min-height: 100vh;
margin: 0 auto;
- padding: 2rem;
- text-align: center;
+ padding: 1.5rem;
+}
+
+.site-header {
+ display: flex;
+ gap: 1.5rem;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem 1.25rem;
+ background: rgba(255, 255, 255, 0.82);
+ border: 1px solid var(--frauden-border);
+ border-radius: 1.5rem;
+ box-shadow: 0 18px 50px rgba(16, 25, 54, 0.1);
+ backdrop-filter: blur(18px);
+}
+
+.brand {
+ display: inline-flex;
+ align-items: center;
+ min-width: 0;
+}
+
+.brand-logo {
+ display: block;
+ width: clamp(14rem, 34vw, 25rem);
+ max-height: 5.75rem;
+ object-fit: contain;
+}
+
+.header-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.85rem;
+ align-items: center;
+ justify-content: flex-end;
+}
+
+.user-card {
+ min-width: min(15rem, 100%);
+ padding: 0.75rem 1rem;
+ text-align: right;
+ background: linear-gradient(135deg, rgba(16, 25, 54, 0.06), rgba(201, 204, 209, 0.18));
+ border: 1px solid rgba(16, 25, 54, 0.08);
+ border-radius: 1rem;
+}
+
+.user-card strong {
+ display: block;
+ overflow: hidden;
+ color: var(--frauden-navy);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.eyebrow {
+ display: inline-flex;
+ margin-bottom: 0.35rem;
+ color: var(--frauden-silver-dark);
+ font-size: 0.72rem;
+ font-weight: 700;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+}
+
+.sign-out-button.amplify-button {
+ min-height: 3rem;
+ padding-inline: 1.25rem;
+ font-weight: 700;
+ background: linear-gradient(135deg, var(--frauden-navy), var(--frauden-blue));
+ border: 0;
+ box-shadow: 0 14px 30px rgba(16, 25, 54, 0.25);
+}
+
+.hero-card {
+ position: relative;
+ overflow: hidden;
+ margin: 1rem 0;
+ padding: clamp(1rem, 2.5vw, 2.25rem) clamp(1.25rem, 4vw, 3.75rem);
+ color: white;
+ background:
+ linear-gradient(135deg, rgba(16, 25, 54, 0.94), rgba(31, 45, 95, 0.88)),
+ linear-gradient(90deg, rgba(201, 204, 209, 0.22), transparent);
+ border-radius: 2rem;
+ box-shadow: var(--frauden-shadow);
+}
+
+.hero-card::after {
+ position: absolute;
+ top: -38%;
+ right: -10%;
+ width: 27rem;
+ height: 27rem;
+ content: '';
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.2), transparent 62%);
+ border: 1px solid rgba(255, 255, 255, 0.12);
+ border-radius: 999px;
+}
+
+.hero-card > div {
+ position: relative;
+ z-index: 1;
+ width: 100%;
+}
+
+.hero-card .eyebrow {
+ color: var(--frauden-silver);
+}
+
+.hero-card h1 {
+ width: 100%;
+ max-width: none;
+ margin: 0;
+ font-size: clamp(2rem, 5vw, 4.75rem);
+ line-height: 0.96;
+ letter-spacing: -0.06em;
+}
+
+.hero-card p {
+ max-width: 43rem;
+ margin: 1.1rem 0 0;
+ color: rgba(255, 255, 255, 0.78);
+ font-size: clamp(1rem, 2vw, 1.2rem);
+ line-height: 1.7;
}
-.header {
+.knowledge-sync-panel {
display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ align-items: center;
justify-content: space-between;
+ margin-bottom: 1rem;
+ padding: 1rem 1.1rem;
+ background: linear-gradient(135deg, rgba(16, 25, 54, 0.06), rgba(201, 204, 209, 0.18));
+ border: 1px solid rgba(16, 25, 54, 0.08);
+ border-radius: 1.25rem;
+}
+
+.knowledge-sync-panel p {
+ margin: 0;
+ color: var(--frauden-silver-dark);
+ line-height: 1.5;
+}
+
+.knowledge-sync-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem;
align-items: center;
-}
\ No newline at end of file
+ justify-content: flex-end;
+}
+
+.knowledge-sync-button.amplify-button {
+ min-height: 3rem;
+ padding-inline: 1.25rem;
+ font-weight: 700;
+ box-shadow: 0 14px 30px rgba(16, 25, 54, 0.18);
+}
+
+.knowledge-sync-status {
+ max-width: 28rem;
+ padding: 0.7rem 0.85rem;
+ font-size: 0.92rem;
+ font-weight: 700;
+ border-radius: 0.85rem;
+}
+
+.knowledge-sync-status--error {
+ color: #8a1f11;
+ background: #fff0ed;
+ border: 1px solid #f3b3a8;
+}
+
+.knowledge-sync-status--info {
+ color: var(--frauden-navy);
+ background: #eef4ff;
+ border: 1px solid #c7d8f8;
+}
+
+.knowledge-sync-status--success {
+ color: #115f35;
+ background: #edfff5;
+ border: 1px solid #a8e2c0;
+}
+
+.storage-card {
+ padding: clamp(0.85rem, 2vw, 1.4rem);
+ background: var(--frauden-surface);
+ border: 1px solid var(--frauden-border);
+ border-radius: 2rem;
+ box-shadow: var(--frauden-shadow);
+ backdrop-filter: blur(18px);
+}
+
+.storage-card :is(.amplify-button, button) {
+ border-radius: 0.85rem;
+}
+
+.storage-card :is(.amplify-button--primary, [data-variation='primary']) {
+ background: linear-gradient(135deg, var(--frauden-navy), var(--frauden-blue));
+ border-color: transparent;
+}
+
+.storage-card :is(table, .amplify-table) {
+ overflow: hidden;
+ border-radius: 1rem;
+}
+
+.storage-card :is(th, .amplify-table__th) {
+ color: var(--frauden-navy);
+ background: #f4f6f9;
+}
+
+.storage-card [data-testid='LOCATIONS_VIEW'] :is(.amplify-storage-browser__table, .storage-browser__table)
+ :is(th, td):nth-child(2) {
+ display: none;
+}
+
+.amplify-authenticator {
+ min-height: 100vh;
+ background:
+ radial-gradient(circle at 18% 10%, rgba(201, 204, 209, 0.5), transparent 22rem),
+ linear-gradient(135deg, #f8fafc, #eef1f6);
+}
+
+.amplify-authenticator [data-amplify-router] {
+ overflow: hidden;
+ border: 1px solid var(--frauden-border);
+ border-radius: 1.5rem;
+ box-shadow: var(--frauden-shadow);
+}
+
+@media (max-width: 760px) {
+ .app-shell {
+ padding: 0.85rem;
+ }
+
+ .site-header,
+ .header-actions {
+ align-items: stretch;
+ }
+
+ .site-header {
+ flex-direction: column;
+ }
+
+ .brand-logo {
+ width: min(100%, 22rem);
+ }
+
+ .header-actions,
+ .sign-out-button.amplify-button {
+ width: 100%;
+ }
+
+ .user-card {
+ flex: 1;
+ text-align: left;
+ }
+}
+
+.auth-brand {
+ display: flex;
+ justify-content: center;
+ padding: 2rem 2rem 0.5rem;
+}
+
+.auth-brand-logo {
+ width: min(20rem, 82vw);
+ height: auto;
+}
diff --git a/src/App.tsx b/src/App.tsx
index e2f45be..5873c0d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,30 +1,378 @@
import {
+ componentsDefault,
createAmplifyAuthAdapter,
createStorageBrowser,
} from '@aws-amplify/ui-react-storage/browser';
+import '@aws-amplify/ui-react/styles.css';
import '@aws-amplify/ui-react-storage/styles.css';
import './App.css';
-
+import { useState } from 'react';
import config from '../amplify_outputs.json';
import { Amplify } from 'aws-amplify';
-import { Authenticator, Button } from '@aws-amplify/ui-react';
+import { fetchAuthSession } from 'aws-amplify/auth';
+import { I18n } from 'aws-amplify/utils';
+import { Authenticator, Button, translations } from '@aws-amplify/ui-react';
+import fraudenLogo from './assets/frauden-logo.svg';
+
Amplify.configure(config);
+I18n.putVocabularies(translations);
+I18n.setLanguage('es');
const { StorageBrowser } = createStorageBrowser({
config: createAmplifyAuthAdapter(),
+ components: componentsDefault,
});
+type StorageBrowserDisplayText = NonNullable[0]['displayText']>;
+
+type KnowledgeSyncStatus = {
+ message: string;
+ type: 'error' | 'info' | 'success';
+} | null;
+
+const syncKnowledgeEndpoint = import.meta.env.VITE_SYNC_KNOWLEDGE_LAMBDA_URL?.trim();
+const syncKnowledgeTooltip =
+ 'Cuando agregues nuevos documentos o elimines debes sincronizar la base de conocimiento para cargar la nueva información';
+
+const authenticatorComponents = {
+ Header() {
+ return (
+
+

+
+ );
+ },
+};
+
+function KnowledgeSyncButton() {
+ const [isSyncing, setIsSyncing] = useState(false);
+ const [syncStatus, setSyncStatus] = useState(null);
+
+ const handleKnowledgeSync = async () => {
+ if (!syncKnowledgeEndpoint) {
+ setSyncStatus({
+ type: 'error',
+ message:
+ 'Configura VITE_SYNC_KNOWLEDGE_LAMBDA_URL con la URL de la Lambda para sincronizar.',
+ });
+ return;
+ }
+
+ setIsSyncing(true);
+ setSyncStatus({ type: 'info', message: 'Solicitando sincronización de conocimiento...' });
+
+ try {
+ const session = await fetchAuthSession();
+ const idToken = session.tokens?.idToken?.toString();
+
+ if (!idToken) {
+ throw new Error('No se encontró una sesión autenticada para invocar la Lambda.');
+ }
+
+ const response = await fetch(syncKnowledgeEndpoint, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${idToken}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ action: 'syncKnowledgeBase' }),
+ });
+
+ if (!response.ok) {
+ const errorMessage = await response.text();
+ throw new Error(
+ errorMessage || `La Lambda respondió con estado ${response.status}. Intenta nuevamente.`
+ );
+ }
+
+ setSyncStatus({
+ type: 'success',
+ message: 'Sincronización de conocimiento iniciada correctamente.',
+ });
+ } catch (error) {
+ setSyncStatus({
+ type: 'error',
+ message:
+ error instanceof Error
+ ? error.message
+ : 'No se pudo iniciar la sincronización de conocimiento.',
+ });
+ } finally {
+ setIsSyncing(false);
+ }
+ };
+
+ return (
+
+
+ Base de conocimiento
+
+
+
+ {syncStatus ? (
+
+ {syncStatus.message}
+
+ ) : null}
+
+
+ );
+}
+
+const storageBrowserDisplayText: StorageBrowserDisplayText = {
+ LocationsView: {
+ title: 'Inicio',
+ searchPlaceholder: 'Filtrar carpetas y archivos',
+ searchSubmitLabel: 'Buscar',
+ searchClearLabel: 'Limpiar búsqueda',
+ loadingIndicatorLabel: 'Cargando',
+ tableColumnBucketHeader: 'Bucket',
+ tableColumnFolderHeader: 'Carpeta',
+ tableColumnPermissionsHeader: 'Permisos',
+ tableColumnActionsHeader: 'Acciones',
+ getPermissionName: (permissions) => {
+ const canRead = permissions.includes('get') || permissions.includes('list');
+ const canWrite = permissions.includes('write') || permissions.includes('delete');
+
+ if (canRead && canWrite) return 'Lectura/Escritura';
+ if (canRead) return 'Lectura';
+ if (canWrite) return 'Escritura';
+
+ return permissions.join('/');
+ },
+ getDownloadLabel: (fileName) => `Descargar ${fileName}`,
+ getListLocationsResultMessage: (data) => {
+ const { isLoading, items, hasExhaustedSearch, hasError = false, message } = data ?? {};
+
+ if (isLoading) return undefined;
+ if (hasError) {
+ return {
+ type: 'error',
+ content: message ?? 'Ocurrió un error al cargar las ubicaciones.',
+ };
+ }
+ if (items?.length === 0 && !hasExhaustedSearch) {
+ return { type: 'info', content: 'No hay carpetas ni archivos.' };
+ }
+ if (hasExhaustedSearch) {
+ return {
+ type: 'info',
+ content: 'Se muestran resultados de hasta los primeros 10,000 elementos.',
+ };
+ }
+
+ return undefined;
+ },
+ },
+ LocationDetailView: {
+ loadingIndicatorLabel: 'Cargando',
+ searchPlaceholder: 'Buscar en la carpeta actual',
+ searchSubmitLabel: 'Buscar',
+ searchClearLabel: 'Limpiar búsqueda',
+ searchSubfoldersToggleLabel: 'Incluir subcarpetas',
+ selectFileLabel: 'Seleccionar archivo',
+ selectAllFilesLabel: 'Seleccionar todos los archivos',
+ tableColumnLastModifiedHeader: 'Última modificación',
+ tableColumnNameHeader: 'Nombre',
+ tableColumnSizeHeader: 'Tamaño',
+ tableColumnTypeHeader: 'Tipo',
+ getTitle: ({ current, key }) => key || current?.bucket || '',
+ getActionListItemLabel: (key = '') => {
+ const labels: Record = {
+ Copy: 'Copiar',
+ Delete: 'Eliminar',
+ 'Create folder': 'Crear carpeta',
+ Upload: 'Subir',
+ };
+
+ return labels[key] ?? key;
+ },
+ getListItemsResultMessage: (data) => {
+ const { items, hasExhaustedSearch, hasError = false, message, isLoading } = data ?? {};
+
+ if (isLoading) return undefined;
+ if (hasError) {
+ return {
+ type: 'error',
+ content: message ?? 'Ocurrió un error al cargar los elementos.',
+ };
+ }
+ if (!items?.length && hasExhaustedSearch) {
+ return {
+ type: 'info',
+ content: 'No se encontraron resultados en los primeros 10,000 elementos.',
+ };
+ }
+ if (!items?.length) return { type: 'info', content: 'No hay archivos.' };
+ if (hasExhaustedSearch) {
+ return {
+ type: 'info',
+ content: 'Se muestran resultados de hasta los primeros 10,000 elementos.',
+ };
+ }
+
+ return undefined;
+ },
+ },
+ UploadView: {
+ title: 'Subir',
+ actionStartLabel: 'Subir',
+ actionCancelLabel: 'Cancelar',
+ actionExitLabel: 'Salir',
+ addFilesLabel: 'Agregar archivos',
+ addFolderLabel: 'Agregar carpeta',
+ overwriteToggleLabel: 'Sobrescribir archivos existentes',
+ statusDisplayCanceledLabel: 'Cancelado',
+ statusDisplayCompletedLabel: 'Completado',
+ statusDisplayFailedLabel: 'Fallido',
+ statusDisplayInProgressLabel: 'En progreso',
+ statusDisplayOverwritePreventedLabel: 'Sobrescritura evitada',
+ statusDisplayQueuedLabel: 'Sin iniciar',
+ statusDisplayTotalLabel: 'Total',
+ tableColumnFolderHeader: 'Carpeta',
+ tableColumnNameHeader: 'Nombre',
+ tableColumnTypeHeader: 'Tipo',
+ tableColumnSizeHeader: 'Tamaño',
+ tableColumnStatusHeader: 'Estado',
+ tableColumnProgressHeader: 'Progreso',
+ getActionCompleteMessage: () => ({
+ content: 'Proceso de carga finalizado.',
+ type: 'success',
+ }),
+ },
+ DeleteView: {
+ title: 'Eliminar',
+ actionStartLabel: 'Eliminar',
+ actionCancelLabel: 'Cancelar',
+ actionExitLabel: 'Salir',
+ statusDisplayCanceledLabel: 'Cancelado',
+ statusDisplayCompletedLabel: 'Completado',
+ statusDisplayFailedLabel: 'Fallido',
+ statusDisplayInProgressLabel: 'En progreso',
+ statusDisplayQueuedLabel: 'Sin iniciar',
+ statusDisplayTotalLabel: 'Total',
+ tableColumnFolderHeader: 'Carpeta',
+ tableColumnNameHeader: 'Nombre',
+ tableColumnTypeHeader: 'Tipo',
+ tableColumnSizeHeader: 'Tamaño',
+ tableColumnStatusHeader: 'Estado',
+ getActionCompleteMessage: () => ({
+ content: 'Proceso de eliminación finalizado.',
+ type: 'success',
+ }),
+ },
+ CopyView: {
+ title: 'Copiar',
+ actionStartLabel: 'Copiar',
+ actionCancelLabel: 'Cancelar',
+ actionExitLabel: 'Salir',
+ actionDestinationLabel: 'Destino de la copia',
+ loadingIndicatorLabel: 'Cargando' as 'Loading',
+ overwriteWarningMessage:
+ 'Los archivos copiados sobrescribirán archivos existentes en el destino seleccionado.',
+ searchPlaceholder: 'Buscar carpetas',
+ searchSubmitLabel: 'Buscar',
+ searchClearLabel: 'Limpiar búsqueda',
+ statusDisplayCanceledLabel: 'Cancelado',
+ statusDisplayCompletedLabel: 'Completado',
+ statusDisplayFailedLabel: 'Fallido',
+ statusDisplayInProgressLabel: 'En progreso',
+ statusDisplayQueuedLabel: 'Sin iniciar',
+ statusDisplayTotalLabel: 'Total',
+ tableColumnFolderHeader: 'Carpeta',
+ tableColumnNameHeader: 'Nombre',
+ tableColumnTypeHeader: 'Tipo',
+ tableColumnSizeHeader: 'Tamaño',
+ tableColumnStatusHeader: 'Estado',
+ tableColumnProgressHeader: 'Progreso',
+ getListFoldersResultsMessage: ({ folders, query, hasError, message, hasExhaustedSearch }) => {
+ if (!folders?.length) {
+ return {
+ content: query
+ ? `No se encontraron carpetas que coincidan con "${query}".`
+ : 'No se encontraron subcarpetas en la carpeta seleccionada.',
+ type: 'info',
+ };
+ }
+ if ((message && query) || hasError)
+ return { content: 'Error al cargar carpetas.', type: 'error' };
+ if (hasExhaustedSearch) {
+ return {
+ content: 'Se muestran resultados de hasta los primeros 10,000 elementos.',
+ type: 'info',
+ };
+ }
+
+ return undefined;
+ },
+ getActionCompleteMessage: () => ({
+ content: 'Proceso de copia finalizado.',
+ type: 'success',
+ }),
+ },
+ CreateFolderView: {
+ title: 'Crear carpeta',
+ actionStartLabel: 'Crear carpeta',
+ actionCancelLabel: 'Cancelar',
+ actionExitLabel: 'Salir',
+ actionDestinationLabel: 'Destino',
+ folderNameLabel: 'Nombre de la carpeta',
+ folderNamePlaceholder: 'No puede contener "/" ni empezar o terminar con "."',
+ getValidationMessage: () => 'El nombre no puede contener "/" ni empezar o terminar con "."',
+ getActionCompleteMessage: () => ({
+ content: 'Carpeta creada.',
+ type: 'success',
+ }),
+ },
+};
+
function App() {
return (
-
+
{({ signOut, user }) => (
- <>
-
-
{`Hello ${user?.username}`}
-
-
-
- >
+
+
+
+
+
+
Panel seguro
+
Gestor documental de Frauden
+
+ carga archivos y organiza de forma segura y sencilla el archivo documental de
+ Frauden.
+
+
+
+
+
+
)}
);
diff --git a/src/assets/frauden-logo.svg b/src/assets/frauden-logo.svg
new file mode 100644
index 0000000..1a7d2c9
--- /dev/null
+++ b/src/assets/frauden-logo.svg
@@ -0,0 +1,24 @@
+