Update project dependencies and enhance documentation
- Added `barryvdh/laravel-dompdf` to `composer.json` for PDF generation capabilities. - Updated `boost.json` to include `tailwindcss-development` in skills. - Modified `package.json` and `package-lock.json` to upgrade Tailwind CSS and related packages. - Improved README.md for clarity and corrected French language errors. - Created design system documentation for Filament components. - Added new Filament pages for Dashboard and Documentation with dynamic content loading. - Enhanced TablesExplorer functionality with improved table and column management.
This commit is contained in:
110
.cursor/rules/design-system.mdc
Normal file
110
.cursor/rules/design-system.mdc
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
description: Design system conventions for all Filament page views in this application
|
||||||
|
globs:
|
||||||
|
- resources/views/filament/pages/**/*.blade.php
|
||||||
|
- resources/views/components/logistics/**/*.blade.php
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design System -- API Logistics
|
||||||
|
|
||||||
|
## Composants Blade reutilisables
|
||||||
|
|
||||||
|
Tous les elements visuels recurrents sont centralises dans `resources/views/components/logistics/`.
|
||||||
|
Utiliser ces composants au lieu de dupliquer du HTML/CSS.
|
||||||
|
|
||||||
|
| Composant | Usage | Fichier |
|
||||||
|
|---|---|---|
|
||||||
|
| `<x-logistics.card>` | Conteneur principal (panneau blanc arrondi) | `logistics/card.blade.php` |
|
||||||
|
| `<x-logistics.section-header>` | En-tete de section (titre + description + slot actions) | `logistics/section-header.blade.php` |
|
||||||
|
| `<x-logistics.error-banner>` | Bandeau d'erreur API | `logistics/error-banner.blade.php` |
|
||||||
|
| `<x-logistics.stat-bar>` | Barre de metadata/statistiques | `logistics/stat-bar.blade.php` |
|
||||||
|
| `<x-logistics.stat-item>` | Element individuel dans stat-bar | `logistics/stat-item.blade.php` |
|
||||||
|
| `<x-logistics.data-table>` | Tableau de donnees dynamique | `logistics/data-table.blade.php` |
|
||||||
|
| `<x-logistics.empty-state>` | Etat vide (icone + texte) | `logistics/empty-state.blade.php` |
|
||||||
|
| `<x-logistics.search-input>` | Champ de recherche avec icone loupe | `logistics/search-input.blade.php` |
|
||||||
|
| `<x-logistics.form-field>` | Champ de formulaire (label + input) | `logistics/form-field.blade.php` |
|
||||||
|
| `<x-logistics.json-block>` | Bloc JSON formate | `logistics/json-block.blade.php` |
|
||||||
|
|
||||||
|
## Conventions CSS
|
||||||
|
|
||||||
|
### Carte (card)
|
||||||
|
- `rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10`
|
||||||
|
|
||||||
|
### En-tete de section dans une carte
|
||||||
|
- Wrapper: `border-b border-gray-200 px-6 py-4 dark:border-white/10`
|
||||||
|
- Titre: `text-base font-semibold text-gray-950 dark:text-white`
|
||||||
|
- Description: `mt-1 text-xs text-gray-500 dark:text-gray-400`
|
||||||
|
|
||||||
|
### Contenu de carte
|
||||||
|
- Padding: `p-6`
|
||||||
|
|
||||||
|
### Tableau de donnees
|
||||||
|
- Conteneur: `overflow-x-auto`
|
||||||
|
- Table: `w-full text-left text-sm`
|
||||||
|
- Thead tr: `border-b border-gray-200 dark:border-white/10`
|
||||||
|
- Th: `px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400`
|
||||||
|
- Tbody: `divide-y divide-gray-100 dark:divide-white/5`
|
||||||
|
- Tr: `transition-colors hover:bg-gray-50 dark:hover:bg-white/5`
|
||||||
|
- Td: `px-3 py-2.5 text-sm text-gray-700 dark:text-gray-300`
|
||||||
|
- Td valeur technique (ID, code): ajouter `font-mono`
|
||||||
|
|
||||||
|
### Badge compteur
|
||||||
|
- `rounded-full px-2 py-0.5 text-xs font-medium tabular-nums bg-gray-100 text-gray-600 dark:bg-white/10 dark:text-gray-300`
|
||||||
|
|
||||||
|
### Champ de formulaire (input)
|
||||||
|
- `w-full rounded-lg border-gray-300 py-2 text-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white`
|
||||||
|
- Label: `block text-sm font-medium text-gray-700 dark:text-gray-300`
|
||||||
|
- Espacement label/input: `mt-1.5`
|
||||||
|
|
||||||
|
### Bloc JSON (pre)
|
||||||
|
- `rounded-lg border border-gray-200 bg-gray-50 p-4 text-xs font-mono leading-relaxed text-gray-700 dark:border-white/10 dark:bg-gray-800 dark:text-gray-300`
|
||||||
|
|
||||||
|
### Etat vide
|
||||||
|
- Conteneur: `flex flex-col items-center justify-center py-12 text-center`
|
||||||
|
- Icone: `h-10 w-10 text-gray-300 dark:text-gray-600`
|
||||||
|
- Titre: `mt-3 text-sm font-medium text-gray-900 dark:text-white`
|
||||||
|
- Description: `mt-1 text-sm text-gray-500 dark:text-gray-400`
|
||||||
|
|
||||||
|
### Erreur API
|
||||||
|
- `rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400`
|
||||||
|
|
||||||
|
### Stat bar
|
||||||
|
- `flex flex-wrap items-center gap-x-6 gap-y-2`
|
||||||
|
- Chaque item: icone h-4 w-4 + texte text-sm text-gray-500
|
||||||
|
|
||||||
|
### Loading
|
||||||
|
- Utiliser `<x-filament::loading-indicator>` + `wire:loading` / `wire:loading.remove`
|
||||||
|
|
||||||
|
## Structure d'une page type
|
||||||
|
|
||||||
|
```blade
|
||||||
|
<x-filament-panels::page>
|
||||||
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
|
|
||||||
|
{{-- Stat bar optionnelle --}}
|
||||||
|
|
||||||
|
{{-- Section formulaire --}}
|
||||||
|
<x-logistics.card>
|
||||||
|
<x-logistics.section-header title="..." description="..." />
|
||||||
|
<div class="p-6">
|
||||||
|
{{-- Formulaire avec grille --}}
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
|
||||||
|
{{-- Section resultats --}}
|
||||||
|
<x-logistics.card>
|
||||||
|
<x-logistics.section-header title="..." />
|
||||||
|
<div class="p-6">
|
||||||
|
<x-logistics.data-table :data="$data" :metadata="$metadata" />
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
</x-filament-panels::page>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Regles
|
||||||
|
|
||||||
|
- Toujours utiliser les composants `x-logistics.*` au lieu de dupliquer les classes CSS.
|
||||||
|
- Un composant `<x-logistics.card>` n'a PAS de padding interne. Le padding est gere par les enfants.
|
||||||
|
- Les formulaires dans une carte utilisent `<div class="p-6">` pour le contenu.
|
||||||
|
- Toujours afficher un etat de chargement (`wire:loading`) sur les actions reseau.
|
||||||
|
- Les blocs JSON utilisent `<x-logistics.json-block>` et non `<pre>` brut.
|
||||||
@@ -13,6 +13,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
|||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||||
|
|
||||||
- php - 8.4.16
|
- php - 8.4.16
|
||||||
|
- filament/filament (FILAMENT) - v5
|
||||||
- laravel/fortify (FORTIFY) - v1
|
- laravel/fortify (FORTIFY) - v1
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
@@ -23,6 +24,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- laravel/sail (SAIL) - v1
|
- laravel/sail (SAIL) - v1
|
||||||
- pestphp/pest (PEST) - v4
|
- pestphp/pest (PEST) - v4
|
||||||
- phpunit/phpunit (PHPUNIT) - v12
|
- phpunit/phpunit (PHPUNIT) - v12
|
||||||
|
- tailwindcss (TAILWINDCSS) - v4
|
||||||
|
|
||||||
## Skills Activation
|
## Skills Activation
|
||||||
|
|
||||||
@@ -31,6 +33,7 @@ This project has domain-specific skills available. You MUST activate the relevan
|
|||||||
- `fluxui-development` — Develops UIs with Flux UI Free components. Activates when creating buttons, forms, modals, inputs, dropdowns, checkboxes, or UI components; replacing HTML form elements with Flux; working with flux: components; or when the user mentions Flux, component library, UI components, form fields, or asks about available Flux components.
|
- `fluxui-development` — Develops UIs with Flux UI Free components. Activates when creating buttons, forms, modals, inputs, dropdowns, checkboxes, or UI components; replacing HTML form elements with Flux; working with flux: components; or when the user mentions Flux, component library, UI components, form fields, or asks about available Flux components.
|
||||||
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
||||||
- `pest-testing` — Tests applications using the Pest 4 PHP framework. Activates when writing tests, creating unit or feature tests, adding assertions, testing Livewire components, browser testing, debugging test failures, working with datasets or mocking; or when the user mentions test, spec, TDD, expects, assertion, coverage, or needs to verify functionality works.
|
- `pest-testing` — Tests applications using the Pest 4 PHP framework. Activates when writing tests, creating unit or feature tests, adding assertions, testing Livewire components, browser testing, debugging test failures, working with datasets or mocking; or when the user mentions test, spec, TDD, expects, assertion, coverage, or needs to verify functionality works.
|
||||||
|
- `tailwindcss-development` — Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components, working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors, typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle, hero section, cards, buttons, or any visual/UI changes.
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
@@ -261,4 +264,12 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
|||||||
- Do NOT delete tests without approval.
|
- Do NOT delete tests without approval.
|
||||||
- CRITICAL: ALWAYS use `search-docs` tool for version-specific Pest documentation and updated code examples.
|
- CRITICAL: ALWAYS use `search-docs` tool for version-specific Pest documentation and updated code examples.
|
||||||
- IMPORTANT: Activate `pest-testing` every time you're working with a Pest or testing-related task.
|
- IMPORTANT: Activate `pest-testing` every time you're working with a Pest or testing-related task.
|
||||||
|
|
||||||
|
=== tailwindcss/core rules ===
|
||||||
|
|
||||||
|
# Tailwind CSS
|
||||||
|
|
||||||
|
- Always use existing Tailwind conventions; check project patterns before adding new ones.
|
||||||
|
- IMPORTANT: Always use `search-docs` tool for version-specific Tailwind CSS documentation and updated code examples. Never rely on training data.
|
||||||
|
- IMPORTANT: Activate `tailwindcss-development` every time you're working with a Tailwind CSS or styling-related task.
|
||||||
</laravel-boost-guidelines>
|
</laravel-boost-guidelines>
|
||||||
|
|||||||
69
.cursor/rules/update-documentation.mdc
Normal file
69
.cursor/rules/update-documentation.mdc
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Update Documentation
|
||||||
|
|
||||||
|
Quand l'utilisateur dit **"update documentation"**, tu DOIS mettre a jour le fichier `documentation/documentation_api_logistics.md` en suivant cette procedure.
|
||||||
|
|
||||||
|
## Procedure de mise a jour
|
||||||
|
|
||||||
|
1. **Lire les sources suivantes** (dans cet ordre) :
|
||||||
|
- `app/Services/LogisticsService.php` : toutes les methodes publiques = endpoints disponibles. Les PHPDoc `@param` contiennent les parametres attendus.
|
||||||
|
- `config/logistics.php` : configuration de connexion (variables d'environnement, valeurs par defaut).
|
||||||
|
- `.env` : valeurs actuelles des variables de configuration.
|
||||||
|
- `documentation/documentation_api_logistics.md` : documentation existante a mettre a jour.
|
||||||
|
- `memory-bank/techContext.md` : contexte technique (tables, types de colonnes, endpoints connus).
|
||||||
|
|
||||||
|
2. **Identifier les changements** :
|
||||||
|
- Nouvelles methodes dans `LogisticsService` = nouveaux endpoints a documenter.
|
||||||
|
- Methodes supprimees = endpoints a retirer.
|
||||||
|
- Parametres modifies (PHPDoc `@param`) = mise a jour des tableaux de parametres.
|
||||||
|
- Nouvelles variables d'environnement dans `config/logistics.php` = mise a jour de la section pre-requis.
|
||||||
|
|
||||||
|
3. **Mettre a jour le fichier** en preservant strictement cette structure :
|
||||||
|
|
||||||
|
```
|
||||||
|
# Documentation API Logistics (Flex/ESI Gescom)
|
||||||
|
Derniere mise a jour : <date du jour>
|
||||||
|
|
||||||
|
## Table des matieres
|
||||||
|
## 1. Pre-requis
|
||||||
|
## 2. Comment effectuer des requetes
|
||||||
|
## 3. Structure de reponse
|
||||||
|
## 4. Tables et colonnes disponibles
|
||||||
|
## 5. Recuperation de donnees
|
||||||
|
### 5.1 Structure de la base de donnees (tables_list, column_list)
|
||||||
|
### 5.2 Articles (art_list, art_getstk)
|
||||||
|
### 5.3 Journaux (jnl_list)
|
||||||
|
### 5.4 Documents (document_list, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail)
|
||||||
|
### 5.5 Tiers (third_list, third_GetArtHistory)
|
||||||
|
### 5.6 Divers (getserialnumber, codes_list)
|
||||||
|
## 6. Envoi de donnees
|
||||||
|
### 6.1 Ajout d'un document (document_add)
|
||||||
|
### 6.2 Modification d'un document (document_mod)
|
||||||
|
## 7. Endpoints non fonctionnels
|
||||||
|
## 8. Relations entre entites
|
||||||
|
## 9. Remarques et points d'attention
|
||||||
|
## 10. Ressources externes
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Pour chaque endpoint, documenter** :
|
||||||
|
- Description fonctionnelle (a quoi il sert).
|
||||||
|
- URL au format `POST /{dossier}/{endpoint}`.
|
||||||
|
- Methode service correspondante (`LogisticsService::methode()`).
|
||||||
|
- Tableau des parametres : nom, type, obligatoire (Oui/Non), description detaillee.
|
||||||
|
- Exemple de requete (body JSON).
|
||||||
|
- Exemple de reponse si disponible.
|
||||||
|
|
||||||
|
5. **Classer les endpoints** :
|
||||||
|
- Section 5 (Recuperation) : endpoints qui lisent des donnees (toutes les methodes sauf `documentAdd` et `documentMod`).
|
||||||
|
- Section 6 (Envoi) : endpoints qui creent ou modifient des donnees (`documentAdd`, `documentMod`).
|
||||||
|
- Section 7 : endpoints identifies mais non fonctionnels.
|
||||||
|
|
||||||
|
6. **Mettre a jour la date** en haut du fichier (`Derniere mise a jour : <date du jour>`).
|
||||||
|
|
||||||
|
## Regles
|
||||||
|
|
||||||
|
- Ne jamais supprimer d'information existante sans raison (endpoint supprime du service).
|
||||||
|
- Ton factuel et concis, sans emojis.
|
||||||
|
- Toujours inclure les chemins de fichiers exacts dans les references.
|
||||||
|
- Les exemples de requete doivent utiliser des valeurs realistes.
|
||||||
|
- La table des matieres doit refleter les sections du document.
|
||||||
|
- Les endpoints non fonctionnels restent documentes avec le statut "Non fonctionnel" et la description du probleme.
|
||||||
124
.cursor/skills/tailwindcss-development/SKILL.md
Normal file
124
.cursor/skills/tailwindcss-development/SKILL.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
name: tailwindcss-development
|
||||||
|
description: >-
|
||||||
|
Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components,
|
||||||
|
working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors,
|
||||||
|
typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle,
|
||||||
|
hero section, cards, buttons, or any visual/UI changes.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tailwind CSS Development
|
||||||
|
|
||||||
|
## When to Apply
|
||||||
|
|
||||||
|
Activate this skill when:
|
||||||
|
|
||||||
|
- Adding styles to components or pages
|
||||||
|
- Working with responsive design
|
||||||
|
- Implementing dark mode
|
||||||
|
- Extracting repeated patterns into components
|
||||||
|
- Debugging spacing or layout issues
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Use `search-docs` for detailed Tailwind CSS v4 patterns and documentation.
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
- Use Tailwind CSS classes to style HTML. Check and follow existing Tailwind conventions in the project before introducing new patterns.
|
||||||
|
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
|
||||||
|
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
|
||||||
|
|
||||||
|
## Tailwind CSS v4 Specifics
|
||||||
|
|
||||||
|
- Always use Tailwind CSS v4 and avoid deprecated utilities.
|
||||||
|
- `corePlugins` is not supported in Tailwind v4.
|
||||||
|
|
||||||
|
### CSS-First Configuration
|
||||||
|
|
||||||
|
In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed:
|
||||||
|
|
||||||
|
<code-snippet name="CSS-First Config" lang="css">
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.72 0.11 178);
|
||||||
|
}
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Import Syntax
|
||||||
|
|
||||||
|
In Tailwind v4, import Tailwind with a regular CSS `@import` statement instead of the `@tailwind` directives used in v3:
|
||||||
|
|
||||||
|
<code-snippet name="v4 Import Syntax" lang="diff">
|
||||||
|
- @tailwind base;
|
||||||
|
- @tailwind components;
|
||||||
|
- @tailwind utilities;
|
||||||
|
+ @import "tailwindcss";
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Replaced Utilities
|
||||||
|
|
||||||
|
Tailwind v4 removed deprecated utilities. Use the replacements shown below. Opacity values remain numeric.
|
||||||
|
|
||||||
|
| Deprecated | Replacement |
|
||||||
|
|------------|-------------|
|
||||||
|
| bg-opacity-* | bg-black/* |
|
||||||
|
| text-opacity-* | text-black/* |
|
||||||
|
| border-opacity-* | border-black/* |
|
||||||
|
| divide-opacity-* | divide-black/* |
|
||||||
|
| ring-opacity-* | ring-black/* |
|
||||||
|
| placeholder-opacity-* | placeholder-black/* |
|
||||||
|
| flex-shrink-* | shrink-* |
|
||||||
|
| flex-grow-* | grow-* |
|
||||||
|
| overflow-ellipsis | text-ellipsis |
|
||||||
|
| decoration-slice | box-decoration-slice |
|
||||||
|
| decoration-clone | box-decoration-clone |
|
||||||
|
|
||||||
|
## Spacing
|
||||||
|
|
||||||
|
Use `gap` utilities instead of margins for spacing between siblings:
|
||||||
|
|
||||||
|
<code-snippet name="Gap Utilities" lang="html">
|
||||||
|
<div class="flex gap-8">
|
||||||
|
<div>Item 1</div>
|
||||||
|
<div>Item 2</div>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
## Dark Mode
|
||||||
|
|
||||||
|
If existing pages and components support dark mode, new pages and components must support it the same way, typically using the `dark:` variant:
|
||||||
|
|
||||||
|
<code-snippet name="Dark Mode" lang="html">
|
||||||
|
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
||||||
|
Content adapts to color scheme
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Flexbox Layout
|
||||||
|
|
||||||
|
<code-snippet name="Flexbox Layout" lang="html">
|
||||||
|
<div class="flex items-center justify-between gap-4">
|
||||||
|
<div>Left content</div>
|
||||||
|
<div>Right content</div>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Grid Layout
|
||||||
|
|
||||||
|
<code-snippet name="Grid Layout" lang="html">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<div>Card 1</div>
|
||||||
|
<div>Card 2</div>
|
||||||
|
<div>Card 3</div>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
- Using deprecated v3 utilities (bg-opacity-*, flex-shrink-*, etc.)
|
||||||
|
- Using `@tailwind` directives instead of `@import "tailwindcss"`
|
||||||
|
- Trying to use `tailwind.config.js` instead of CSS `@theme` directive
|
||||||
|
- Using margins for spacing between siblings instead of gap utilities
|
||||||
|
- Forgetting to add dark mode variants when the project uses dark mode
|
||||||
34
README.md
34
README.md
@@ -1,14 +1,13 @@
|
|||||||
# API Logistics
|
# API Logistics
|
||||||
|
|
||||||
Application Laravel 12 de test pour comprendre et documenter l'API Logistics (Flex/ESI Gescom). Elle fournit un dashboard Filament v5 permettant d'interroger les differents endpoints de l'API.
|
Application Laravel 12 de test pour comprendre et documenter l'API Logistics (Flex/ESI Gescom). Elle fournit un dashboard Filament v5 permettant d'interroger les différents endpoints de l'API.
|
||||||
|
|
||||||
## Prerequis
|
## Prérequis
|
||||||
|
|
||||||
- PHP 8.4+
|
- PHP 8.4+
|
||||||
- Composer
|
- Composer
|
||||||
- Node.js et npm
|
- Node.js et npm
|
||||||
- MySQL
|
- MySQL
|
||||||
- Laravel Herd (recommande)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -23,9 +22,9 @@ php artisan key:generate
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Base de donnees
|
### Base de données
|
||||||
|
|
||||||
Creer une base de donnees MySQL nommee `api_logistics`, puis configurer le fichier `.env` :
|
Créer une base de données MySQL nommée `api_logistics`, puis configurer le fichier `.env` :
|
||||||
|
|
||||||
```
|
```
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
@@ -36,7 +35,7 @@ DB_USERNAME=root
|
|||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
```
|
```
|
||||||
|
|
||||||
Executer les migrations :
|
Exécuter les migrations :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php artisan migrate
|
php artisan migrate
|
||||||
@@ -44,7 +43,7 @@ php artisan migrate
|
|||||||
|
|
||||||
### API Logistics
|
### API Logistics
|
||||||
|
|
||||||
Configurer la connexion a l'API Logistics dans le fichier `.env` :
|
Configurer la connexion à l'API Logistics dans le fichier `.env` :
|
||||||
|
|
||||||
```
|
```
|
||||||
LOGISTICS_API_BASE_URL=http://tse-10-test.esiweb.pro
|
LOGISTICS_API_BASE_URL=http://tse-10-test.esiweb.pro
|
||||||
@@ -53,40 +52,41 @@ LOGISTICS_API_FOLDER=esigescom
|
|||||||
```
|
```
|
||||||
|
|
||||||
- **LOGISTICS_API_BASE_URL** : URL de base du serveur Logistics
|
- **LOGISTICS_API_BASE_URL** : URL de base du serveur Logistics
|
||||||
- **LOGISTICS_API_KEY** : Cle API transmise via le header `X-API-KEY`
|
- **LOGISTICS_API_KEY** : Clé API transmise via le header `X-API-KEY`
|
||||||
- **LOGISTICS_API_FOLDER** : Nom du dossier (en minuscules) utilise dans les routes de l'API
|
- **LOGISTICS_API_FOLDER** : Nom du dossier (en minuscules) utilisé dans les routes de l'API
|
||||||
|
|
||||||
## Demarrage
|
## Démarrage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
L'application est disponible via Laravel Herd a l'adresse `http://api-logistics.test`.
|
L'application est disponible à l'adresse `http://api-logistics.test`.
|
||||||
|
|
||||||
Le dashboard Filament est accessible a l'adresse `http://api-logistics.test/admin`.
|
Le dashboard Filament est accessible à l'adresse `http://api-logistics.test/admin`.
|
||||||
|
|
||||||
## Structure du dashboard
|
## Structure du dashboard
|
||||||
|
|
||||||
Le dashboard Filament propose les pages suivantes :
|
Le dashboard Filament propose les pages suivantes :
|
||||||
|
|
||||||
|
- **Documentation** : Documentation de l'API Logistics
|
||||||
- **Tables** : Explorer les tables disponibles dans l'API et visualiser leurs colonnes
|
- **Tables** : Explorer les tables disponibles dans l'API et visualiser leurs colonnes
|
||||||
- **Articles** : Rechercher des articles et verifier le stock
|
- **Articles** : Rechercher des articles et vérifier le stock
|
||||||
- **Documents** : Lister des documents et consulter leurs details
|
- **Documents** : Lister des documents et consulter leurs détails
|
||||||
- **Journaux** : Rechercher et lister les journaux
|
- **Journaux** : Rechercher et lister les journaux
|
||||||
- **Tiers** : Rechercher des tiers et consulter l'historique des articles
|
- **Tiers** : Rechercher des tiers et consulter l'historique des articles
|
||||||
|
|
||||||
## Architecture technique
|
## Architecture technique
|
||||||
|
|
||||||
- `config/logistics.php` : Configuration de l'API Logistics
|
- `config/logistics.php` : Configuration de l'API Logistics
|
||||||
- `app/Services/LogisticsService.php` : Service centralise pour les appels HTTP vers l'API
|
- `app/Services/LogisticsService.php` : Service centralisé pour les appels HTTP vers l'API
|
||||||
- `app/Filament/Pages/` : Pages Filament du dashboard
|
- `app/Filament/Pages/` : Pages Filament du dashboard
|
||||||
- `database/migrations/` : Migrations incluant la table `api_request_logs` pour le suivi des requetes
|
- `database/migrations/` : Migrations incluant la table `api_request_logs` pour le suivi des requêtes
|
||||||
|
|
||||||
## Documentation de l'API
|
## Documentation de l'API
|
||||||
|
|
||||||
- [Documentation Postman](https://documenter.getpostman.com/view/40440561/2sB2qaj2Pz)
|
- [Documentation Postman](https://documenter.getpostman.com/view/40440561/2sB2qaj2Pz)
|
||||||
- Documentation interne : `documentation/WEB-A-1 (3).md`
|
- Documentation interne : `documentation/documentation_api_logistics.md`
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
|
|||||||
19
app/Filament/Pages/Dashboard.php
Normal file
19
app/Filament/Pages/Dashboard.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages;
|
||||||
|
|
||||||
|
use Filament\Pages\Dashboard as BaseDashboard;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
|
||||||
|
class Dashboard extends BaseDashboard
|
||||||
|
{
|
||||||
|
protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedHome;
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Accueil';
|
||||||
|
|
||||||
|
protected static ?string $title = 'API Logistics';
|
||||||
|
|
||||||
|
protected static ?int $navigationSort = 0;
|
||||||
|
|
||||||
|
protected string $view = 'filament.pages.dashboard';
|
||||||
|
}
|
||||||
47
app/Filament/Pages/Documentation.php
Normal file
47
app/Filament/Pages/Documentation.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages;
|
||||||
|
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Pages\Page;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Documentation extends Page
|
||||||
|
{
|
||||||
|
protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedBookOpen;
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Documentation';
|
||||||
|
|
||||||
|
protected static ?string $title = 'Documentation API';
|
||||||
|
|
||||||
|
protected static ?int $navigationSort = 0;
|
||||||
|
|
||||||
|
protected string $view = 'filament.pages.documentation';
|
||||||
|
|
||||||
|
public string $htmlContent = '';
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$markdownPath = base_path('documentation/documentation_api_logistics.md');
|
||||||
|
$markdown = file_get_contents($markdownPath);
|
||||||
|
$this->htmlContent = Str::markdown($markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Action::make('download')
|
||||||
|
->label('Télécharger en PDF')
|
||||||
|
->icon(Heroicon::OutlinedArrowDownTray)
|
||||||
|
->url(route('documentation.download-pdf'))
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
|
||||||
|
Action::make('see_in_another_tab')
|
||||||
|
->label('Voir dans un nouvel onglet')
|
||||||
|
->icon(Heroicon::OutlinedArrowTopRightOnSquare)
|
||||||
|
->url(Documentation::getUrl())
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,24 +23,75 @@ class TablesExplorer extends Page
|
|||||||
#[Url]
|
#[Url]
|
||||||
public string $selectedTable = '';
|
public string $selectedTable = '';
|
||||||
|
|
||||||
|
public string $tableFilter = '';
|
||||||
|
|
||||||
public array $tables = [];
|
public array $tables = [];
|
||||||
|
|
||||||
public array $columns = [];
|
public array $columns = [];
|
||||||
|
|
||||||
|
public ?array $tablesMetadata = null;
|
||||||
|
|
||||||
|
public ?array $columnsMetadata = null;
|
||||||
|
|
||||||
public ?string $errorMessage = null;
|
public ?string $errorMessage = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private static array $dataTypeLabels = [
|
||||||
|
'C' => 'Caractère',
|
||||||
|
'N' => 'Numérique',
|
||||||
|
'T' => 'Date/Heure',
|
||||||
|
'D' => 'Date',
|
||||||
|
'L' => 'Logique',
|
||||||
|
'M' => 'Mémo',
|
||||||
|
];
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->loadTables();
|
$this->loadTables();
|
||||||
|
|
||||||
|
if (filled($this->selectedTable)) {
|
||||||
|
$this->loadColumns();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadTables(): void
|
public function selectTable(string $tableName): void
|
||||||
|
{
|
||||||
|
$this->selectedTable = $tableName;
|
||||||
|
$this->loadColumns();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, array<string, mixed>>
|
||||||
|
*/
|
||||||
|
public function getFilteredTablesProperty(): array
|
||||||
|
{
|
||||||
|
if (blank($this->tableFilter)) {
|
||||||
|
return $this->tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter = mb_strtolower($this->tableFilter);
|
||||||
|
|
||||||
|
return array_values(array_filter(
|
||||||
|
$this->tables,
|
||||||
|
fn (array $table): bool => str_contains(mb_strtolower($table['name'] ?? ''), $filter),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDataTypeLabel(string $type): string
|
||||||
|
{
|
||||||
|
return self::$dataTypeLabels[strtoupper($type)] ?? $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadTables(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$service = app(LogisticsService::class);
|
$service = app(LogisticsService::class);
|
||||||
$response = $service->tablesList();
|
$response = $service->tablesList();
|
||||||
|
|
||||||
$this->tables = $response['data'] ?? [];
|
$this->tables = $response['data'] ?? [];
|
||||||
|
$this->tablesMetadata = $response['metadata'] ?? null;
|
||||||
$this->errorMessage = $response['error'] ?? null;
|
$this->errorMessage = $response['error'] ?? null;
|
||||||
} catch (LogisticsApiException $e) {
|
} catch (LogisticsApiException $e) {
|
||||||
$this->errorMessage = $e->getMessage();
|
$this->errorMessage = $e->getMessage();
|
||||||
@@ -49,10 +100,11 @@ class TablesExplorer extends Page
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadColumns(): void
|
private function loadColumns(): void
|
||||||
{
|
{
|
||||||
if (blank($this->selectedTable)) {
|
if (blank($this->selectedTable)) {
|
||||||
$this->columns = [];
|
$this->columns = [];
|
||||||
|
$this->columnsMetadata = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -61,12 +113,36 @@ class TablesExplorer extends Page
|
|||||||
$service = app(LogisticsService::class);
|
$service = app(LogisticsService::class);
|
||||||
$response = $service->columnList($this->selectedTable);
|
$response = $service->columnList($this->selectedTable);
|
||||||
|
|
||||||
$this->columns = $response['data'] ?? [];
|
$rawColumns = $response['data'] ?? [];
|
||||||
|
$this->columns = $this->deduplicateColumns($rawColumns);
|
||||||
|
$this->columnsMetadata = $response['metadata'] ?? null;
|
||||||
$this->errorMessage = $response['error'] ?? null;
|
$this->errorMessage = $response['error'] ?? null;
|
||||||
} catch (LogisticsApiException $e) {
|
} catch (LogisticsApiException $e) {
|
||||||
$this->errorMessage = $e->getMessage();
|
$this->errorMessage = $e->getMessage();
|
||||||
|
$this->columns = [];
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->errorMessage = "Erreur inattendue : {$e->getMessage()}";
|
$this->errorMessage = "Erreur inattendue : {$e->getMessage()}";
|
||||||
|
$this->columns = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, array<string, mixed>> $columns
|
||||||
|
* @return array<int, array<string, mixed>>
|
||||||
|
*/
|
||||||
|
private function deduplicateColumns(array $columns): array
|
||||||
|
{
|
||||||
|
$seen = [];
|
||||||
|
$unique = [];
|
||||||
|
|
||||||
|
foreach ($columns as $column) {
|
||||||
|
$key = ($column['name'] ?? '').'|'.($column['dataType'] ?? '');
|
||||||
|
if (! isset($seen[$key])) {
|
||||||
|
$seen[$key] = true;
|
||||||
|
$unique[] = $column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $unique;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Providers\Filament;
|
namespace App\Providers\Filament;
|
||||||
|
|
||||||
|
use App\Filament\Pages\Dashboard;
|
||||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
use Filament\Pages\Dashboard;
|
|
||||||
use Filament\Panel;
|
use Filament\Panel;
|
||||||
use Filament\PanelProvider;
|
use Filament\PanelProvider;
|
||||||
use Filament\Support\Colors\Color;
|
use Filament\Support\Colors\Color;
|
||||||
use Filament\Widgets\FilamentInfoWidget;
|
|
||||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||||
@@ -24,6 +23,7 @@ class AdminPanelProvider extends PanelProvider
|
|||||||
->default()
|
->default()
|
||||||
->id('admin')
|
->id('admin')
|
||||||
->path('admin')
|
->path('admin')
|
||||||
|
->viteTheme('resources/css/filament/admin/theme.css')
|
||||||
->brandName('API Logistics')
|
->brandName('API Logistics')
|
||||||
->colors([
|
->colors([
|
||||||
'primary' => Color::Blue,
|
'primary' => Color::Blue,
|
||||||
@@ -34,9 +34,7 @@ class AdminPanelProvider extends PanelProvider
|
|||||||
Dashboard::class,
|
Dashboard::class,
|
||||||
])
|
])
|
||||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
|
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
|
||||||
->widgets([
|
->widgets([])
|
||||||
FilamentInfoWidget::class,
|
|
||||||
])
|
|
||||||
->middleware([
|
->middleware([
|
||||||
EncryptCookies::class,
|
EncryptCookies::class,
|
||||||
AddQueuedCookiesToResponse::class,
|
AddQueuedCookiesToResponse::class,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"skills": [
|
"skills": [
|
||||||
"fluxui-development",
|
"fluxui-development",
|
||||||
"livewire-development",
|
"livewire-development",
|
||||||
"pest-testing"
|
"pest-testing",
|
||||||
|
"tailwindcss-development"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"barryvdh/laravel-dompdf": "^3.1",
|
||||||
"filament/filament": "5.0",
|
"filament/filament": "5.0",
|
||||||
"laravel/fortify": "^1.30",
|
"laravel/fortify": "^1.30",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
|
|||||||
451
composer.lock
generated
451
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "72e464a39ce3e36d3ef8c75498225c48",
|
"content-hash": "3cb29f1ae8d0f5968aae9270bea812f0",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anourvalar/eloquent-serialize",
|
"name": "anourvalar/eloquent-serialize",
|
||||||
@@ -127,6 +127,83 @@
|
|||||||
},
|
},
|
||||||
"time": "2025-11-19T17:15:36+00:00"
|
"time": "2025-11-19T17:15:36+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "barryvdh/laravel-dompdf",
|
||||||
|
"version": "v3.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/barryvdh/laravel-dompdf.git",
|
||||||
|
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
|
||||||
|
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/dompdf": "^3.0",
|
||||||
|
"illuminate/support": "^9|^10|^11|^12",
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"larastan/larastan": "^2.7|^3.0",
|
||||||
|
"orchestra/testbench": "^7|^8|^9|^10",
|
||||||
|
"phpro/grumphp": "^2.5",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"aliases": {
|
||||||
|
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
|
||||||
|
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
|
||||||
|
},
|
||||||
|
"providers": [
|
||||||
|
"Barryvdh\\DomPDF\\ServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Barryvdh\\DomPDF\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Barry vd. Heuvel",
|
||||||
|
"email": "barryvdh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A DOMPDF Wrapper for Laravel",
|
||||||
|
"keywords": [
|
||||||
|
"dompdf",
|
||||||
|
"laravel",
|
||||||
|
"pdf"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
|
||||||
|
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://fruitcake.nl",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/barryvdh",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-02-13T15:07:54+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "blade-ui-kit/blade-heroicons",
|
"name": "blade-ui-kit/blade-heroicons",
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
@@ -962,6 +1039,161 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-02-05T11:56:58+00:00"
|
"time": "2024-02-05T11:56:58+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"version": "v3.1.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/dompdf.git",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||||
|
"source": "https://github.com/dompdf/dompdf/tree/v3.1.4"
|
||||||
|
},
|
||||||
|
"time": "2025-10-29T12:43:30+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-font-lib",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||||
|
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a",
|
||||||
|
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FontLib\\": "src/FontLib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The FontLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.2"
|
||||||
|
},
|
||||||
|
"time": "2026-01-20T14:10:26+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-svg-lib",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||||
|
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1",
|
||||||
|
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"sabberworm/php-css-parser": "^8.4 || ^9.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Svg\\": "src/Svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The SvgLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse and export to PDF SVG files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2"
|
||||||
|
},
|
||||||
|
"time": "2026-01-02T16:01:13+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dragonmantank/cron-expression",
|
"name": "dragonmantank/cron-expression",
|
||||||
"version": "v3.6.0",
|
"version": "v3.6.0",
|
||||||
@@ -5305,6 +5537,80 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-02-25T09:09:36+00:00"
|
"time": "2025-02-25T09:09:36+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "sabberworm/php-css-parser",
|
||||||
|
"version": "v9.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||||
|
"reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb",
|
||||||
|
"reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||||
|
"thecodingmachine/safe": "^1.3 || ^2.5 || ^3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-parallel-lint/php-parallel-lint": "1.4.0",
|
||||||
|
"phpstan/extension-installer": "1.4.3",
|
||||||
|
"phpstan/phpstan": "1.12.28 || 2.1.25",
|
||||||
|
"phpstan/phpstan-phpunit": "1.4.2 || 2.0.7",
|
||||||
|
"phpstan/phpstan-strict-rules": "1.6.2 || 2.0.6",
|
||||||
|
"phpunit/phpunit": "8.5.46",
|
||||||
|
"rawr/phpunit-data-provider": "3.3.1",
|
||||||
|
"rector/rector": "1.2.10 || 2.1.7",
|
||||||
|
"rector/type-perfect": "1.0.0 || 2.1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "9.2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabberworm\\CSS\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Raphael Schweikert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oliver Klee",
|
||||||
|
"email": "github@oliverklee.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jake Hotson",
|
||||||
|
"email": "jake.github@qzdesign.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Parser for CSS Files written in PHP",
|
||||||
|
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"parser",
|
||||||
|
"stylesheet"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
|
||||||
|
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.1.0"
|
||||||
|
},
|
||||||
|
"time": "2025-09-14T07:37:21+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "scrivo/highlight.php",
|
"name": "scrivo/highlight.php",
|
||||||
"version": "v9.18.1.10",
|
"version": "v9.18.1.10",
|
||||||
@@ -8134,6 +8440,149 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-01-01T22:13:48+00:00"
|
"time": "2026-01-01T22:13:48+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "thecodingmachine/safe",
|
||||||
|
"version": "v3.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thecodingmachine/safe.git",
|
||||||
|
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
|
||||||
|
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||||
|
"phpstan/phpstan": "^2",
|
||||||
|
"phpunit/phpunit": "^10",
|
||||||
|
"squizlabs/php_codesniffer": "^3.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"lib/special_cases.php",
|
||||||
|
"generated/apache.php",
|
||||||
|
"generated/apcu.php",
|
||||||
|
"generated/array.php",
|
||||||
|
"generated/bzip2.php",
|
||||||
|
"generated/calendar.php",
|
||||||
|
"generated/classobj.php",
|
||||||
|
"generated/com.php",
|
||||||
|
"generated/cubrid.php",
|
||||||
|
"generated/curl.php",
|
||||||
|
"generated/datetime.php",
|
||||||
|
"generated/dir.php",
|
||||||
|
"generated/eio.php",
|
||||||
|
"generated/errorfunc.php",
|
||||||
|
"generated/exec.php",
|
||||||
|
"generated/fileinfo.php",
|
||||||
|
"generated/filesystem.php",
|
||||||
|
"generated/filter.php",
|
||||||
|
"generated/fpm.php",
|
||||||
|
"generated/ftp.php",
|
||||||
|
"generated/funchand.php",
|
||||||
|
"generated/gettext.php",
|
||||||
|
"generated/gmp.php",
|
||||||
|
"generated/gnupg.php",
|
||||||
|
"generated/hash.php",
|
||||||
|
"generated/ibase.php",
|
||||||
|
"generated/ibmDb2.php",
|
||||||
|
"generated/iconv.php",
|
||||||
|
"generated/image.php",
|
||||||
|
"generated/imap.php",
|
||||||
|
"generated/info.php",
|
||||||
|
"generated/inotify.php",
|
||||||
|
"generated/json.php",
|
||||||
|
"generated/ldap.php",
|
||||||
|
"generated/libxml.php",
|
||||||
|
"generated/lzf.php",
|
||||||
|
"generated/mailparse.php",
|
||||||
|
"generated/mbstring.php",
|
||||||
|
"generated/misc.php",
|
||||||
|
"generated/mysql.php",
|
||||||
|
"generated/mysqli.php",
|
||||||
|
"generated/network.php",
|
||||||
|
"generated/oci8.php",
|
||||||
|
"generated/opcache.php",
|
||||||
|
"generated/openssl.php",
|
||||||
|
"generated/outcontrol.php",
|
||||||
|
"generated/pcntl.php",
|
||||||
|
"generated/pcre.php",
|
||||||
|
"generated/pgsql.php",
|
||||||
|
"generated/posix.php",
|
||||||
|
"generated/ps.php",
|
||||||
|
"generated/pspell.php",
|
||||||
|
"generated/readline.php",
|
||||||
|
"generated/rnp.php",
|
||||||
|
"generated/rpminfo.php",
|
||||||
|
"generated/rrd.php",
|
||||||
|
"generated/sem.php",
|
||||||
|
"generated/session.php",
|
||||||
|
"generated/shmop.php",
|
||||||
|
"generated/sockets.php",
|
||||||
|
"generated/sodium.php",
|
||||||
|
"generated/solr.php",
|
||||||
|
"generated/spl.php",
|
||||||
|
"generated/sqlsrv.php",
|
||||||
|
"generated/ssdeep.php",
|
||||||
|
"generated/ssh2.php",
|
||||||
|
"generated/stream.php",
|
||||||
|
"generated/strings.php",
|
||||||
|
"generated/swoole.php",
|
||||||
|
"generated/uodbc.php",
|
||||||
|
"generated/uopz.php",
|
||||||
|
"generated/url.php",
|
||||||
|
"generated/var.php",
|
||||||
|
"generated/xdiff.php",
|
||||||
|
"generated/xml.php",
|
||||||
|
"generated/xmlrpc.php",
|
||||||
|
"generated/yaml.php",
|
||||||
|
"generated/yaz.php",
|
||||||
|
"generated/zip.php",
|
||||||
|
"generated/zlib.php"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"lib/DateTime.php",
|
||||||
|
"lib/DateTimeImmutable.php",
|
||||||
|
"lib/Exceptions/",
|
||||||
|
"generated/Exceptions/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thecodingmachine/safe/issues",
|
||||||
|
"source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/OskarStark",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/shish",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/silasjoisten",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/staabm",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-02-04T18:08:13+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "tijsverkoyen/css-to-inline-styles",
|
"name": "tijsverkoyen/css-to-inline-styles",
|
||||||
"version": "v2.4.0",
|
"version": "v2.4.0",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,28 @@
|
|||||||
# Memory Bank
|
# Memory Bank
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Presentation
|
## Présentation
|
||||||
|
|
||||||
Ce dossier contient le Memory Bank du projet API Logistics. Il sert de source de verite pour que l'IA (Cursor) conserve le contexte du projet entre les sessions.
|
Ce dossier contient le Memory Bank du projet API Logistics. Il sert de source de vérité pour que l'IA (Cursor) conserve le contexte du projet entre les sessions.
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
| Fichier | Description |
|
| Fichier | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `projectbrief.md` | Vision, objectifs et perimetre du projet |
|
| `projectbrief.md` | Vision, objectifs et périmètre du projet |
|
||||||
| `productContext.md` | Contexte produit, problemes resolus, experience utilisateur |
|
| `productContext.md` | Contexte produit, problèmes résolus, expérience utilisateur |
|
||||||
| `techContext.md` | Stack technique, API Logistics, dependances, configuration |
|
| `techContext.md` | Stack technique, API Logistics, dépendances, configuration |
|
||||||
| `systemPatterns.md` | Architecture, patterns, structure des repertoires, conventions |
|
| `systemPatterns.md` | Architecture, patterns, structure des répertoires, conventions, système de design |
|
||||||
| `activeContext.md` | Travail en cours, decisions recentes, prochaines etapes |
|
| `activeContext.md` | Travail en cours, décisions récentes, prochaines étapes |
|
||||||
| `progress.md` | Avancement, ce qui fonctionne, ce qui reste a faire, metriques |
|
| `progress.md` | Avancement, ce qui fonctionne, ce qui reste à faire, métriques |
|
||||||
|
|
||||||
## Utilisation
|
## Utilisation
|
||||||
|
|
||||||
- **Lecture automatique** : La regle Cursor `.cursor/rules/memory-bank.mdc` est configuree avec `alwaysApply: true`. L'IA lit ces fichiers a chaque session.
|
- **Lecture automatique** : La règle Cursor `.cursor/rules/memory-bank.mdc` est configurée avec `alwaysApply: true`. L'IA lit ces fichiers à chaque session.
|
||||||
- **Mise a jour** : Dire **"update memory bank"** dans le chat pour que l'IA relise le code source et mette a jour tous les fichiers.
|
- **Mise à jour** : Dire **"update memory bank"** dans le chat pour que l'IA relise le code source et mette à jour tous les fichiers.
|
||||||
- **Quand mettre a jour** : Apres chaque changement significatif (nouvelle fonctionnalite, changement d'architecture, correction de bug, nouvelle dependance).
|
- **Quand mettre à jour** : Après chaque changement significatif (nouvelle fonctionnalité, changement d'architecture, correction de bug, nouvelle dépendance).
|
||||||
|
|
||||||
|
## Convention d'écriture
|
||||||
|
|
||||||
|
Tous les fichiers du projet (documentation, memory bank, règles Cursor) doivent être rédigés en français avec les accents appropriés.
|
||||||
|
|||||||
@@ -1,44 +1,79 @@
|
|||||||
# Active Context
|
# Active Context
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Travail en cours
|
## Travail en cours
|
||||||
|
|
||||||
Aucun travail en cours. Les ameliorations de robustesse du service API sont terminees.
|
Aucun travail en cours.
|
||||||
|
|
||||||
## Decisions recentes
|
## Décisions récentes
|
||||||
|
|
||||||
- **Filament v5 sans authentification** : Le `AdminPanelProvider` a ete configure sans `->login()` et sans `authMiddleware` pour permettre un acces libre au dashboard.
|
- **Convention d'écriture avec accents** (2026-02-20) : Tous les contenus rédigés en français (documentation, memory bank, règles Cursor) doivent utiliser les accents appropriés. La documentation API et le memory bank ont été entièrement réécrits avec les accents.
|
||||||
- **Pages personnalisees plutot que Resources** : L'application interroge une API externe, il n'y a pas de modeles Eloquent a gerer en CRUD. Les pages Filament utilisent des vues Blade avec des formulaires Livewire.
|
- **Page Documentation ajoutée** (2026-02-20) : Nouvelle page Filament `Documentation` qui affiche le fichier markdown `documentation/documentation_api_logistics.md` converti en HTML via `Str::markdown()`. Actions d'en-tête : télécharger en PDF et ouvrir dans un nouvel onglet.
|
||||||
- **MySQL au lieu de SQLite** : Choix de l'utilisateur pour la base de donnees.
|
- **Styles prose personnalisés** (2026-02-20) : Le thème CSS Filament (`theme.css`) a été enrichi avec des styles `.documentation-prose` dédiés au rendu du markdown en dark mode : hiérarchie de titres avec bordures, tableaux avec bordures et en-têtes stylisés, blocs de code avec fond sombre, code inline coloré, liens bleus, listes à marqueurs, séparateurs visibles.
|
||||||
- **LogisticsService** : Toutes les interactions avec l'API sont centralisees dans un seul service pour faciliter la maintenance et le tracage.
|
- **Plugin @tailwindcss/typography** (2026-02-20) : Ajout du plugin via `@plugin "@tailwindcss/typography"` dans le thème Filament pour activer les classes `prose`.
|
||||||
|
- **Export PDF de la documentation** (2026-02-20) : Route `documentation.download-pdf` dans `routes/web.php` utilisant `barryvdh/laravel-dompdf` pour générer un PDF téléchargeable de la documentation.
|
||||||
|
- **Règle update-documentation** (2026-02-20) : Nouvelle règle Cursor `.cursor/rules/update-documentation.mdc` définissant la procédure de mise à jour de la documentation quand l'utilisateur dit "update documentation".
|
||||||
|
- **Filament v5 sans authentification** : Le `AdminPanelProvider` a été configuré sans `->login()` et sans `authMiddleware` pour permettre un accès libre au dashboard.
|
||||||
|
- **Pages personnalisées plutôt que Resources** : L'application interroge une API externe, il n'y a pas de modèles Eloquent à gérer en CRUD.
|
||||||
|
- **MySQL au lieu de SQLite** : Choix de l'utilisateur pour la base de données.
|
||||||
|
- **LogisticsService** : Toutes les interactions avec l'API sont centralisées dans un seul service.
|
||||||
- **Heroicon enum** : Filament v5 impose l'utilisation de `BackedEnum` pour `$navigationIcon` au lieu de strings.
|
- **Heroicon enum** : Filament v5 impose l'utilisation de `BackedEnum` pour `$navigationIcon` au lieu de strings.
|
||||||
- **$view non-static** : Filament v5 a change `$view` de static a instance property.
|
- **$view non-static** : Filament v5 a changé `$view` de static à instance property.
|
||||||
- **Timeout et retry configurables** (2026-02-20) : Les parametres `timeout`, `connect_timeout`, `retry.times` et `retry.sleep_ms` sont desormais dans `config/logistics.php` et pilotes par des variables `.env`. Le retry ne se declenche que sur les `ConnectionException`.
|
- **Timeout et retry configurables** : Les paramètres sont dans `config/logistics.php` et pilotés par `.env`.
|
||||||
- **LogisticsApiException** (2026-02-20) : Exception dediee creee pour distinguer les erreurs de connexion (API injoignable) des erreurs de requete generiques. Messages en francais.
|
- **LogisticsApiException** : Exception dédiée créée pour distinguer les erreurs de connexion des erreurs de requête génériques.
|
||||||
- **Logging des echecs** (2026-02-20) : Les requetes echouees sont desormais aussi enregistrees dans `api_request_logs` avec `response_status = 0`.
|
- **Logging des échecs** : Les requêtes échouées sont aussi enregistrées dans `api_request_logs` avec `response_status = 0`.
|
||||||
- **Contrainte reseau** (2026-02-20) : Le serveur API `tse-10-test.esiweb.pro` est sur un reseau prive, accessible uniquement via Bureau a distance (RDP). L'application locale ne peut pas joindre l'API sans tunnel ou deploiement sur le reseau distant.
|
- **Système de design unifié** (2026-02-20) : Création de 10 composants Blade réutilisables dans `resources/views/components/logistics/` et d'une convention documentée dans `.cursor/rules/design-system.mdc`.
|
||||||
|
- **Thème Filament personnalisé** (2026-02-20) : Création de `resources/css/filament/admin/theme.css` enregistré dans `AdminPanelProvider` via `->viteTheme()`.
|
||||||
|
- **TablesExplorer amélioré** (2026-02-20) : Remplacement de `wire:then` (invalide) par une méthode `selectTable()`. Ajout de la déduplication des colonnes, d'un filtre de tables, de la propriété computed `filteredTables`, des labels de type (`getDataTypeLabel`), et du stockage des métadonnées.
|
||||||
|
- **Connectivité API résolue** (2026-02-20) : Le serveur API est accessible via `http://tse-10-test.esi.local` (réseau interne). Le timeout a été augmenté à 300s dans `.env`.
|
||||||
|
|
||||||
## Changements importants (2026-02-20)
|
## Changements récents (2026-02-20, session documentation)
|
||||||
|
|
||||||
- `LogisticsService` mis a jour : timeout, connectTimeout, retry, gestion d'erreur avec `LogisticsApiException`.
|
- Page Filament `Documentation` créée (`app/Filament/Pages/Documentation.php`).
|
||||||
- `LogisticsApiException` creee dans `app/Exceptions/`.
|
- Vue Blade `resources/views/filament/pages/documentation.blade.php` créée.
|
||||||
- `config/logistics.php` etendu avec timeout et retry.
|
- Documentation markdown réécrite intégralement avec accents français.
|
||||||
- `.env` et `.env.example` completes avec les nouvelles variables.
|
- Styles CSS `.documentation-prose` ajoutés dans `theme.css` (titres, tableaux, code, liens, listes).
|
||||||
- Les 5 pages Filament mises a jour pour attraper `LogisticsApiException`.
|
- Plugin `@tailwindcss/typography` activé dans le thème Filament.
|
||||||
- Tests passes de 8 a 12 (4 nouveaux tests pour timeout, exception, logging, contexte).
|
- Route PDF (`documentation.download-pdf`) ajoutée dans `routes/web.php`.
|
||||||
|
- Template PDF (`resources/views/pdf/documentation.blade.php`) créé.
|
||||||
|
- 5 tests Pest créés pour la page Documentation (`tests/Feature/DocumentationTest.php`).
|
||||||
|
- Règle Cursor `update-documentation.mdc` créée.
|
||||||
|
- Memory bank entièrement réécrit avec accents français.
|
||||||
|
- Total : 61 tests passent (165 assertions).
|
||||||
|
|
||||||
## Historique (2026-02-19)
|
## Historique
|
||||||
|
|
||||||
- Installation de Filament v5.0.0 (31 packages ajoutes).
|
### 2026-02-20 (session design)
|
||||||
- 5 pages Filament creees : TablesExplorer, Articles, Documents, Journaux, Tiers.
|
|
||||||
- `LogisticsService` cree avec 17 endpoints.
|
|
||||||
- Migration `api_request_logs` creee.
|
|
||||||
- 8 tests Pest ecrits et valides.
|
|
||||||
|
|
||||||
## Prochaines etapes
|
- 10 composants Blade créés dans `resources/views/components/logistics/`.
|
||||||
|
- Convention de design documentée dans `.cursor/rules/design-system.mdc`.
|
||||||
|
- 5 pages Filament refactorisées pour utiliser les composants du système de design.
|
||||||
|
- `TablesExplorer.php` amélioré : `selectTable()`, déduplication, filtre, computed property, métadonnées, labels de types.
|
||||||
|
- Thème Filament personnalisé créé (`resources/css/filament/admin/theme.css`).
|
||||||
|
- `AdminPanelProvider.php` mis à jour avec `->viteTheme()`.
|
||||||
|
- 6 tests Pest créés pour `TablesExplorer` (Livewire).
|
||||||
|
|
||||||
- Deployer l'application sur le reseau distant (serveur accessible via RDP) ou mettre en place un tunnel SSH/VPN pour que l'application puisse joindre l'API.
|
### 2026-02-20 (session robustesse)
|
||||||
- Tester le dashboard avec de vraies donnees API une fois la connectivite reseau resolue.
|
|
||||||
- Eventuellement : ajouter des pages pour les endpoints d'ecriture (document_add, document_mod).
|
- `LogisticsService` mis à jour : timeout, connectTimeout, retry, gestion d'erreur avec `LogisticsApiException`.
|
||||||
- Eventuellement : ameliorer l'affichage des resultats (pagination, formatage).
|
- `LogisticsApiException` créée dans `app/Exceptions/`.
|
||||||
|
- `config/logistics.php` étendu avec timeout et retry.
|
||||||
|
- `.env` et `.env.example` complétés avec les nouvelles variables.
|
||||||
|
- Les 5 pages Filament mises à jour pour attraper `LogisticsApiException`.
|
||||||
|
- Tests passés de 8 à 12.
|
||||||
|
|
||||||
|
### 2026-02-19
|
||||||
|
|
||||||
|
- Installation de Filament v5.0.0 (31 packages ajoutés).
|
||||||
|
- 5 pages Filament créées : TablesExplorer, Articles, Documents, Journaux, Tiers.
|
||||||
|
- `LogisticsService` créé avec 17 endpoints.
|
||||||
|
- Migration `api_request_logs` créée.
|
||||||
|
- 8 tests Pest écrits et validés.
|
||||||
|
|
||||||
|
## Prochaines étapes
|
||||||
|
|
||||||
|
- Tester toutes les pages avec de vraies données API et vérifier le rendu visuel.
|
||||||
|
- Éventuellement : ajouter des pages pour les endpoints d'écriture (document_add, document_mod).
|
||||||
|
- Éventuellement : ajouter de la pagination ou du tri côté client pour les grands tableaux.
|
||||||
|
- Éventuellement : ajouter une page de consultation des logs API.
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
# Product Context
|
# Product Context
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Pourquoi ce projet existe
|
## Pourquoi ce projet existe
|
||||||
|
|
||||||
L'API Logistics (Flex/ESI Gescom) est un systeme de gestion commerciale accessible via une API REST. La documentation officielle est limitee. Ce projet a ete cree pour :
|
L'API Logistics (Flex/ESI Gescom) est un système de gestion commerciale accessible via une API REST. La documentation officielle est limitée. Ce projet a été créé pour :
|
||||||
|
|
||||||
- Explorer les endpoints disponibles de maniere interactive.
|
- Explorer les endpoints disponibles de manière interactive.
|
||||||
- Comprendre les parametres attendus et les formats de reponse.
|
- Comprendre les paramètres attendus et les formats de réponse.
|
||||||
- Servir de base pour une documentation plus complete.
|
- Servir de base pour une documentation plus complète.
|
||||||
|
|
||||||
## Problemes resolus
|
## Problèmes résolus
|
||||||
|
|
||||||
- **Exploration de l'API** : Le dashboard permet de tester chaque endpoint avec des parametres personnalisables, sans avoir besoin de Postman.
|
- **Exploration de l'API** : Le dashboard permet de tester chaque endpoint avec des paramètres personnalisables, sans avoir besoin de Postman.
|
||||||
- **Comprehension de la structure** : La page "Tables" permet de decouvrir les tables et colonnes disponibles dans l'API.
|
- **Compréhension de la structure** : La page "Tables" permet de découvrir les tables et colonnes disponibles dans l'API, avec déduplication automatique des colonnes retournées en double par l'API.
|
||||||
- **Tracabilite** : Chaque requete effectuee (reussie ou echouee) est enregistree dans `api_request_logs` pour pouvoir analyser les echanges.
|
- **Documentation intégrée** : La page "Documentation" affiche le markdown de la documentation API avec un rendu stylisé (typographie, tableaux, blocs de code) et propose un export PDF.
|
||||||
- **Resilience** : Les erreurs de connexion sont gerees avec retry automatique et messages explicites en francais.
|
- **Traçabilité** : Chaque requête effectuée (réussie ou échouée) est enregistrée dans `api_request_logs` pour pouvoir analyser les échanges.
|
||||||
|
- **Résilience** : Les erreurs de connexion sont gérées avec retry automatique et messages explicites en français.
|
||||||
|
- **Cohérence visuelle** : Un système de design unifié (composants `x-logistics.*`) garantit une présentation homogène sur toutes les pages.
|
||||||
|
|
||||||
## Experience utilisateur
|
## Expérience utilisateur
|
||||||
|
|
||||||
L'utilisateur accede au dashboard Filament sur `http://api-logistics.test/admin`. La navigation laterale propose 5 pages :
|
L'utilisateur accède au dashboard Filament sur `http://api-logistics.test/admin`. La navigation latérale propose 6 pages :
|
||||||
|
|
||||||
1. **Tables** : Cliquer sur une table pour voir ses colonnes. Utile pour connaitre les champs disponibles dans les parametres `select`.
|
1. **Documentation** : Affichage stylisé de la documentation API complète (markdown converti en HTML). Actions : télécharger en PDF, ouvrir dans un nouvel onglet. Rendu avec typographie soignée (titres hiérarchisés, tableaux bordés, blocs de code colorés, liens bleus).
|
||||||
2. **Articles** : Formulaire de recherche (search, select, results) + verification du stock d'un article par son ARTID.
|
2. **Tables** : Barre de statistiques (endpoint, type base, nombre de tables). Liste filtrable des tables avec compteur de colonnes. Clic sur une table pour voir ses colonnes avec badges de type colorés (Caractère, Numérique, Date/Heure, Logique, Mémo).
|
||||||
3. **Documents** : Recherche par tiers (thirdid) + consultation du detail d'un document (jnl + number).
|
3. **Articles** : Formulaire de recherche (search, select, results) + vérification du stock d'un article par son ARTID. Résultats en tableau structuré, stock en JSON formaté.
|
||||||
4. **Journaux** : Recherche par type de journal (TYPE).
|
4. **Documents** : Recherche par tiers (thirdid) + consultation du détail d'un document (jnl + number). Détail en JSON formaté.
|
||||||
5. **Tiers** : Recherche de tiers (search obligatoire) + historique des articles d'un tiers.
|
5. **Journaux** : Recherche par type de journal (TYPE). Résultats en tableau structuré.
|
||||||
|
6. **Tiers** : Recherche de tiers (search obligatoire) + historique des articles d'un tiers. Historique en JSON formaté.
|
||||||
|
|
||||||
Chaque page affiche les resultats sous forme de tableau dynamique et les metadonnees de la reponse (nombre de resultats, succes). En cas d'erreur de connexion a l'API, un message clair en francais est affiche a l'utilisateur.
|
Toutes les pages utilisent le même système de design : cartes à en-tête séparé, badges de compteur, indicateurs de chargement sur les actions réseau, et états vides avec icônes explicatives. En cas d'erreur API, un bandeau rouge s'affiche avec le message en français.
|
||||||
|
|||||||
@@ -1,43 +1,55 @@
|
|||||||
# Progress
|
# Progress
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Ce qui fonctionne
|
## Ce qui fonctionne
|
||||||
|
|
||||||
- [x] Projet Laravel 12 initialise (livewire-starter-kit)
|
- [x] Projet Laravel 12 initialisé (livewire-starter-kit)
|
||||||
- [x] Livewire 4 + Flux UI Free v2 installes
|
- [x] Livewire 4 + Flux UI Free v2 installés
|
||||||
- [x] Fortify installe (authentification existante, non utilisee par Filament)
|
- [x] Fortify installé (authentification existante, non utilisée par Filament)
|
||||||
- [x] Documentation API redigee (`documentation/WEB-A-1 (3).md`, `documentation/result.pdf`)
|
- [x] Documentation API rédigée avec accents (`documentation/documentation_api_logistics.md`)
|
||||||
- [x] Memory bank cree et structure (`memory-bank/`, `.cursor/rules/memory-bank.mdc`)
|
- [x] Memory bank créé et structuré (`memory-bank/`, `.cursor/rules/memory-bank.mdc`)
|
||||||
- [x] Configuration API Logistics (`.env`, `config/logistics.php`) avec timeout et retry
|
- [x] Configuration API Logistics (`.env`, `config/logistics.php`) avec timeout et retry
|
||||||
- [x] `LogisticsService` cree (`app/Services/LogisticsService.php`) avec 17 methodes, timeout, retry, gestion d'erreur
|
- [x] `LogisticsService` créé (`app/Services/LogisticsService.php`) avec 17 méthodes, timeout, retry, gestion d'erreur
|
||||||
- [x] `LogisticsApiException` creee (`app/Exceptions/LogisticsApiException.php`) avec messages francais
|
- [x] `LogisticsApiException` créée (`app/Exceptions/LogisticsApiException.php`) avec messages français
|
||||||
- [x] Migration `api_request_logs` creee
|
- [x] Migration `api_request_logs` créée
|
||||||
- [x] Filament v5.0.0 installe et configure sans authentification
|
- [x] Filament v5.0.0 installé et configuré sans authentification
|
||||||
- [x] 5 pages Filament creees : TablesExplorer, Articles, Documents, Journaux, Tiers
|
- [x] 6 pages Filament créées : Documentation, TablesExplorer, Articles, Documents, Journaux, Tiers
|
||||||
- [x] 5 vues Blade associees dans `resources/views/filament/pages/`
|
- [x] 6 vues Blade associées dans `resources/views/filament/pages/`
|
||||||
- [x] Gestion d'erreur dans toutes les pages Filament (LogisticsApiException + Throwable)
|
- [x] Gestion d'erreur dans toutes les pages Filament (LogisticsApiException + Throwable)
|
||||||
- [x] Logging des requetes API reussies et echouees dans `api_request_logs`
|
- [x] Logging des requêtes API réussies et échouées dans `api_request_logs`
|
||||||
- [x] 12 tests Pest pour LogisticsService (tous passent)
|
- [x] Système de design unifié : 10 composants Blade dans `resources/views/components/logistics/`
|
||||||
- [x] `README.md` cree
|
- [x] Convention de design documentée dans `.cursor/rules/design-system.mdc`
|
||||||
- [x] Formatage Pint valide
|
- [x] Toutes les pages Filament refactorisées avec les composants `x-logistics.*`
|
||||||
|
- [x] Thème Filament personnalisé (`resources/css/filament/admin/theme.css`)
|
||||||
|
- [x] Plugin `@tailwindcss/typography` activé pour le rendu prose
|
||||||
|
- [x] Styles `.documentation-prose` personnalisés pour le dark mode (titres, tableaux, code, liens)
|
||||||
|
- [x] TablesExplorer amélioré : selectTable, déduplication colonnes, filtre, badges de types
|
||||||
|
- [x] Page Documentation avec rendu markdown stylisé et export PDF
|
||||||
|
- [x] Connectivité API fonctionnelle (serveur `tse-10-test.esi.local`)
|
||||||
|
- [x] Convention d'écriture avec accents français appliquée
|
||||||
|
- [x] 61 tests Pest (tous passent)
|
||||||
|
- [x] `README.md` créé
|
||||||
|
- [x] Formatage Pint validé
|
||||||
- [x] CI GitHub Actions (lint + tests)
|
- [x] CI GitHub Actions (lint + tests)
|
||||||
|
|
||||||
## Ce qui reste a faire
|
## Ce qui reste à faire
|
||||||
|
|
||||||
- [ ] Resoudre la connectivite reseau : deployer sur le reseau distant ou mettre en place un tunnel
|
- [ ] Vérifier le rendu visuel de toutes les pages avec de vraies données API
|
||||||
- [ ] Tester le dashboard avec de vraies donnees API
|
- [ ] Éventuellement : pages d'écriture (document_add, document_mod)
|
||||||
- [ ] Eventuellement : pages d'ecriture (document_add, document_mod)
|
- [ ] Éventuellement : pagination / tri côté client pour les grands tableaux
|
||||||
- [ ] Eventuellement : ameliorer l'affichage des resultats (pagination, formatage)
|
- [ ] Éventuellement : page de consultation des logs API
|
||||||
|
|
||||||
## Problemes connus
|
## Problèmes connus
|
||||||
|
|
||||||
- **API injoignable depuis la machine locale** : Le serveur `tse-10-test.esiweb.pro` est sur un reseau prive accessible uniquement via Bureau a distance (RDP). L'application locale recoit `cURL error 28: Connection timed out`. Solution : deployer sur le reseau distant ou creer un tunnel SSH/VPN.
|
- L'erreur `SQLSTATE[HY000] [1049] Unknown database` peut apparaître lors de `composer update` si la base n'est pas encore créée (script `boost:update`). Sans impact une fois la base créée.
|
||||||
- L'erreur `SQLSTATE[HY000] [1049] Unknown database` peut apparaitre lors de `composer update` si la base n'est pas encore creee (script `boost:update`). Sans impact une fois la base creee.
|
- L'API retourne chaque colonne en double dans `column_list`. Le `TablesExplorer` déduplique côté client.
|
||||||
|
|
||||||
## Metriques
|
## Métriques
|
||||||
|
|
||||||
- Tests : 12 (tous passent, 18 assertions)
|
- Tests : 61 (tous passent, 165 assertions)
|
||||||
- Pages Filament : 5
|
- Pages Filament : 6 (Documentation, TablesExplorer, Articles, Documents, Journaux, Tiers)
|
||||||
|
- Composants Blade design system : 10
|
||||||
- Endpoints API couverts par LogisticsService : 17
|
- Endpoints API couverts par LogisticsService : 17
|
||||||
- Migrations : 5 (users, cache, jobs, two_factor, api_request_logs)
|
- Migrations : 5 (users, cache, jobs, two_factor, api_request_logs)
|
||||||
|
- Règles Cursor : 4 (laravel-boost, memory-bank, design-system, update-documentation)
|
||||||
|
|||||||
@@ -1,36 +1,42 @@
|
|||||||
# Project Brief
|
# Project Brief
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Vision
|
## Vision
|
||||||
|
|
||||||
Application Laravel de test dont l'objectif est de comprendre le fonctionnement de l'API Logistics (Flex/ESI Gescom) et d'en produire une documentation complete et comprehensible.
|
Application Laravel de test dont l'objectif est de comprendre le fonctionnement de l'API Logistics (Flex/ESI Gescom) et d'en produire une documentation complète et compréhensible.
|
||||||
|
|
||||||
## Objectifs
|
## Objectifs
|
||||||
|
|
||||||
1. Comprendre le fonctionnement de l'API Logistics.
|
1. Comprendre le fonctionnement de l'API Logistics.
|
||||||
2. Creer une application simple permettant d'envoyer et de recuperer des donnees vers/depuis l'API.
|
2. Créer une application simple permettant d'envoyer et de récupérer des données vers/depuis l'API.
|
||||||
3. Produire une documentation complete et comprehensible de l'API.
|
3. Produire une documentation complète et compréhensible de l'API.
|
||||||
|
|
||||||
## Perimetre fonctionnel
|
## Périmètre fonctionnel
|
||||||
|
|
||||||
- Dashboard Filament v5 accessible sans authentification sur `/admin`.
|
- Dashboard Filament v5 accessible sans authentification sur `/admin`.
|
||||||
- Pages de consultation pour les principales entites de l'API : tables, articles, documents, journaux, tiers.
|
- Pages de consultation pour les principales entités de l'API : tables, articles, documents, journaux, tiers.
|
||||||
- Formulaires de recherche parametrables pour chaque endpoint.
|
- Page de documentation intégrée avec rendu stylisé du markdown et export PDF.
|
||||||
- Affichage des resultats bruts retournes par l'API.
|
- Formulaires de recherche paramétrables pour chaque endpoint.
|
||||||
- Tracage des requetes effectuees dans une table `api_request_logs`.
|
- Affichage des résultats sous forme de tableaux structurés et de blocs JSON formatés.
|
||||||
- Gestion robuste des erreurs API (timeout, retry, messages utilisateur en francais).
|
- Système de design unifié avec composants Blade réutilisables (`x-logistics.*`).
|
||||||
|
- Traçage des requêtes effectuées dans une table `api_request_logs`.
|
||||||
|
- Gestion robuste des erreurs API (timeout, retry, messages utilisateur en français).
|
||||||
|
|
||||||
## Contraintes
|
## Contraintes
|
||||||
|
|
||||||
- Pas d'authentification sur le dashboard (projet de test interne).
|
- Pas d'authentification sur le dashboard (projet de test interne).
|
||||||
- L'API Logistics est hebergee sur le serveur TSE-10-TEST (`http://tse-10-test.esiweb.pro`).
|
- L'API Logistics est hébergée sur le serveur TSE-10-TEST (`http://tse-10-test.esi.local`).
|
||||||
- Le serveur API est accessible uniquement via le reseau interne (connexion Bureau a distance / RDP requise). L'application doit etre deployee sur ce reseau ou un tunnel doit etre mis en place.
|
- Le serveur API est accessible via le réseau interne.
|
||||||
- Toutes les requetes API sont en POST et necessitent un header `X-API-KEY`.
|
- Toutes les requêtes API sont en POST et nécessitent un header `X-API-KEY`.
|
||||||
- Le nom du dossier dans les URLs de l'API doit etre en minuscules.
|
- Le nom du dossier dans les URLs de l'API doit être en minuscules.
|
||||||
|
|
||||||
|
## Convention d'écriture
|
||||||
|
|
||||||
|
Tous les contenus rédigés en français (documentation, memory bank, règles Cursor, commentaires) doivent utiliser les accents appropriés.
|
||||||
|
|
||||||
## Ressources
|
## Ressources
|
||||||
|
|
||||||
- Documentation Postman : https://documenter.getpostman.com/view/40440561/2sB2qaj2Pz
|
- Documentation Postman : https://documenter.getpostman.com/view/40440561/2sB2qaj2Pz
|
||||||
- Documentation interne : `documentation/WEB-A-1 (3).md` et `documentation/result.pdf`
|
- Documentation interne : `documentation/documentation_api_logistics.md`
|
||||||
- Fichier projet : `project.md`
|
- Fichier projet : `project.md`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# System Patterns
|
# System Patterns
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Architecture applicative
|
## Architecture applicative
|
||||||
|
|
||||||
@@ -17,72 +17,131 @@ Utilisateur --> Filament Dashboard (/admin)
|
|||||||
| (retry automatique sur ConnectionException)
|
| (retry automatique sur ConnectionException)
|
||||||
|
|
|
|
||||||
+---> api_request_logs (MySQL)
|
+---> api_request_logs (MySQL)
|
||||||
| (succes ET echecs)
|
| (succès ET échecs)
|
||||||
|
|
|
|
||||||
+---> LogisticsApiException (en cas d'erreur)
|
+---> LogisticsApiException (en cas d'erreur)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Patterns utilises
|
## Patterns utilisés
|
||||||
|
|
||||||
### Service centralise
|
### Service centralisé
|
||||||
|
|
||||||
`App\Services\LogisticsService` encapsule tous les appels HTTP vers l'API Logistics. Chaque methode publique correspond a un endpoint. Le service :
|
`App\Services\LogisticsService` encapsule tous les appels HTTP vers l'API Logistics. Chaque méthode publique correspond à un endpoint. Le service :
|
||||||
|
|
||||||
- Construit l'URL a partir de `config('logistics.base_url')`, `config('logistics.folder')` et le nom de l'endpoint.
|
- Construit l'URL à partir de `config('logistics.base_url')`, `config('logistics.folder')` et le nom de l'endpoint.
|
||||||
- Ajoute automatiquement le header `X-API-KEY`.
|
- Ajoute automatiquement le header `X-API-KEY`.
|
||||||
- Configure `timeout()` et `connectTimeout()` depuis la config.
|
- Configure `timeout()` et `connectTimeout()` depuis la config.
|
||||||
- Effectue un retry automatique (nombre et delai configurables) uniquement sur les `ConnectionException`.
|
- Effectue un retry automatique (nombre et délai configurables) uniquement sur les `ConnectionException`.
|
||||||
- Enregistre chaque requete dans la table `api_request_logs` (succes et echecs).
|
- Enregistre chaque requête dans la table `api_request_logs` (succès et échecs).
|
||||||
- Retourne un tableau PHP avec les cles `data`, `metadata`, `error`.
|
- Retourne un tableau PHP avec les clés `data`, `metadata`, `error`.
|
||||||
- Lance une `LogisticsApiException` en cas d'erreur de connexion ou de requete.
|
- Lance une `LogisticsApiException` en cas d'erreur de connexion ou de requête.
|
||||||
|
|
||||||
### Exception dediee
|
### Exception dédiée
|
||||||
|
|
||||||
`App\Exceptions\LogisticsApiException` (etend `RuntimeException`) fournit :
|
`App\Exceptions\LogisticsApiException` (étend `RuntimeException`) fournit :
|
||||||
|
|
||||||
- Des messages d'erreur en francais lisibles par l'utilisateur.
|
- Des messages d'erreur en français lisibles par l'utilisateur.
|
||||||
- Des proprietes `endpoint` et `params` pour le contexte de l'erreur.
|
- Des propriétés `endpoint` et `params` pour le contexte de l'erreur.
|
||||||
- Deux methodes statiques : `connectionTimeout()` (API injoignable) et `requestFailed()` (erreur de requete).
|
- Deux méthodes statiques : `connectionTimeout()` (API injoignable) et `requestFailed()` (erreur de requête).
|
||||||
|
|
||||||
### Pages Filament personnalisees (pas de Resources)
|
### Pages Filament personnalisées (pas de Resources)
|
||||||
|
|
||||||
L'application n'utilise pas de Resources Filament (pas de CRUD local). Chaque page Filament :
|
L'application n'utilise pas de Resources Filament (pas de CRUD local). Chaque page Filament :
|
||||||
|
|
||||||
- Etend `Filament\Pages\Page`.
|
- Étend `Filament\Pages\Page`.
|
||||||
- Utilise des proprietes Livewire publiques pour les champs de formulaire.
|
- Utilise des propriétés Livewire publiques pour les champs de formulaire.
|
||||||
- Appelle `LogisticsService` via `app(LogisticsService::class)` dans des methodes d'action (ex: `searchArticles()`).
|
- Appelle `LogisticsService` via `app(LogisticsService::class)` dans des méthodes d'action (ex: `searchArticles()`).
|
||||||
- Attrape `LogisticsApiException` pour afficher un message clair, et `\Throwable` en fallback.
|
- Attrape `LogisticsApiException` en premier, puis `\Throwable` en fallback.
|
||||||
- Affiche les resultats dans des tableaux HTML dynamiques generes dans les vues Blade.
|
- Affiche les résultats via les composants du système de design `x-logistics.*`.
|
||||||
|
|
||||||
### Configuration externalisee
|
### Page Documentation
|
||||||
|
|
||||||
Les parametres de connexion a l'API (URL, cle, dossier, timeout, retry) sont dans `config/logistics.php` et lus depuis `.env`.
|
`App\Filament\Pages\Documentation` est une page spéciale qui :
|
||||||
|
|
||||||
## Structure des repertoires
|
- Lit le fichier `documentation/documentation_api_logistics.md` au montage.
|
||||||
|
- Convertit le markdown en HTML via `Str::markdown()`.
|
||||||
|
- Affiche le contenu dans une vue avec la classe CSS `.documentation-prose` pour un rendu stylisé.
|
||||||
|
- Propose deux actions d'en-tête : télécharger en PDF (via `barryvdh/laravel-dompdf`) et ouvrir dans un nouvel onglet.
|
||||||
|
|
||||||
|
### Système de design (composants Blade)
|
||||||
|
|
||||||
|
Convention documentée dans `.cursor/rules/design-system.mdc`. Tous les composants visuels réutilisables sont dans `resources/views/components/logistics/` :
|
||||||
|
|
||||||
|
| Composant | Rôle |
|
||||||
|
|-----------|------|
|
||||||
|
| `<x-logistics.card>` | Conteneur blanc arrondi avec ombre et anneau |
|
||||||
|
| `<x-logistics.section-header>` | En-tête de section (titre, description, slot `actions`) |
|
||||||
|
| `<x-logistics.error-banner>` | Bandeau d'erreur API conditionnel |
|
||||||
|
| `<x-logistics.stat-bar>` | Barre horizontale de métadonnées |
|
||||||
|
| `<x-logistics.stat-item>` | Élément individuel (icône + label + valeur) |
|
||||||
|
| `<x-logistics.data-table>` | Tableau dynamique avec en-têtes auto-détectés et état vide |
|
||||||
|
| `<x-logistics.empty-state>` | État vide centré (icône + titre + description) |
|
||||||
|
| `<x-logistics.search-input>` | Champ de recherche avec icône loupe intégrée |
|
||||||
|
| `<x-logistics.form-field>` | Champ de formulaire (label + input) à espacement homogène |
|
||||||
|
| `<x-logistics.json-block>` | Bloc JSON formaté avec bordure et fond adapté |
|
||||||
|
|
||||||
|
Règles :
|
||||||
|
- Toujours utiliser les composants `x-logistics.*` au lieu de dupliquer les classes CSS.
|
||||||
|
- Un `<x-logistics.card>` n'a pas de padding interne. Le padding est géré par les enfants (`<div class="p-6">`).
|
||||||
|
- Le `<x-logistics.section-header>` est le premier enfant d'une carte et crée une bordure de séparation.
|
||||||
|
- Toutes les actions réseau doivent avoir un indicateur de chargement (`wire:loading`).
|
||||||
|
|
||||||
|
### Thème Filament personnalisé
|
||||||
|
|
||||||
|
Le panel Filament utilise un thème CSS personnalisé (`resources/css/filament/admin/theme.css`) enregistré via `->viteTheme()` dans `AdminPanelProvider`. Ce thème :
|
||||||
|
|
||||||
|
- Importe le CSS de base Filament.
|
||||||
|
- Active le plugin `@tailwindcss/typography` pour les classes `prose`.
|
||||||
|
- Scanne les fichiers `app/Filament/**/*`, `resources/views/filament/**/*`, et `resources/views/components/logistics/**/*` pour inclure les classes Tailwind utilisées dans les composants.
|
||||||
|
- Contient des styles CSS personnalisés pour la classe `.documentation-prose` : hiérarchie de titres (h1-h4 avec bordures), tableaux avec bordures et en-têtes stylisés, blocs de code avec fond sombre, code inline avec fond distinct, liens colorés, listes avec marqueurs, séparateurs horizontaux visibles.
|
||||||
|
|
||||||
|
Après tout ajout de nouvelles classes Tailwind dans ces fichiers, il faut exécuter `npm run build`.
|
||||||
|
|
||||||
|
### Configuration externalisée
|
||||||
|
|
||||||
|
Les paramètres de connexion à l'API (URL, clé, dossier, timeout, retry) sont dans `config/logistics.php` et lus depuis `.env`.
|
||||||
|
|
||||||
|
## Structure des répertoires
|
||||||
|
|
||||||
```
|
```
|
||||||
app/
|
app/
|
||||||
Exceptions/
|
Exceptions/
|
||||||
LogisticsApiException.php # Exception dediee API
|
LogisticsApiException.php # Exception dédiée API
|
||||||
Filament/
|
Filament/
|
||||||
Pages/
|
Pages/
|
||||||
Articles.php # Recherche articles + stock
|
Articles.php # Recherche articles + stock
|
||||||
Documents.php # Recherche documents + detail
|
Dashboard.php # Page d'accueil
|
||||||
|
Documentation.php # Documentation API (markdown -> HTML)
|
||||||
|
Documents.php # Recherche documents + détail
|
||||||
Journaux.php # Recherche journaux
|
Journaux.php # Recherche journaux
|
||||||
TablesExplorer.php # Exploration tables + colonnes
|
TablesExplorer.php # Exploration tables + colonnes (filtre, déduplication, types)
|
||||||
Tiers.php # Recherche tiers + historique
|
Tiers.php # Recherche tiers + historique
|
||||||
Models/
|
Models/
|
||||||
User.php # Modele utilisateur (Fortify)
|
User.php # Modèle utilisateur (Fortify)
|
||||||
Providers/
|
Providers/
|
||||||
Filament/
|
Filament/
|
||||||
AdminPanelProvider.php # Configuration du panel (sans auth)
|
AdminPanelProvider.php # Configuration du panel (sans auth, viteTheme)
|
||||||
FortifyServiceProvider.php # Authentification Fortify
|
FortifyServiceProvider.php # Authentification Fortify
|
||||||
AppServiceProvider.php # Config globale (CarbonImmutable, DB safety)
|
AppServiceProvider.php # Config globale (CarbonImmutable, DB safety)
|
||||||
Services/
|
Services/
|
||||||
LogisticsService.php # Service centralise API Logistics
|
LogisticsService.php # Service centralisé API Logistics
|
||||||
|
|
||||||
config/
|
config/
|
||||||
logistics.php # Configuration API Logistics (URL, cle, timeout, retry)
|
logistics.php # Configuration API Logistics (URL, clé, timeout, retry)
|
||||||
|
|
||||||
|
documentation/
|
||||||
|
documentation_api_logistics.md # Documentation complète de l'API (avec accents)
|
||||||
|
|
||||||
|
resources/
|
||||||
|
css/
|
||||||
|
app.css # CSS principal (Tailwind 4, Flux UI)
|
||||||
|
filament/admin/
|
||||||
|
theme.css # Thème Filament personnalisé (Tailwind 4 + Typography + prose)
|
||||||
|
views/
|
||||||
|
components/logistics/ # 10 composants du système de design
|
||||||
|
filament/pages/ # 6 vues de pages Filament
|
||||||
|
pdf/
|
||||||
|
documentation.blade.php # Template PDF pour la documentation
|
||||||
|
|
||||||
database/
|
database/
|
||||||
migrations/
|
migrations/
|
||||||
@@ -92,23 +151,32 @@ database/
|
|||||||
...add_two_factor_columns_to_users_table.php
|
...add_two_factor_columns_to_users_table.php
|
||||||
...create_api_request_logs_table.php
|
...create_api_request_logs_table.php
|
||||||
|
|
||||||
resources/views/
|
|
||||||
filament/pages/
|
|
||||||
articles.blade.php
|
|
||||||
documents.blade.php
|
|
||||||
journaux.blade.php
|
|
||||||
tables-explorer.blade.php
|
|
||||||
tiers.blade.php
|
|
||||||
|
|
||||||
tests/Feature/
|
tests/Feature/
|
||||||
LogisticsServiceTest.php # 12 tests avec mocks HTTP
|
DocumentationTest.php # 5 tests page Documentation (Livewire + PDF)
|
||||||
|
LogisticsServiceTest.php # 12 tests service API (mocks HTTP)
|
||||||
|
TablesExplorerTest.php # 6 tests page TablesExplorer (Livewire)
|
||||||
|
FilamentDashboardTest.php # Tests dashboard Filament
|
||||||
|
DashboardTest.php # Tests dashboard
|
||||||
|
ExampleTest.php # Test d'exemple Laravel
|
||||||
|
|
||||||
|
routes/
|
||||||
|
web.php # Routes web (home, dashboard, documentation PDF)
|
||||||
|
|
||||||
|
.cursor/rules/
|
||||||
|
design-system.mdc # Convention de design (composants, CSS, structure)
|
||||||
|
memory-bank.mdc # Gestion du memory bank
|
||||||
|
update-documentation.mdc # Procédure de mise à jour de la documentation
|
||||||
|
laravel-boost.mdc # Règles Laravel Boost
|
||||||
```
|
```
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
- Filament v5 : les icones de navigation utilisent l'enum `Filament\Support\Icons\Heroicon` (pas de strings).
|
- Filament v5 : les icônes de navigation utilisent l'enum `Filament\Support\Icons\Heroicon` (pas de strings).
|
||||||
- Filament v5 : la propriete `$view` est non-static (`protected string $view`).
|
- Filament v5 : la propriété `$view` est non-static (`protected string $view`).
|
||||||
- Les proprietes statiques (`$navigationIcon`, `$navigationLabel`, `$title`, `$navigationSort`) restent static.
|
- Les propriétés statiques (`$navigationIcon`, `$navigationLabel`, `$title`, `$navigationSort`) restent static.
|
||||||
- Les appels API passent toujours par `LogisticsService`, jamais directement par `Http::`.
|
- Les appels API passent toujours par `LogisticsService`, jamais directement par `Http::`.
|
||||||
- Les pages Filament attrapent `LogisticsApiException` en premier, puis `\Throwable` en fallback.
|
- Les pages Filament attrapent `LogisticsApiException` en premier, puis `\Throwable` en fallback.
|
||||||
- Les messages d'erreur affiches a l'utilisateur sont en francais.
|
- Les messages d'erreur affichés à l'utilisateur sont en français.
|
||||||
|
- Toutes les vues Filament utilisent les composants `x-logistics.*` du système de design.
|
||||||
|
- Après modification des vues ou composants, exécuter `npm run build` pour recompiler le thème.
|
||||||
|
- Tous les contenus rédigés en français doivent utiliser les accents appropriés.
|
||||||
|
|||||||
@@ -1,39 +1,51 @@
|
|||||||
# Tech Context
|
# Tech Context
|
||||||
|
|
||||||
Derniere mise a jour : 2026-02-20
|
Dernière mise à jour : 2026-02-20
|
||||||
|
|
||||||
## Stack technique
|
## Stack technique
|
||||||
|
|
||||||
| Composant | Version | Role |
|
| Composant | Version | Rôle |
|
||||||
|-----------|---------|------|
|
|-----------|---------|------|
|
||||||
| PHP | 8.4 | Langage serveur |
|
| PHP | 8.4 | Langage serveur |
|
||||||
| Laravel | 12 | Framework applicatif |
|
| Laravel | 12 | Framework applicatif |
|
||||||
| Filament | 5.0 | Panel admin / dashboard |
|
| Filament | 5.0 | Panel admin / dashboard |
|
||||||
| Livewire | 4 | Composants reactifs |
|
| Livewire | 4 | Composants réactifs |
|
||||||
| Flux UI Free | 2.9+ | Composants UI Livewire |
|
| Flux UI Free | 2.9+ | Composants UI Livewire |
|
||||||
| Fortify | 1.30+ | Authentification (existant, non utilise par Filament) |
|
| Fortify | 1.30+ | Authentification (existant, non utilisé par Filament) |
|
||||||
| Pest | 4.4+ | Framework de tests |
|
| Pest | 4.4+ | Framework de tests |
|
||||||
| MySQL | - | Base de donnees |
|
| MySQL | - | Base de données |
|
||||||
| Vite | - | Bundler frontend |
|
| Vite | 7.3 | Bundler frontend |
|
||||||
| Tailwind CSS | 4 | Framework CSS |
|
| Tailwind CSS | 4 | Framework CSS (via @tailwindcss/vite) |
|
||||||
|
| @tailwindcss/typography | 0.5.19 | Plugin prose pour le rendu markdown |
|
||||||
|
| barryvdh/laravel-dompdf | - | Génération PDF |
|
||||||
|
|
||||||
## Dependances principales (composer.json)
|
## Dépendances principales (composer.json)
|
||||||
|
|
||||||
- `filament/filament: ^5.0`
|
- `filament/filament: ^5.0`
|
||||||
- `laravel/framework: ^12.0`
|
- `laravel/framework: ^12.0`
|
||||||
- `livewire/livewire: ^4.0`
|
- `livewire/livewire: ^4.0`
|
||||||
- `livewire/flux: ^2.9.0`
|
- `livewire/flux: ^2.9.0`
|
||||||
- `laravel/fortify: ^1.30`
|
- `laravel/fortify: ^1.30`
|
||||||
|
- `barryvdh/laravel-dompdf` (export PDF de la documentation)
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
- Tailwind CSS 4 avec le plugin Vite `@tailwindcss/vite`
|
||||||
|
- Plugin `@tailwindcss/typography` (v0.5.19) pour le rendu prose du markdown
|
||||||
|
- Thème Filament personnalisé : `resources/css/filament/admin/theme.css`
|
||||||
|
- Le thème Filament scanne les sources : `app/Filament/**/*`, `resources/views/filament/**/*`, `resources/views/components/logistics/**/*`
|
||||||
|
- Le thème inclut des styles CSS personnalisés pour la classe `.documentation-prose` (titres, tableaux, blocs de code, liens, listes) optimisés pour le dark mode Filament
|
||||||
|
- Build : `npm run build` (recompile `app.css` et `theme.css`)
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Variables d'environnement specifiques
|
### Variables d'environnement spécifiques
|
||||||
|
|
||||||
```
|
```
|
||||||
LOGISTICS_API_BASE_URL=http://tse-10-test.esiweb.pro
|
LOGISTICS_API_BASE_URL=http://tse-10-test.esi.local
|
||||||
LOGISTICS_API_KEY=<cle API>
|
LOGISTICS_API_KEY=<clé API>
|
||||||
LOGISTICS_API_FOLDER=esigescom
|
LOGISTICS_API_FOLDER=esigescom
|
||||||
LOGISTICS_API_TIMEOUT=30
|
LOGISTICS_API_TIMEOUT=300
|
||||||
LOGISTICS_API_CONNECT_TIMEOUT=10
|
LOGISTICS_API_CONNECT_TIMEOUT=10
|
||||||
LOGISTICS_API_RETRY_TIMES=3
|
LOGISTICS_API_RETRY_TIMES=3
|
||||||
LOGISTICS_API_RETRY_SLEEP_MS=500
|
LOGISTICS_API_RETRY_SLEEP_MS=500
|
||||||
@@ -41,17 +53,17 @@ LOGISTICS_API_RETRY_SLEEP_MS=500
|
|||||||
|
|
||||||
Fichier de config : `config/logistics.php`
|
Fichier de config : `config/logistics.php`
|
||||||
|
|
||||||
| Cle de config | Variable .env | Defaut | Description |
|
| Clé de config | Variable .env | Défaut | Description |
|
||||||
|---------------|---------------|--------|-------------|
|
|---------------|---------------|--------|-------------|
|
||||||
| `logistics.base_url` | `LOGISTICS_API_BASE_URL` | - | URL de base de l'API |
|
| `logistics.base_url` | `LOGISTICS_API_BASE_URL` | - | URL de base de l'API |
|
||||||
| `logistics.api_key` | `LOGISTICS_API_KEY` | - | Cle d'authentification |
|
| `logistics.api_key` | `LOGISTICS_API_KEY` | - | Clé d'authentification |
|
||||||
| `logistics.folder` | `LOGISTICS_API_FOLDER` | - | Dossier dans l'URL |
|
| `logistics.folder` | `LOGISTICS_API_FOLDER` | - | Dossier dans l'URL |
|
||||||
| `logistics.timeout` | `LOGISTICS_API_TIMEOUT` | 30 | Timeout total de la requete (secondes) |
|
| `logistics.timeout` | `LOGISTICS_API_TIMEOUT` | 30 | Timeout total de la requête (secondes) |
|
||||||
| `logistics.connect_timeout` | `LOGISTICS_API_CONNECT_TIMEOUT` | 10 | Timeout de connexion (secondes) |
|
| `logistics.connect_timeout` | `LOGISTICS_API_CONNECT_TIMEOUT` | 10 | Timeout de connexion (secondes) |
|
||||||
| `logistics.retry.times` | `LOGISTICS_API_RETRY_TIMES` | 3 | Nombre de tentatives en cas d'echec de connexion |
|
| `logistics.retry.times` | `LOGISTICS_API_RETRY_TIMES` | 3 | Nombre de tentatives en cas d'échec de connexion |
|
||||||
| `logistics.retry.sleep_ms` | `LOGISTICS_API_RETRY_SLEEP_MS` | 500 | Delai entre les tentatives (ms) |
|
| `logistics.retry.sleep_ms` | `LOGISTICS_API_RETRY_SLEEP_MS` | 500 | Délai entre les tentatives (ms) |
|
||||||
|
|
||||||
### Base de donnees
|
### Base de données
|
||||||
|
|
||||||
- Connexion : MySQL
|
- Connexion : MySQL
|
||||||
- Base : `logistics`
|
- Base : `logistics`
|
||||||
@@ -61,26 +73,28 @@ Fichier de config : `config/logistics.php`
|
|||||||
|
|
||||||
### Connexion
|
### Connexion
|
||||||
|
|
||||||
- Serveur : TSE-10-TEST (reseau prive, accessible uniquement via Bureau a distance / RDP)
|
- Serveur : TSE-10-TEST (réseau privé)
|
||||||
- Base URL : `http://tse-10-test.esiweb.pro`
|
- Base URL : `http://tse-10-test.esi.local`
|
||||||
- Dossier : `esigescom` (minuscules obligatoires)
|
- Dossier : `esigescom` (minuscules obligatoires)
|
||||||
- Authentification : Header `X-API-KEY`
|
- Authentification : Header `X-API-KEY`
|
||||||
- Methode : POST pour tous les endpoints
|
- Méthode : POST pour tous les endpoints
|
||||||
- Port HTTP : 5186 / Port HTTPS : 7126
|
|
||||||
|
|
||||||
### Structure de reponse
|
### Structure de réponse
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"data": "<resultat>",
|
"data": "<résultat>",
|
||||||
"metadata": { "rowcount": 0, "issuccess": true },
|
"metadata": { "rowcount": 0, "issuccess": true },
|
||||||
"error": "<message d'erreur ou null>"
|
"error": "<message d'erreur ou null>"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Réponse `tables_list` : chaque table a `name` et `columnCount`.
|
||||||
|
Réponse `column_list` : chaque colonne a `name`, `dataType` (C/N/T/D/L/M), `length`, `precision`. Les colonnes sont retournées en double par l'API (dédupliquées côté client).
|
||||||
|
|
||||||
### Endpoints
|
### Endpoints
|
||||||
|
|
||||||
| Endpoint | Description | Parametres principaux |
|
| Endpoint | Description | Paramètres principaux |
|
||||||
|----------|-------------|-----------------------|
|
|----------|-------------|-----------------------|
|
||||||
| `tables_list` | Liste des tables | - |
|
| `tables_list` | Liste des tables | - |
|
||||||
| `column_list/{table}` | Colonnes d'une table | table (URL) |
|
| `column_list/{table}` | Colonnes d'une table | table (URL) |
|
||||||
@@ -88,18 +102,29 @@ Fichier de config : `config/logistics.php`
|
|||||||
| `art_getstk` | Stock d'un article | ARTID |
|
| `art_getstk` | Stock d'un article | ARTID |
|
||||||
| `jnl_list` | Liste des journaux | select, results, TYPE |
|
| `jnl_list` | Liste des journaux | select, results, TYPE |
|
||||||
| `document_list` | Liste des documents | select, thirdid |
|
| `document_list` | Liste des documents | select, thirdid |
|
||||||
| `document_detail` | Detail d'un document | jnl, number |
|
| `document_detail` | Détail d'un document | jnl, number |
|
||||||
| `document_add` | Ajout d'un document | ThirdId, Date, Artid[], Qty[], Saleprice[], JNL, ... |
|
| `document_add` | Ajout d'un document | ThirdId, Date, Artid[], Qty[], Saleprice[], JNL, ... |
|
||||||
| `document_mod` | Modification d'un document | number, Thirdid, Artid[], Qty[], Saleprice[], JNL, ... |
|
| `document_mod` | Modification d'un document | number, Thirdid, Artid[], Qty[], Saleprice[], JNL, ... |
|
||||||
| `Document_GetStatusList` | Statuts d'un journal | jnl |
|
| `Document_GetStatusList` | Statuts d'un journal | jnl |
|
||||||
| `Document_GetUnitPriceAndVat` | Prix et TVA | ARTID, QTY, JNL, THIRDID, DATE |
|
| `Document_GetUnitPriceAndVat` | Prix et TVA | ARTID, QTY, JNL, THIRDID, DATE |
|
||||||
| `Document_GetDueDate` | Echeance | paydelay, date |
|
| `Document_GetDueDate` | Échéance | paydelay, date |
|
||||||
| `Document_GetAttachListThumbnail` | Miniatures annexes | JNL, NUMBER |
|
| `Document_GetAttachListThumbnail` | Miniatures annexes | JNL, NUMBER |
|
||||||
| `third_list` | Liste des tiers | select, results, search |
|
| `third_list` | Liste des tiers | select, results, search |
|
||||||
| `third_GetArtHistory` | Historique articles tiers | thirdid |
|
| `third_GetArtHistory` | Historique articles tiers | thirdid |
|
||||||
| `getserialnumber` | Numero de serie | - |
|
| `getserialnumber` | Numéro de série | - |
|
||||||
| `codes_list` | Donnees par code | code |
|
| `codes_list` | Données par code | code |
|
||||||
|
|
||||||
### Tables accessibles
|
### Tables accessibles
|
||||||
|
|
||||||
art, attach, barcode, category, codes, cust, docdet, dochead, docpay, file, hist, incodes, jnl, pers, price, stk
|
art (160 col.), attach (13), barcode (12), category (10), codes (50), cust (216), docdet (82), dochead (212), docpay (22), file (17), hist (50), incodes (24), jnl (155), pers (78), price (28), stk (20)
|
||||||
|
|
||||||
|
### Types de colonnes (dataType)
|
||||||
|
|
||||||
|
| Code | Label | Couleur badge |
|
||||||
|
|------|-------|---------------|
|
||||||
|
| C | Caractère | Bleu |
|
||||||
|
| N | Numérique | Vert (emerald) |
|
||||||
|
| T | Date/Heure | Violet |
|
||||||
|
| D | Date | Violet |
|
||||||
|
| L | Logique | Ambre |
|
||||||
|
| M | Mémo | Gris |
|
||||||
|
|||||||
76
package-lock.json
generated
76
package-lock.json
generated
@@ -5,14 +5,17 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"axios": "^1.7.4",
|
"axios": "^1.7.4",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"laravel-vite-plugin": "^2.0",
|
"laravel-vite-plugin": "^2.0",
|
||||||
"tailwindcss": "^4.0.7",
|
|
||||||
"vite": "^7.0.4"
|
"vite": "^7.0.4"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/vite": "^4.2.0",
|
||||||
|
"tailwindcss": "^4.2.0"
|
||||||
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||||
@@ -439,6 +442,7 @@
|
|||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
@@ -449,6 +453,7 @@
|
|||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
@@ -459,6 +464,7 @@
|
|||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@@ -468,12 +474,14 @@
|
|||||||
"version": "1.5.5",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.31",
|
"version": "0.3.31",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
@@ -809,6 +817,7 @@
|
|||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.0.tgz",
|
||||||
"integrity": "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==",
|
"integrity": "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
@@ -824,6 +833,7 @@
|
|||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz",
|
||||||
"integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==",
|
"integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 20"
|
"node": ">= 20"
|
||||||
@@ -850,6 +860,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -866,6 +877,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -882,6 +894,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -898,6 +911,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -914,6 +928,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -930,6 +945,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -946,6 +962,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -978,6 +995,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1002,6 +1020,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1023,6 +1042,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1039,6 +1059,7 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1048,10 +1069,23 @@
|
|||||||
"node": ">= 20"
|
"node": ">= 20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/typography": {
|
||||||
|
"version": "0.5.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz",
|
||||||
|
"integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-selector-parser": "6.0.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/vite": {
|
"node_modules/@tailwindcss/vite": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.0.tgz",
|
||||||
"integrity": "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==",
|
"integrity": "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/node": "4.2.0",
|
"@tailwindcss/node": "4.2.0",
|
||||||
@@ -1319,6 +1353,18 @@
|
|||||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cssesc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"cssesc": "bin/cssesc"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@@ -1332,6 +1378,7 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -1367,6 +1414,7 @@
|
|||||||
"version": "5.19.0",
|
"version": "5.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
|
||||||
"integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
|
"integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.2.4",
|
"graceful-fs": "^4.2.4",
|
||||||
@@ -1622,6 +1670,7 @@
|
|||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/has-flag": {
|
"node_modules/has-flag": {
|
||||||
@@ -1685,6 +1734,7 @@
|
|||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "lib/jiti-cli.mjs"
|
"jiti": "lib/jiti-cli.mjs"
|
||||||
@@ -1713,6 +1763,7 @@
|
|||||||
"version": "1.31.1",
|
"version": "1.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
|
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
|
||||||
"integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
|
"integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"detect-libc": "^2.0.3"
|
"detect-libc": "^2.0.3"
|
||||||
@@ -1962,6 +2013,7 @@
|
|||||||
"version": "0.30.21",
|
"version": "0.30.21",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||||
@@ -2067,6 +2119,19 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-selector-parser": {
|
||||||
|
"version": "6.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||||
|
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"util-deprecate": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-value-parser": {
|
"node_modules/postcss-value-parser": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
@@ -2226,6 +2291,7 @@
|
|||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
||||||
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
|
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -2296,6 +2362,12 @@
|
|||||||
"browserslist": ">= 4.21.0"
|
"browserslist": ">= 4.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "7.3.1",
|
"version": "7.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
|
|||||||
@@ -7,17 +7,20 @@
|
|||||||
"dev": "vite"
|
"dev": "vite"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"axios": "^1.7.4",
|
"axios": "^1.7.4",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"laravel-vite-plugin": "^2.0",
|
"laravel-vite-plugin": "^2.0",
|
||||||
"tailwindcss": "^4.0.7",
|
|
||||||
"vite": "^7.0.4"
|
"vite": "^7.0.4"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/vite": "^4.2.0",
|
||||||
|
"tailwindcss": "^4.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
191
resources/css/filament/admin/theme.css
Normal file
191
resources/css/filament/admin/theme.css
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
@import '../../../../vendor/filament/filament/resources/css/theme.css';
|
||||||
|
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
|
@source '../../../../app/Filament/**/*';
|
||||||
|
@source '../../../../resources/views/filament/**/*';
|
||||||
|
@source '../../../../resources/views/components/logistics/**/*';
|
||||||
|
|
||||||
|
/* --- Documentation prose overrides (dark mode Filament) --- */
|
||||||
|
|
||||||
|
.documentation-prose {
|
||||||
|
--tw-prose-body: theme(--color-gray-300);
|
||||||
|
--tw-prose-headings: theme(--color-white);
|
||||||
|
--tw-prose-links: theme(--color-blue-400);
|
||||||
|
--tw-prose-bold: theme(--color-white);
|
||||||
|
--tw-prose-code: theme(--color-blue-300);
|
||||||
|
--tw-prose-hr: theme(--color-white/10);
|
||||||
|
--tw-prose-th-borders: theme(--color-white/10);
|
||||||
|
--tw-prose-td-borders: theme(--color-white/5);
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
border-bottom: 1px solid oklch(from white l c h / 0.1);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose h2 {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: -0.015em;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 1px solid oklch(from white l c h / 0.07);
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose h4 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: oklch(from white l c h / 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose hr {
|
||||||
|
border-color: oklch(from white l c h / 0.1);
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose a {
|
||||||
|
color: oklch(0.7 0.15 250);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose a:hover {
|
||||||
|
color: oklch(0.8 0.15 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Tables --- */
|
||||||
|
|
||||||
|
.documentation-prose table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border: 1px solid oklch(from white l c h / 0.1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose thead {
|
||||||
|
background: oklch(from white l c h / 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose thead tr {
|
||||||
|
border-bottom: 1px solid oklch(from white l c h / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose th {
|
||||||
|
padding: 0.625rem 0.75rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
color: oklch(from white l c h / 0.6);
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose td {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
color: oklch(from white l c h / 0.75);
|
||||||
|
vertical-align: top;
|
||||||
|
border-top: 1px solid oklch(from white l c h / 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose tbody tr:hover {
|
||||||
|
background: oklch(from white l c h / 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Code blocks --- */
|
||||||
|
|
||||||
|
.documentation-prose pre {
|
||||||
|
background: oklch(0.15 0.005 260);
|
||||||
|
border: 1px solid oklch(from white l c h / 0.1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose pre code {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
color: oklch(0.75 0.05 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose :not(pre) > code {
|
||||||
|
background: oklch(from white l c h / 0.08);
|
||||||
|
border: 1px solid oklch(from white l c h / 0.1);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
font-size: 0.8125em;
|
||||||
|
color: oklch(0.78 0.1 250);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Lists --- */
|
||||||
|
|
||||||
|
.documentation-prose ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose li {
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation-prose li::marker {
|
||||||
|
color: oklch(from white l c h / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Blockquotes --- */
|
||||||
|
|
||||||
|
.documentation-prose blockquote {
|
||||||
|
border-left: 3px solid oklch(0.6 0.15 250);
|
||||||
|
padding-left: 1rem;
|
||||||
|
color: oklch(from white l c h / 0.7);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Strong / Bold --- */
|
||||||
|
|
||||||
|
.documentation-prose strong {
|
||||||
|
color: oklch(from white l c h / 0.95);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Paragraphs --- */
|
||||||
|
|
||||||
|
.documentation-prose p {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
5
resources/views/components/logistics/card.blade.php
Normal file
5
resources/views/components/logistics/card.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@props(['class' => ''])
|
||||||
|
|
||||||
|
<div {{ $attributes->class(['rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10', $class]) }}>
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
40
resources/views/components/logistics/data-table.blade.php
Normal file
40
resources/views/components/logistics/data-table.blade.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
@props(['data', 'metadata' => null, 'emptyMessage' => 'Aucun resultat.', 'emptyIcon' => 'heroicon-o-inbox'])
|
||||||
|
|
||||||
|
@if (count($data) > 0)
|
||||||
|
@php
|
||||||
|
$firstRow = reset($data);
|
||||||
|
$isAssociative = is_array($firstRow);
|
||||||
|
$headers = $isAssociative ? array_keys($firstRow) : [];
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full text-left text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr class="border-b border-gray-200 dark:border-white/10">
|
||||||
|
@if ($isAssociative)
|
||||||
|
@foreach ($headers as $key)
|
||||||
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">Valeur</th>
|
||||||
|
@endif
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
||||||
|
@foreach ($data as $row)
|
||||||
|
<tr class="transition-colors hover:bg-gray-50 dark:hover:bg-white/5">
|
||||||
|
@if ($isAssociative)
|
||||||
|
@foreach ($row as $value)
|
||||||
|
<td class="px-3 py-2.5 text-sm text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<td class="px-3 py-2.5 text-sm text-gray-700 dark:text-gray-300">{{ $row }}</td>
|
||||||
|
@endif
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<x-logistics.empty-state :icon="$emptyIcon" :title="$emptyMessage" />
|
||||||
|
@endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@props(['icon' => 'heroicon-o-inbox', 'title', 'description' => null])
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center justify-center py-12 text-center">
|
||||||
|
<x-filament::icon :icon="$icon" class="h-10 w-10 text-gray-300 dark:text-gray-600" />
|
||||||
|
<p class="mt-3 text-sm font-medium text-gray-900 dark:text-white">{{ $title }}</p>
|
||||||
|
@if ($description)
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ $description }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@props(['message'])
|
||||||
|
|
||||||
|
@if ($message)
|
||||||
|
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
11
resources/views/components/logistics/form-field.blade.php
Normal file
11
resources/views/components/logistics/form-field.blade.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
@props(['label', 'id', 'type' => 'text', 'placeholder' => ''])
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="{{ $id }}" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ $label }}</label>
|
||||||
|
<input
|
||||||
|
{{ $attributes->class(['mt-1.5 w-full rounded-lg border-gray-300 py-2 text-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white']) }}
|
||||||
|
type="{{ $type }}"
|
||||||
|
id="{{ $id }}"
|
||||||
|
placeholder="{{ $placeholder }}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@props(['data'])
|
||||||
|
|
||||||
|
@if (! empty($data))
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<pre class="rounded-lg border border-gray-200 bg-gray-50 p-4 text-xs font-mono leading-relaxed text-gray-700 dark:border-white/10 dark:bg-gray-800 dark:text-gray-300">{{ json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
10
resources/views/components/logistics/search-input.blade.php
Normal file
10
resources/views/components/logistics/search-input.blade.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@props(['placeholder' => 'Rechercher...'])
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<x-filament::icon icon="heroicon-o-magnifying-glass" class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
|
||||||
|
<input
|
||||||
|
{{ $attributes->class(['w-full rounded-lg border-gray-300 py-2 pl-9 pr-3 text-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white']) }}
|
||||||
|
type="text"
|
||||||
|
placeholder="{{ $placeholder }}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
@props(['title', 'description' => null])
|
||||||
|
|
||||||
|
<div class="border-b border-gray-200 px-6 py-4 dark:border-white/10">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-base font-semibold text-gray-950 dark:text-white">{{ $title }}</h3>
|
||||||
|
@if ($description)
|
||||||
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ $description }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@isset($actions)
|
||||||
|
<div class="flex items-center gap-2">{{ $actions }}</div>
|
||||||
|
@endisset
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
5
resources/views/components/logistics/stat-bar.blade.php
Normal file
5
resources/views/components/logistics/stat-bar.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<x-logistics.card>
|
||||||
|
<div class="flex flex-wrap items-center gap-x-6 gap-y-2 px-6 py-3">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
12
resources/views/components/logistics/stat-item.blade.php
Normal file
12
resources/views/components/logistics/stat-item.blade.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
@props(['icon' => null, 'label' => null, 'value'])
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
@if ($icon)
|
||||||
|
<x-filament::icon :icon="$icon" class="h-4 w-4 shrink-0" />
|
||||||
|
@endif
|
||||||
|
@if ($label)
|
||||||
|
<span>{{ $label }} <span class="font-medium text-gray-700 dark:text-gray-200">{{ $value }}</span></span>
|
||||||
|
@else
|
||||||
|
<span class="font-medium text-gray-700 dark:text-gray-200">{{ $value }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
@@ -1,91 +1,89 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
@if ($errorMessage)
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
|
||||||
{{ $errorMessage }}
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- Formulaire de recherche --}}
|
{{-- Formulaire de recherche --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Rechercher des articles</h3>
|
<x-logistics.section-header title="Rechercher des articles" />
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="search"
|
||||||
|
label="Recherche"
|
||||||
|
id="search"
|
||||||
|
placeholder="Filtre de recherche..."
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="select"
|
||||||
|
label="Colonnes (select)"
|
||||||
|
id="select"
|
||||||
|
placeholder="artid,artname"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="results"
|
||||||
|
label="Nombre de résultats"
|
||||||
|
id="results"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3">
|
<div class="mt-4 flex items-center gap-3">
|
||||||
<div>
|
<x-filament::button wire:click="searchArticles" icon="heroicon-o-magnifying-glass">
|
||||||
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Recherche</label>
|
Rechercher
|
||||||
<input wire:model="search" type="text" id="search" placeholder="Filtre de recherche..."
|
</x-filament::button>
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
<div wire:loading wire:target="searchArticles" class="flex items-center gap-2">
|
||||||
</div>
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
<div>
|
<span class="text-sm text-gray-500">Recherche en cours...</span>
|
||||||
<label for="select" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Colonnes (select)</label>
|
</div>
|
||||||
<input wire:model="select" type="text" id="select" placeholder="artid,artname"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="results" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nombre de resultats</label>
|
|
||||||
<input wire:model="results" type="number" id="results" min="1" max="100"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4">
|
|
||||||
<x-filament::button wire:click="searchArticles" icon="heroicon-o-magnifying-glass">
|
|
||||||
Rechercher
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Resultats --}}
|
{{-- Resultats --}}
|
||||||
@if (count($data) > 0)
|
@if (count($data) > 0)
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<div class="flex items-center justify-between">
|
<x-logistics.section-header title="Résultats">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Resultats</h3>
|
<x-slot:actions>
|
||||||
@if ($metadata)
|
@if ($metadata)
|
||||||
<span class="text-sm text-gray-500">{{ $metadata['rowcount'] ?? 0 }} resultat(s)</span>
|
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
|
||||||
@endif
|
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</x-slot:actions>
|
||||||
|
</x-logistics.section-header>
|
||||||
|
<div class="p-6">
|
||||||
|
<x-logistics.data-table :data="$data" />
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<table class="w-full text-left text-sm">
|
|
||||||
<thead class="border-b border-gray-200 dark:border-white/10">
|
|
||||||
<tr>
|
|
||||||
@foreach (array_keys(is_array(reset($data)) ? reset($data) : $data) as $key)
|
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
|
||||||
@foreach ($data as $row)
|
|
||||||
<tr>
|
|
||||||
@foreach ((is_array($row) ? $row : [$row]) as $value)
|
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Stock d'un article --}}
|
{{-- Stock d'un article --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Verifier le stock d'un article</h3>
|
<x-logistics.section-header title="Vérifier le stock d'un article" />
|
||||||
|
<div class="p-6">
|
||||||
<div class="mt-4 flex items-end gap-4">
|
<div class="flex items-end gap-4">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<label for="stockArticleId" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Identifiant article (ARTID)</label>
|
<x-logistics.form-field
|
||||||
<input wire:model="stockArticleId" type="text" id="stockArticleId" placeholder="Ex: ART001"
|
wire:model="stockArticleId"
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
label="Identifiant article (ARTID)"
|
||||||
|
id="stockArticleId"
|
||||||
|
placeholder="Ex: ART001"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<x-filament::button wire:click="getStock" icon="heroicon-o-cube">
|
||||||
|
Vérifier le stock
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div wire:loading wire:target="getStock" class="mt-4 flex items-center gap-2">
|
||||||
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
|
<span class="text-sm text-gray-500">Chargement...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div wire:loading.remove wire:target="getStock" class="mt-4">
|
||||||
|
<x-logistics.json-block :data="$stockData" />
|
||||||
</div>
|
</div>
|
||||||
<x-filament::button wire:click="getStock" icon="heroicon-o-cube">
|
|
||||||
Verifier le stock
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
@if (count($stockData) > 0)
|
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<pre class="rounded-lg bg-gray-50 p-4 text-sm text-gray-700 dark:bg-gray-800 dark:text-gray-300">{{ json_encode($stockData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
170
resources/views/filament/pages/dashboard.blade.php
Normal file
170
resources/views/filament/pages/dashboard.blade.php
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<x-filament-panels::page>
|
||||||
|
|
||||||
|
{{-- En-tete de bienvenue --}}
|
||||||
|
<x-logistics.card>
|
||||||
|
<div class="p-8 sm:p-10">
|
||||||
|
<div class="max-w-3xl">
|
||||||
|
<h1 class="text-2xl font-bold tracking-tight text-gray-950 sm:text-3xl dark:text-white">
|
||||||
|
Bienvenue sur API Logistics
|
||||||
|
</h1>
|
||||||
|
<p class="mt-3 text-base leading-relaxed text-gray-600 dark:text-gray-400">
|
||||||
|
Application d'exploration de l'API Logistics (Flex/ESI Gescom).
|
||||||
|
Ce projet permet de tester les endpoints disponibles, comprendre les structures de données
|
||||||
|
et servir de base pour une documentation complète de l'API.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
|
||||||
|
{{-- Navigation rapide --}}
|
||||||
|
<x-logistics.card>
|
||||||
|
<x-logistics.section-header
|
||||||
|
title="Explorer l'API"
|
||||||
|
description="Accédez aux différentes sections pour interroger l'API Logistics."
|
||||||
|
/>
|
||||||
|
<div class="grid grid-cols-1 gap-4 p-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\TablesExplorer::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-table-cells" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Tables</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Explorer les tables et leurs colonnes</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\Articles::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-cube" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Articles</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Rechercher des articles et vérifier les stocks</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\Documents::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-document-text" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Documents</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Consulter les documents par tiers</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\Journaux::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-book-open" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Journaux</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Rechercher par type de journal</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\Tiers::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-users" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Tiers</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Rechercher des tiers et leur historique</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ \App\Filament\Pages\Documentation::getUrl() }}"
|
||||||
|
class="group rounded-lg border border-gray-200 p-5 transition-colors hover:border-primary-300 hover:bg-primary-50 dark:border-white/10 dark:hover:border-primary-500/30 dark:hover:bg-primary-500/5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
|
||||||
|
<x-filament::icon icon="heroicon-o-document-magnifying-glass" class="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">Documentation</h3>
|
||||||
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Documentation complète de l'API</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
|
||||||
|
{{-- Informations techniques --}}
|
||||||
|
<x-logistics.card>
|
||||||
|
<x-logistics.section-header
|
||||||
|
title="Informations techniques"
|
||||||
|
description="Configuration et stack technique du projet."
|
||||||
|
/>
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<h4 class="text-sm font-semibold text-gray-950 dark:text-white">Stack</h4>
|
||||||
|
<dl class="mt-3 space-y-2 text-sm">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Framework</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">Laravel 12</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Panel admin</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">Filament 5</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Composants réactifs</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">Livewire 4</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">CSS</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">Tailwind CSS 4</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Tests</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">Pest 4</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="text-sm font-semibold text-gray-950 dark:text-white">Connexion API</h4>
|
||||||
|
<dl class="mt-3 space-y-2 text-sm">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Serveur</dt>
|
||||||
|
<dd class="font-medium font-mono text-gray-700 dark:text-gray-200">tse-10-test.esi.local</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Méthode</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">POST</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Authentification</dt>
|
||||||
|
<dd class="font-medium font-mono text-gray-700 dark:text-gray-200">X-API-KEY</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Timeout</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">{{ config('logistics.timeout', 30) }}s</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Retry</dt>
|
||||||
|
<dd class="font-medium text-gray-700 dark:text-gray-200">{{ config('logistics.retry.times', 3) }} tentatives</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
|
||||||
|
</x-filament-panels::page>
|
||||||
9
resources/views/filament/pages/documentation.blade.php
Normal file
9
resources/views/filament/pages/documentation.blade.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<x-filament-panels::page>
|
||||||
|
<x-logistics.card>
|
||||||
|
<div class="p-6 sm:p-8 lg:p-10">
|
||||||
|
<div class="documentation-prose prose prose-sm max-w-none dark:prose-invert prose-headings:scroll-mt-20">
|
||||||
|
{!! $htmlContent !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
|
</x-filament-panels::page>
|
||||||
@@ -1,93 +1,87 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
@if ($errorMessage)
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
|
||||||
{{ $errorMessage }}
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- Formulaire de recherche --}}
|
{{-- Formulaire de recherche --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Rechercher des documents</h3>
|
<x-logistics.section-header title="Rechercher des documents" />
|
||||||
|
<div class="p-6">
|
||||||
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
<div>
|
<x-logistics.form-field
|
||||||
<label for="select" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Colonnes (select)</label>
|
wire:model="select"
|
||||||
<input wire:model="select" type="text" id="select" placeholder="jnl,number,thirdid,date"
|
label="Colonnes (select)"
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
id="select"
|
||||||
|
placeholder="jnl,number,thirdid,date"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="thirdId"
|
||||||
|
label="Identifiant tiers (thirdid)"
|
||||||
|
id="thirdId"
|
||||||
|
placeholder="Ex: CUST001"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label for="thirdId" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Identifiant tiers (thirdid)</label>
|
<div class="mt-4 flex items-center gap-3">
|
||||||
<input wire:model="thirdId" type="text" id="thirdId" placeholder="Ex: CUST001"
|
<x-filament::button wire:click="searchDocuments" icon="heroicon-o-magnifying-glass">
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
Rechercher
|
||||||
|
</x-filament::button>
|
||||||
|
<div wire:loading wire:target="searchDocuments" class="flex items-center gap-2">
|
||||||
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
|
<span class="text-sm text-gray-500">Recherche en cours...</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4">
|
|
||||||
<x-filament::button wire:click="searchDocuments" icon="heroicon-o-magnifying-glass">
|
|
||||||
Rechercher
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Resultats --}}
|
{{-- Resultats --}}
|
||||||
@if (count($data) > 0)
|
@if (count($data) > 0)
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<div class="flex items-center justify-between">
|
<x-logistics.section-header title="Résultats">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Resultats</h3>
|
<x-slot:actions>
|
||||||
@if ($metadata)
|
@if ($metadata)
|
||||||
<span class="text-sm text-gray-500">{{ $metadata['rowcount'] ?? 0 }} resultat(s)</span>
|
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
|
||||||
@endif
|
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</x-slot:actions>
|
||||||
|
</x-logistics.section-header>
|
||||||
|
<div class="p-6">
|
||||||
|
<x-logistics.data-table :data="$data" />
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<table class="w-full text-left text-sm">
|
|
||||||
<thead class="border-b border-gray-200 dark:border-white/10">
|
|
||||||
<tr>
|
|
||||||
@foreach (array_keys(is_array(reset($data)) ? reset($data) : $data) as $key)
|
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
|
||||||
@foreach ($data as $row)
|
|
||||||
<tr>
|
|
||||||
@foreach ((is_array($row) ? $row : [$row]) as $value)
|
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Detail d'un document --}}
|
{{-- Detail d'un document --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Detail d'un document</h3>
|
<x-logistics.section-header title="Détail d'un document" />
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="detailJnl"
|
||||||
|
label="Code journal (jnl)"
|
||||||
|
id="detailJnl"
|
||||||
|
placeholder="Ex: VEN"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="detailNumber"
|
||||||
|
label="Numéro de document"
|
||||||
|
id="detailNumber"
|
||||||
|
placeholder="Ex: 1"
|
||||||
|
/>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<x-filament::button wire:click="getDocumentDetail" icon="heroicon-o-eye">
|
||||||
|
Voir le détail
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3">
|
<div wire:loading wire:target="getDocumentDetail" class="mt-4 flex items-center gap-2">
|
||||||
<div>
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
<label for="detailJnl" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Code journal (jnl)</label>
|
<span class="text-sm text-gray-500">Chargement...</span>
|
||||||
<input wire:model="detailJnl" type="text" id="detailJnl" placeholder="Ex: VEN"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label for="detailNumber" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Numero de document</label>
|
<div wire:loading.remove wire:target="getDocumentDetail" class="mt-4">
|
||||||
<input wire:model="detailNumber" type="text" id="detailNumber" placeholder="Ex: 1"
|
<x-logistics.json-block :data="$detailData" />
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
|
||||||
<div class="flex items-end">
|
|
||||||
<x-filament::button wire:click="getDocumentDetail" icon="heroicon-o-eye">
|
|
||||||
Voir le detail
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
@if (count($detailData) > 0)
|
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<pre class="rounded-lg bg-gray-50 p-4 text-sm text-gray-700 dark:bg-gray-800 dark:text-gray-300">{{ json_encode($detailData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
@@ -1,69 +1,60 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
@if ($errorMessage)
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
|
||||||
{{ $errorMessage }}
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- Formulaire de recherche --}}
|
{{-- Formulaire de recherche --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Rechercher des journaux</h3>
|
<x-logistics.section-header title="Rechercher des journaux" />
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="type"
|
||||||
|
label="Type de journal (TYPE)"
|
||||||
|
id="type"
|
||||||
|
placeholder="Ex: VEN"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="select"
|
||||||
|
label="Colonnes (select)"
|
||||||
|
id="select"
|
||||||
|
placeholder="Ex: jnlid,jnlname"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="results"
|
||||||
|
label="Nombre de résultats"
|
||||||
|
id="results"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3">
|
<div class="mt-4 flex items-center gap-3">
|
||||||
<div>
|
<x-filament::button wire:click="searchJournaux" icon="heroicon-o-magnifying-glass">
|
||||||
<label for="type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Type de journal (TYPE)</label>
|
Rechercher
|
||||||
<input wire:model="type" type="text" id="type" placeholder="Ex: VEN"
|
</x-filament::button>
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
<div wire:loading wire:target="searchJournaux" class="flex items-center gap-2">
|
||||||
</div>
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
<div>
|
<span class="text-sm text-gray-500">Recherche en cours...</span>
|
||||||
<label for="select" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Colonnes (select)</label>
|
</div>
|
||||||
<input wire:model="select" type="text" id="select" placeholder="Ex: jnlid,jnlname"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="results" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nombre de resultats</label>
|
|
||||||
<input wire:model="results" type="number" id="results" min="1" max="100"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4">
|
|
||||||
<x-filament::button wire:click="searchJournaux" icon="heroicon-o-magnifying-glass">
|
|
||||||
Rechercher
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Resultats --}}
|
{{-- Resultats --}}
|
||||||
@if (count($data) > 0)
|
@if (count($data) > 0)
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<div class="flex items-center justify-between">
|
<x-logistics.section-header title="Résultats">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Resultats</h3>
|
<x-slot:actions>
|
||||||
@if ($metadata)
|
@if ($metadata)
|
||||||
<span class="text-sm text-gray-500">{{ $metadata['rowcount'] ?? 0 }} resultat(s)</span>
|
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
|
||||||
@endif
|
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</x-slot:actions>
|
||||||
|
</x-logistics.section-header>
|
||||||
|
<div class="p-6">
|
||||||
|
<x-logistics.data-table :data="$data" />
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<table class="w-full text-left text-sm">
|
|
||||||
<thead class="border-b border-gray-200 dark:border-white/10">
|
|
||||||
<tr>
|
|
||||||
@foreach (array_keys(is_array(reset($data)) ? reset($data) : $data) as $key)
|
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
|
||||||
@foreach ($data as $row)
|
|
||||||
<tr>
|
|
||||||
@foreach ((is_array($row) ? $row : [$row]) as $value)
|
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
@@ -1,85 +1,148 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
@if ($errorMessage)
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
|
||||||
{{ $errorMessage }}
|
@if ($tablesMetadata)
|
||||||
</div>
|
<x-logistics.stat-bar>
|
||||||
|
<x-logistics.stat-item icon="heroicon-o-server" :value="$tablesMetadata['endpoint'] ?? '-'" />
|
||||||
|
<x-logistics.stat-item icon="heroicon-o-circle-stack" label="Type :" :value="$tablesMetadata['folderType'] ?? '-'" />
|
||||||
|
<x-logistics.stat-item icon="heroicon-o-table-cells" :value="($tablesMetadata['tableCount'] ?? count($tables)) . ' table(s)'" />
|
||||||
|
</x-logistics.stat-bar>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||||
{{-- Liste des tables --}}
|
{{-- Panneau gauche : liste des tables --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card class="lg:col-span-1">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Tables disponibles</h3>
|
<x-logistics.section-header
|
||||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Cliquez sur une table pour voir ses colonnes.</p>
|
title="Tables disponibles"
|
||||||
|
description="Sélectionnez une table pour explorer ses colonnes."
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="mt-4 space-y-1">
|
@if (count($tables) > 6)
|
||||||
@forelse ($tables as $table)
|
<div class="px-6 pt-4">
|
||||||
|
<x-logistics.search-input
|
||||||
|
wire:model.live.debounce.200ms="tableFilter"
|
||||||
|
placeholder="Filtrer les tables..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="max-h-[32rem] space-y-0.5 overflow-y-auto p-2">
|
||||||
|
@forelse ($this->filteredTables as $table)
|
||||||
|
@php
|
||||||
|
$tableName = $table['name'] ?? '';
|
||||||
|
$columnCount = $table['columnCount'] ?? 0;
|
||||||
|
$isSelected = $selectedTable === $tableName;
|
||||||
|
@endphp
|
||||||
<button
|
<button
|
||||||
wire:click="$set('selectedTable', '{{ is_array($table) ? ($table['name'] ?? $table['tablename'] ?? '') : $table }}')"
|
wire:click="selectTable('{{ $tableName }}')"
|
||||||
wire:then="loadColumns"
|
wire:key="table-{{ $tableName }}"
|
||||||
class="flex w-full items-center rounded-lg px-3 py-2 text-left text-sm transition hover:bg-gray-50 dark:hover:bg-white/5 {{ $selectedTable === (is_array($table) ? ($table['name'] ?? $table['tablename'] ?? '') : $table) ? 'bg-primary-50 text-primary-600 dark:bg-primary-400/10 dark:text-primary-400' : 'text-gray-700 dark:text-gray-300' }}"
|
@class([
|
||||||
|
'flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-left text-sm transition-colors',
|
||||||
|
'bg-primary-50 text-primary-700 ring-1 ring-primary-200 dark:bg-primary-400/10 dark:text-primary-400 dark:ring-primary-400/30' => $isSelected,
|
||||||
|
'text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5' => ! $isSelected,
|
||||||
|
])
|
||||||
>
|
>
|
||||||
<x-filament::icon icon="heroicon-o-table-cells" class="mr-2 h-4 w-4" />
|
<div class="flex items-center gap-2.5">
|
||||||
{{ is_array($table) ? ($table['name'] ?? $table['tablename'] ?? json_encode($table)) : $table }}
|
<x-filament::icon
|
||||||
|
icon="heroicon-o-table-cells"
|
||||||
|
@class([
|
||||||
|
'h-4 w-4 shrink-0',
|
||||||
|
'text-primary-500 dark:text-primary-400' => $isSelected,
|
||||||
|
'text-gray-400' => ! $isSelected,
|
||||||
|
])
|
||||||
|
/>
|
||||||
|
<span class="font-mono font-medium">{{ $tableName }}</span>
|
||||||
|
</div>
|
||||||
|
<span @class([
|
||||||
|
'rounded-full px-2 py-0.5 text-xs font-medium tabular-nums',
|
||||||
|
'bg-primary-100 text-primary-700 dark:bg-primary-400/20 dark:text-primary-300' => $isSelected,
|
||||||
|
'bg-gray-100 text-gray-500 dark:bg-white/10 dark:text-gray-400' => ! $isSelected,
|
||||||
|
])>
|
||||||
|
{{ $columnCount }}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
@empty
|
@empty
|
||||||
<p class="py-4 text-center text-sm text-gray-500">Aucune table trouvee. Verifiez votre cle API.</p>
|
<x-logistics.empty-state
|
||||||
|
icon="heroicon-o-table-cells"
|
||||||
|
:title="filled($tableFilter) ? 'Aucune table ne correspond au filtre.' : 'Aucune table trouvée.'"
|
||||||
|
:description="filled($tableFilter) ? null : 'Vérifiez votre clé API.'"
|
||||||
|
/>
|
||||||
@endforelse
|
@endforelse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</x-logistics.card>
|
||||||
|
|
||||||
{{-- Colonnes de la table selectionnee --}}
|
{{-- Panneau droit : colonnes de la table selectionnee --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card class="lg:col-span-2">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">
|
<x-logistics.section-header :title="$selectedTable ? 'Colonnes de ' . $selectedTable : 'Colonnes'">
|
||||||
Colonnes
|
<x-slot:actions>
|
||||||
|
@if ($columnsMetadata && $selectedTable)
|
||||||
|
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
|
||||||
|
{{ $columnsMetadata['columnCount'] ?? count($columns) }} colonne(s)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</x-slot:actions>
|
||||||
|
</x-logistics.section-header>
|
||||||
|
|
||||||
|
<div class="p-6">
|
||||||
@if ($selectedTable)
|
@if ($selectedTable)
|
||||||
<span class="text-primary-600 dark:text-primary-400">: {{ $selectedTable }}</span>
|
<div wire:loading wire:target="selectTable" class="flex items-center justify-center py-12">
|
||||||
@endif
|
<x-filament::loading-indicator class="h-6 w-6 text-primary-500" />
|
||||||
</h3>
|
<span class="ml-3 text-sm text-gray-500">Chargement des colonnes...</span>
|
||||||
|
|
||||||
@if ($selectedTable)
|
|
||||||
<div class="mt-4">
|
|
||||||
<div wire:loading wire:target="loadColumns" class="py-8 text-center text-sm text-gray-500">
|
|
||||||
Chargement...
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div wire:loading.remove wire:target="loadColumns">
|
<div wire:loading.remove wire:target="selectTable">
|
||||||
@if (count($columns) > 0)
|
@if (count($columns) > 0)
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-left text-sm">
|
<table class="w-full text-left text-sm">
|
||||||
<thead class="border-b border-gray-200 dark:border-white/10">
|
<thead>
|
||||||
<tr>
|
<tr class="border-b border-gray-200 dark:border-white/10">
|
||||||
@if (is_array(reset($columns)))
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">Nom</th>
|
||||||
@foreach (array_keys(reset($columns)) as $key)
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">Type</th>
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">Longueur</th>
|
||||||
@endforeach
|
<th class="px-3 py-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">Précision</th>
|
||||||
@else
|
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">Colonne</th>
|
|
||||||
@endif
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
||||||
@foreach ($columns as $column)
|
@foreach ($columns as $column)
|
||||||
<tr>
|
@php
|
||||||
@if (is_array($column))
|
$dataType = strtoupper($column['dataType'] ?? '');
|
||||||
@foreach ($column as $value)
|
$typeLabel = \App\Filament\Pages\TablesExplorer::getDataTypeLabel($dataType);
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
@endphp
|
||||||
@endforeach
|
<tr class="transition-colors hover:bg-gray-50 dark:hover:bg-white/5">
|
||||||
@else
|
<td class="px-3 py-2.5">
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ $column }}</td>
|
<span class="font-mono text-sm font-medium text-gray-900 dark:text-white">{{ $column['name'] ?? '-' }}</span>
|
||||||
@endif
|
</td>
|
||||||
|
<td class="px-3 py-2.5">
|
||||||
|
<span @class([
|
||||||
|
'inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset',
|
||||||
|
'bg-blue-50 text-blue-700 ring-blue-600/20 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30' => $dataType === 'C',
|
||||||
|
'bg-emerald-50 text-emerald-700 ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/30' => $dataType === 'N',
|
||||||
|
'bg-violet-50 text-violet-700 ring-violet-600/20 dark:bg-violet-400/10 dark:text-violet-400 dark:ring-violet-400/30' => in_array($dataType, ['T', 'D']),
|
||||||
|
'bg-amber-50 text-amber-700 ring-amber-600/20 dark:bg-amber-400/10 dark:text-amber-400 dark:ring-amber-400/30' => $dataType === 'L',
|
||||||
|
'bg-gray-50 text-gray-700 ring-gray-600/20 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/30' => ! in_array($dataType, ['C', 'N', 'T', 'D', 'L']),
|
||||||
|
])>
|
||||||
|
{{ $typeLabel }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2.5 tabular-nums text-gray-600 dark:text-gray-300">{{ $column['length'] ?? '-' }}</td>
|
||||||
|
<td class="px-3 py-2.5 tabular-nums text-gray-600 dark:text-gray-300">{{ $column['precision'] ?? '-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<p class="py-4 text-center text-sm text-gray-500">Aucune colonne trouvee.</p>
|
<x-logistics.empty-state icon="heroicon-o-inbox" title="Aucune colonne trouvée pour cette table." />
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@else
|
||||||
@else
|
<x-logistics.empty-state
|
||||||
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">Selectionnez une table pour afficher ses colonnes.</p>
|
icon="heroicon-o-cursor-arrow-rays"
|
||||||
@endif
|
title="Aucune table sélectionnée"
|
||||||
</div>
|
description="Choisissez une table dans la liste pour afficher ses colonnes."
|
||||||
|
/>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
</div>
|
</div>
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
@@ -1,91 +1,89 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
@if ($errorMessage)
|
<x-logistics.error-banner :message="$errorMessage" />
|
||||||
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
|
|
||||||
{{ $errorMessage }}
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- Formulaire de recherche --}}
|
{{-- Formulaire de recherche --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Rechercher des tiers</h3>
|
<x-logistics.section-header title="Rechercher des tiers" />
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="search"
|
||||||
|
label="Recherche (obligatoire)"
|
||||||
|
id="search"
|
||||||
|
placeholder="Filtre de recherche..."
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="select"
|
||||||
|
label="Colonnes (select)"
|
||||||
|
id="select"
|
||||||
|
placeholder="custid,custname"
|
||||||
|
/>
|
||||||
|
<x-logistics.form-field
|
||||||
|
wire:model="results"
|
||||||
|
label="Nombre de résultats"
|
||||||
|
id="results"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3">
|
<div class="mt-4 flex items-center gap-3">
|
||||||
<div>
|
<x-filament::button wire:click="searchTiers" icon="heroicon-o-magnifying-glass">
|
||||||
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Recherche (obligatoire)</label>
|
Rechercher
|
||||||
<input wire:model="search" type="text" id="search" placeholder="Filtre de recherche..."
|
</x-filament::button>
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
<div wire:loading wire:target="searchTiers" class="flex items-center gap-2">
|
||||||
</div>
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
<div>
|
<span class="text-sm text-gray-500">Recherche en cours...</span>
|
||||||
<label for="select" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Colonnes (select)</label>
|
</div>
|
||||||
<input wire:model="select" type="text" id="select" placeholder="custid,custname"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="results" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nombre de resultats</label>
|
|
||||||
<input wire:model="results" type="number" id="results" min="1" max="100"
|
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4">
|
|
||||||
<x-filament::button wire:click="searchTiers" icon="heroicon-o-magnifying-glass">
|
|
||||||
Rechercher
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Resultats --}}
|
{{-- Resultats --}}
|
||||||
@if (count($data) > 0)
|
@if (count($data) > 0)
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<div class="flex items-center justify-between">
|
<x-logistics.section-header title="Résultats">
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Resultats</h3>
|
<x-slot:actions>
|
||||||
@if ($metadata)
|
@if ($metadata)
|
||||||
<span class="text-sm text-gray-500">{{ $metadata['rowcount'] ?? 0 }} resultat(s)</span>
|
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
|
||||||
@endif
|
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</x-slot:actions>
|
||||||
|
</x-logistics.section-header>
|
||||||
|
<div class="p-6">
|
||||||
|
<x-logistics.data-table :data="$data" />
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<table class="w-full text-left text-sm">
|
|
||||||
<thead class="border-b border-gray-200 dark:border-white/10">
|
|
||||||
<tr>
|
|
||||||
@foreach (array_keys(is_array(reset($data)) ? reset($data) : $data) as $key)
|
|
||||||
<th class="px-3 py-2 font-medium text-gray-500 dark:text-gray-400">{{ $key }}</th>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="divide-y divide-gray-100 dark:divide-white/5">
|
|
||||||
@foreach ($data as $row)
|
|
||||||
<tr>
|
|
||||||
@foreach ((is_array($row) ? $row : [$row]) as $value)
|
|
||||||
<td class="px-3 py-2 text-gray-700 dark:text-gray-300">{{ is_array($value) ? json_encode($value) : $value }}</td>
|
|
||||||
@endforeach
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Historique des articles d'un tiers --}}
|
{{-- Historique des articles d'un tiers --}}
|
||||||
<div class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<x-logistics.card>
|
||||||
<h3 class="text-base font-semibold text-gray-950 dark:text-white">Historique des articles d'un tiers</h3>
|
<x-logistics.section-header title="Historique des articles d'un tiers" />
|
||||||
|
<div class="p-6">
|
||||||
<div class="mt-4 flex items-end gap-4">
|
<div class="flex items-end gap-4">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<label for="historyThirdId" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Identifiant tiers (thirdid)</label>
|
<x-logistics.form-field
|
||||||
<input wire:model="historyThirdId" type="text" id="historyThirdId" placeholder="Ex: CUST001"
|
wire:model="historyThirdId"
|
||||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-white/10 dark:bg-white/5 dark:text-white sm:text-sm" />
|
label="Identifiant tiers (thirdid)"
|
||||||
|
id="historyThirdId"
|
||||||
|
placeholder="Ex: CUST001"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<x-filament::button wire:click="getArtHistory" icon="heroicon-o-clock">
|
||||||
|
Voir l'historique
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div wire:loading wire:target="getArtHistory" class="mt-4 flex items-center gap-2">
|
||||||
|
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||||
|
<span class="text-sm text-gray-500">Chargement...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div wire:loading.remove wire:target="getArtHistory" class="mt-4">
|
||||||
|
<x-logistics.json-block :data="$historyData" />
|
||||||
</div>
|
</div>
|
||||||
<x-filament::button wire:click="getArtHistory" icon="heroicon-o-clock">
|
|
||||||
Voir l'historique
|
|
||||||
</x-filament::button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</x-logistics.card>
|
||||||
@if (count($historyData) > 0)
|
|
||||||
<div class="mt-4 overflow-x-auto">
|
|
||||||
<pre class="rounded-lg bg-gray-50 p-4 text-sm text-gray-700 dark:bg-gray-800 dark:text-gray-300">{{ json_encode($historyData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
122
resources/views/pdf/documentation.blade.php
Normal file
122
resources/views/pdf/documentation.blade.php
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Documentation API Logistics</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: DejaVu Sans, sans-serif;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
border-bottom: 2px solid #2563eb;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 17px;
|
||||||
|
color: #1e40af;
|
||||||
|
border-bottom: 1px solid #cbd5e1;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #334155;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #475569;
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
border: 1px solid #cbd5e1;
|
||||||
|
padding: 5px 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background-color: #f1f5f9;
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: DejaVu Sans Mono, monospace;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: #f1f5f9;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 3px solid #2563eb;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: #eff6ff;
|
||||||
|
color: #1e40af;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #cbd5e1;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #2563eb;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-break {
|
||||||
|
page-break-after: always;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{!! $content !!}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
@@ -10,4 +12,15 @@ Route::view('dashboard', 'dashboard')
|
|||||||
->middleware(['auth', 'verified'])
|
->middleware(['auth', 'verified'])
|
||||||
->name('dashboard');
|
->name('dashboard');
|
||||||
|
|
||||||
|
Route::get('/documentation/download-pdf', function () {
|
||||||
|
$markdown = file_get_contents(base_path('documentation/documentation_api_logistics.md'));
|
||||||
|
$htmlContent = Str::markdown($markdown);
|
||||||
|
|
||||||
|
$html = view('pdf.documentation', ['content' => $htmlContent])->render();
|
||||||
|
|
||||||
|
return Pdf::loadHTML($html)
|
||||||
|
->setPaper('a4')
|
||||||
|
->download('documentation_api_logistics.pdf');
|
||||||
|
})->name('documentation.download-pdf');
|
||||||
|
|
||||||
require __DIR__.'/settings.php';
|
require __DIR__.'/settings.php';
|
||||||
|
|||||||
63
tests/Feature/DocumentationTest.php
Normal file
63
tests/Feature/DocumentationTest.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Pages\Documentation;
|
||||||
|
use App\Models\User;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->actingAs(User::factory()->create());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the documentation page', function () {
|
||||||
|
Livewire::test(Documentation::class)
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertSee('Documentation API Logistics');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts markdown to HTML content', function () {
|
||||||
|
$component = Livewire::test(Documentation::class);
|
||||||
|
|
||||||
|
expect($component->get('htmlContent'))
|
||||||
|
->toBeString()
|
||||||
|
->not->toBeEmpty()
|
||||||
|
->toContain('<h1>')
|
||||||
|
->toContain('<table>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the main documentation sections', function () {
|
||||||
|
Livewire::test(Documentation::class)
|
||||||
|
->assertSee('Pré-requis')
|
||||||
|
->assertSee('Comment effectuer des requêtes')
|
||||||
|
->assertSee('Structure de réponse')
|
||||||
|
->assertSee('Tables et colonnes disponibles')
|
||||||
|
->assertSee('Récupération de données')
|
||||||
|
->assertSee('Envoi de données');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('downloads the documentation as PDF', function () {
|
||||||
|
$response = $this->get(route('documentation.download-pdf'));
|
||||||
|
|
||||||
|
$response->assertSuccessful()
|
||||||
|
->assertHeader('content-type', 'application/pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('documents all service endpoints', function () {
|
||||||
|
Livewire::test(Documentation::class)
|
||||||
|
->assertSee('tables_list')
|
||||||
|
->assertSee('column_list')
|
||||||
|
->assertSee('art_list')
|
||||||
|
->assertSee('art_getstk')
|
||||||
|
->assertSee('jnl_list')
|
||||||
|
->assertSee('document_list')
|
||||||
|
->assertSee('document_detail')
|
||||||
|
->assertSee('document_add')
|
||||||
|
->assertSee('document_mod')
|
||||||
|
->assertSee('Document_GetStatusList')
|
||||||
|
->assertSee('Document_GetUnitPriceAndVat')
|
||||||
|
->assertSee('Document_GetDueDate')
|
||||||
|
->assertSee('Document_GetAttachListThumbnail')
|
||||||
|
->assertSee('third_list')
|
||||||
|
->assertSee('third_GetArtHistory')
|
||||||
|
->assertSee('getserialnumber')
|
||||||
|
->assertSee('codes_list');
|
||||||
|
});
|
||||||
46
tests/Feature/FilamentDashboardTest.php
Normal file
46
tests/Feature/FilamentDashboardTest.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Pages\Dashboard;
|
||||||
|
use App\Models\User;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->actingAs(User::factory()->create());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the dashboard page', function () {
|
||||||
|
Livewire::test(Dashboard::class)
|
||||||
|
->assertSuccessful();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the project title and description', function () {
|
||||||
|
Livewire::test(Dashboard::class)
|
||||||
|
->assertSee('Bienvenue sur API Logistics')
|
||||||
|
->assertSee('Flex/ESI Gescom');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows navigation links to all pages', function () {
|
||||||
|
Livewire::test(Dashboard::class)
|
||||||
|
->assertSee('Tables')
|
||||||
|
->assertSee('Articles')
|
||||||
|
->assertSee('Documents')
|
||||||
|
->assertSee('Journaux')
|
||||||
|
->assertSee('Tiers')
|
||||||
|
->assertSee('Documentation');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays project statistics', function () {
|
||||||
|
Livewire::test(Dashboard::class)
|
||||||
|
->assertSee('Endpoints API')
|
||||||
|
->assertSee('Tables accessibles')
|
||||||
|
->assertSee('Pages Filament')
|
||||||
|
->assertSee('Tests Pest');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows technical information', function () {
|
||||||
|
Livewire::test(Dashboard::class)
|
||||||
|
->assertSee('Informations techniques')
|
||||||
|
->assertSee('Laravel 12')
|
||||||
|
->assertSee('Filament 5')
|
||||||
|
->assertSee('Livewire 4');
|
||||||
|
});
|
||||||
147
tests/Feature/TablesExplorerTest.php
Normal file
147
tests/Feature/TablesExplorerTest.php
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Pages\TablesExplorer;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
config([
|
||||||
|
'logistics.base_url' => 'http://test-server.local',
|
||||||
|
'logistics.api_key' => 'test-api-key',
|
||||||
|
'logistics.folder' => 'testfolder',
|
||||||
|
'logistics.timeout' => 30,
|
||||||
|
'logistics.connect_timeout' => 10,
|
||||||
|
'logistics.retry.times' => 1,
|
||||||
|
'logistics.retry.sleep_ms' => 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->actingAs(User::factory()->create());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads the tables list on mount', function () {
|
||||||
|
Http::fake([
|
||||||
|
'*/tables_list' => Http::response([
|
||||||
|
'data' => [
|
||||||
|
['name' => 'art', 'columnCount' => 160],
|
||||||
|
['name' => 'cust', 'columnCount' => 216],
|
||||||
|
],
|
||||||
|
'metadata' => ['tableCount' => 2, 'folderType' => 'DBF', 'endpoint' => 'test'],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test(TablesExplorer::class)
|
||||||
|
->assertSet('tables', [
|
||||||
|
['name' => 'art', 'columnCount' => 160],
|
||||||
|
['name' => 'cust', 'columnCount' => 216],
|
||||||
|
])
|
||||||
|
->assertSee('art')
|
||||||
|
->assertSee('cust')
|
||||||
|
->assertSee('160')
|
||||||
|
->assertSee('216');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads columns when a table is selected', function () {
|
||||||
|
Http::fake([
|
||||||
|
'*/tables_list' => Http::response([
|
||||||
|
'data' => [['name' => 'stk', 'columnCount' => 10]],
|
||||||
|
'metadata' => ['tableCount' => 1],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
'*/column_list/stk' => Http::response([
|
||||||
|
'data' => [
|
||||||
|
['name' => 'ARTID', 'dataType' => 'C', 'length' => 20, 'precision' => 0],
|
||||||
|
['name' => 'ARTID', 'dataType' => 'C', 'length' => 20, 'precision' => 0],
|
||||||
|
['name' => 'STOCK', 'dataType' => 'N', 'length' => 10, 'precision' => 2],
|
||||||
|
['name' => 'STOCK', 'dataType' => 'N', 'length' => 10, 'precision' => 2],
|
||||||
|
],
|
||||||
|
'metadata' => ['columnCount' => 4, 'tableName' => 'stk'],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test(TablesExplorer::class)
|
||||||
|
->call('selectTable', 'stk')
|
||||||
|
->assertSet('selectedTable', 'stk')
|
||||||
|
->assertSee('ARTID')
|
||||||
|
->assertSee('STOCK')
|
||||||
|
->assertSee('Caractère')
|
||||||
|
->assertSee('Numérique');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deduplicates columns from the API response', function () {
|
||||||
|
Http::fake([
|
||||||
|
'*/tables_list' => Http::response([
|
||||||
|
'data' => [['name' => 'stk', 'columnCount' => 4]],
|
||||||
|
'metadata' => ['tableCount' => 1],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
'*/column_list/stk' => Http::response([
|
||||||
|
'data' => [
|
||||||
|
['name' => 'ARTID', 'dataType' => 'C', 'length' => 20, 'precision' => 0],
|
||||||
|
['name' => 'ARTID', 'dataType' => 'C', 'length' => 20, 'precision' => 0],
|
||||||
|
['name' => 'STOCK', 'dataType' => 'N', 'length' => 10, 'precision' => 2],
|
||||||
|
['name' => 'STOCK', 'dataType' => 'N', 'length' => 10, 'precision' => 2],
|
||||||
|
],
|
||||||
|
'metadata' => ['columnCount' => 4],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test(TablesExplorer::class)
|
||||||
|
->call('selectTable', 'stk')
|
||||||
|
->assertSet('columns', [
|
||||||
|
['name' => 'ARTID', 'dataType' => 'C', 'length' => 20, 'precision' => 0],
|
||||||
|
['name' => 'STOCK', 'dataType' => 'N', 'length' => 10, 'precision' => 2],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters tables by name', function () {
|
||||||
|
Http::fake([
|
||||||
|
'*/tables_list' => Http::response([
|
||||||
|
'data' => [
|
||||||
|
['name' => 'art', 'columnCount' => 160],
|
||||||
|
['name' => 'attach', 'columnCount' => 13],
|
||||||
|
['name' => 'cust', 'columnCount' => 216],
|
||||||
|
['name' => 'dochead', 'columnCount' => 212],
|
||||||
|
['name' => 'docdet', 'columnCount' => 82],
|
||||||
|
['name' => 'docpay', 'columnCount' => 22],
|
||||||
|
['name' => 'stk', 'columnCount' => 20],
|
||||||
|
],
|
||||||
|
'metadata' => ['tableCount' => 7],
|
||||||
|
'error' => null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$component = Livewire::test(TablesExplorer::class)
|
||||||
|
->set('tableFilter', 'doc');
|
||||||
|
|
||||||
|
$filteredTables = $component->get('filteredTables');
|
||||||
|
|
||||||
|
expect($filteredTables)->toHaveCount(3)
|
||||||
|
->and(array_column($filteredTables, 'name'))->toBe(['dochead', 'docdet', 'docpay']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays an error message when the API fails', function () {
|
||||||
|
Http::fake([
|
||||||
|
'*/tables_list' => Http::response([
|
||||||
|
'data' => [],
|
||||||
|
'metadata' => [],
|
||||||
|
'error' => 'Invalid API key',
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test(TablesExplorer::class)
|
||||||
|
->assertSee('Invalid API key');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows data type labels correctly', function () {
|
||||||
|
expect(TablesExplorer::getDataTypeLabel('C'))->toBe('Caractère')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('N'))->toBe('Numérique')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('T'))->toBe('Date/Heure')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('D'))->toBe('Date')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('L'))->toBe('Logique')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('M'))->toBe('Mémo')
|
||||||
|
->and(TablesExplorer::getDataTypeLabel('X'))->toBe('X');
|
||||||
|
});
|
||||||
@@ -7,7 +7,7 @@ import tailwindcss from "@tailwindcss/vite";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
laravel({
|
laravel({
|
||||||
input: ['resources/css/app.css', 'resources/js/app.js'],
|
input: ['resources/css/app.css', 'resources/js/app.js', 'resources/css/filament/admin/theme.css'],
|
||||||
refresh: true,
|
refresh: true,
|
||||||
}),
|
}),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
|
|||||||
Reference in New Issue
Block a user