- Added UrlStateService to sync app state with URL parameters for note selection, tags, folders, and search - Implemented URL state effects in AppComponent to handle navigation from URL parameters - Updated sidebar and layout components to reflect URL state changes in UI - Added URL state updates when navigating via note selection, tag clicks, and search - Modified note sharing to use URL parameters instead of route paths - Added auto-opening of relevant
		
			
				
	
	
		
			585 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			585 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# UrlStateService - Exemples d'URL et Cas d'Usage
 | 
						|
 | 
						|
## 📌 Table des matières
 | 
						|
 | 
						|
1. [Exemples simples](#exemples-simples)
 | 
						|
2. [Exemples combinés](#exemples-combinés)
 | 
						|
3. [Cas d'usage réels](#cas-dusage-réels)
 | 
						|
4. [Partage de liens](#partage-de-liens)
 | 
						|
5. [Gestion des erreurs](#gestion-des-erreurs)
 | 
						|
6. [Bonnes pratiques](#bonnes-pratiques)
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Exemples Simples
 | 
						|
 | 
						|
### 1. Ouvrir une note
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=Docs/Architecture.md
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- La note `Docs/Architecture.md` s'ouvre dans la vue note
 | 
						|
- Le contenu est chargé et affiché
 | 
						|
- La note est mise en surbrillance dans la liste
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.openNote('Docs/Architecture.md');
 | 
						|
```
 | 
						|
 | 
						|
### 2. Filtrer par tag
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?tag=Ideas
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche toutes les notes avec le tag `Ideas`
 | 
						|
- Le tag est mis en surbrillance dans la liste des tags
 | 
						|
- La liste des notes est filtrée
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByTag('Ideas');
 | 
						|
```
 | 
						|
 | 
						|
### 3. Filtrer par dossier
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Notes/Meetings
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche toutes les notes du dossier `Notes/Meetings`
 | 
						|
- Le dossier est mis en surbrillance dans l'arborescence
 | 
						|
- La liste des notes est filtrée
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByFolder('Notes/Meetings');
 | 
						|
```
 | 
						|
 | 
						|
### 4. Afficher un quick link
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Favoris
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche les notes marquées comme favoris
 | 
						|
- Le quick link est mis en surbrillance
 | 
						|
- La liste des notes est filtrée
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByQuickLink('Favoris');
 | 
						|
```
 | 
						|
 | 
						|
### 5. Rechercher
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?search=performance
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche les résultats de recherche pour "performance"
 | 
						|
- Les notes contenant le terme sont listées
 | 
						|
- Le terme est mis en surbrillance
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.updateSearch('performance');
 | 
						|
```
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Exemples Combinés
 | 
						|
 | 
						|
### 1. Note avec recherche
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=Docs/Architecture.md&search=performance
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Ouvre la note `Docs/Architecture.md`
 | 
						|
- Met en surbrillance les occurrences de "performance"
 | 
						|
- Permet de naviguer entre les occurrences
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.openNote('Docs/Architecture.md');
 | 
						|
await this.urlState.updateSearch('performance');
 | 
						|
```
 | 
						|
 | 
						|
### 2. Dossier avec tag
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Notes/Meetings&tag=Important
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche les notes du dossier `Notes/Meetings`
 | 
						|
- Filtre par le tag `Important`
 | 
						|
- Affiche l'intersection des deux filtres
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByFolder('Notes/Meetings');
 | 
						|
await this.urlState.filterByTag('Important');
 | 
						|
```
 | 
						|
 | 
						|
### 3. Quick link avec recherche
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Archive&search=2024
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche les notes archivées
 | 
						|
- Filtre par le terme "2024"
 | 
						|
- Affiche les notes archivées contenant "2024"
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByQuickLink('Archive');
 | 
						|
await this.urlState.updateSearch('2024');
 | 
						|
```
 | 
						|
 | 
						|
### 4. Dossier avec recherche
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Journal&search=2025
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Affiche les notes du dossier `Journal`
 | 
						|
- Filtre par le terme "2025"
 | 
						|
- Affiche les notes du journal contenant "2025"
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
await this.urlState.filterByFolder('Journal');
 | 
						|
await this.urlState.updateSearch('2025');
 | 
						|
```
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Cas d'Usage Réels
 | 
						|
 | 
						|
### 1. Documentation d'Architecture
 | 
						|
 | 
						|
**Scénario:** Vous travaillez sur l'architecture et voulez partager une note spécifique avec votre équipe.
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=Docs/Architecture.md
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Lien direct vers la note
 | 
						|
- Pas besoin de naviguer manuellement
 | 
						|
- Contexte clair pour l'équipe
 | 
						|
 | 
						|
### 2. Réunion d'équipe
 | 
						|
 | 
						|
**Scénario:** Vous voulez afficher les notes de réunion d'un mois spécifique.
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Notes/Meetings/2025-01&tag=Important
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Filtre par dossier et tag
 | 
						|
- Affiche uniquement les réunions importantes
 | 
						|
- Facile à partager avec l'équipe
 | 
						|
 | 
						|
### 3. Recherche de bug
 | 
						|
 | 
						|
**Scénario:** Vous cherchez des notes contenant "bug" dans le dossier "Issues".
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Issues&search=bug
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Recherche ciblée dans un dossier
 | 
						|
- Résultats pertinents
 | 
						|
- Facile à reproduire
 | 
						|
 | 
						|
### 4. Favoris du projet
 | 
						|
 | 
						|
**Scénario:** Vous voulez afficher les notes favorites du projet "ProjectX".
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Favoris&search=ProjectX
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Affiche les favoris
 | 
						|
- Filtre par projet
 | 
						|
- Vue d'ensemble rapide
 | 
						|
 | 
						|
### 5. Tâches urgentes
 | 
						|
 | 
						|
**Scénario:** Vous voulez voir les tâches urgentes du jour.
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Tâches&tag=Urgent
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Affiche les tâches
 | 
						|
- Filtre par urgence
 | 
						|
- Priorisation facile
 | 
						|
 | 
						|
### 6. Brouillons à publier
 | 
						|
 | 
						|
**Scénario:** Vous voulez voir les brouillons prêts à être publiés.
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Brouillons&tag=Prêt
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Affiche les brouillons
 | 
						|
- Filtre par statut
 | 
						|
- Workflow clair
 | 
						|
 | 
						|
### 7. Archive par année
 | 
						|
 | 
						|
**Scénario:** Vous voulez consulter l'archive de 2024.
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=Archive/2024
 | 
						|
```
 | 
						|
 | 
						|
**Avantages:**
 | 
						|
- Affiche l'archive d'une année
 | 
						|
- Navigation facile
 | 
						|
- Historique accessible
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Partage de Liens
 | 
						|
 | 
						|
### 1. Partage simple
 | 
						|
 | 
						|
**Scénario:** Vous voulez partager une note avec un collègue.
 | 
						|
 | 
						|
```typescript
 | 
						|
// Générer le lien
 | 
						|
const shareUrl = this.urlState.generateShareUrl();
 | 
						|
 | 
						|
// Copier dans le presse-papiers
 | 
						|
await this.urlState.copyCurrentUrlToClipboard();
 | 
						|
 | 
						|
// Afficher un toast
 | 
						|
this.toast.success('Lien copié!');
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=Docs/Architecture.md
 | 
						|
```
 | 
						|
 | 
						|
### 2. Partage avec contexte
 | 
						|
 | 
						|
**Scénario:** Vous voulez partager une note avec un contexte de recherche.
 | 
						|
 | 
						|
```typescript
 | 
						|
// Générer le lien avec contexte
 | 
						|
const shareUrl = this.urlState.generateShareUrl({
 | 
						|
  note: 'Docs/Architecture.md',
 | 
						|
  search: 'performance'
 | 
						|
});
 | 
						|
 | 
						|
// Partager
 | 
						|
await navigator.clipboard.writeText(shareUrl);
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=Docs/Architecture.md&search=performance
 | 
						|
```
 | 
						|
 | 
						|
### 3. Partage de filtre
 | 
						|
 | 
						|
**Scénario:** Vous voulez partager un filtre avec votre équipe.
 | 
						|
 | 
						|
```typescript
 | 
						|
// Appliquer le filtre
 | 
						|
await this.urlState.filterByTag('Ideas');
 | 
						|
 | 
						|
// Générer et copier le lien
 | 
						|
const shareUrl = this.urlState.generateShareUrl();
 | 
						|
await navigator.clipboard.writeText(shareUrl);
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?tag=Ideas
 | 
						|
```
 | 
						|
 | 
						|
### 4. Bouton de partage
 | 
						|
 | 
						|
**Scénario:** Vous voulez ajouter un bouton de partage dans l'interface.
 | 
						|
 | 
						|
```typescript
 | 
						|
@Component({
 | 
						|
  selector: 'app-share-button',
 | 
						|
  template: `
 | 
						|
    <button (click)="shareCurrentState()" class="share-btn">
 | 
						|
      📤 Partager
 | 
						|
    </button>
 | 
						|
  `
 | 
						|
})
 | 
						|
export class ShareButtonComponent {
 | 
						|
  urlState = inject(UrlStateService);
 | 
						|
  toast = inject(ToastService);
 | 
						|
  
 | 
						|
  async shareCurrentState(): Promise<void> {
 | 
						|
    try {
 | 
						|
      await this.urlState.copyCurrentUrlToClipboard();
 | 
						|
      this.toast.success('Lien copié!');
 | 
						|
    } catch (error) {
 | 
						|
      this.toast.error('Erreur lors de la copie');
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Gestion des Erreurs
 | 
						|
 | 
						|
### 1. Note introuvable
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?note=NonExistent.md
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Message d'avertissement dans la console
 | 
						|
- L'état n'est pas mis à jour
 | 
						|
- L'interface reste dans l'état précédent
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
try {
 | 
						|
  await this.urlState.openNote('NonExistent.md');
 | 
						|
} catch (error) {
 | 
						|
  console.error('Note not found');
 | 
						|
  this.toast.error('Note introuvable');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 2. Tag inexistant
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?tag=NonExistent
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Message d'avertissement dans la console
 | 
						|
- L'état n'est pas mis à jour
 | 
						|
- L'interface reste dans l'état précédent
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
try {
 | 
						|
  await this.urlState.filterByTag('NonExistent');
 | 
						|
} catch (error) {
 | 
						|
  console.error('Tag not found');
 | 
						|
  this.toast.warning('Tag inexistant');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 3. Dossier inexistant
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?folder=NonExistent
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Message d'avertissement dans la console
 | 
						|
- L'état n'est pas mis à jour
 | 
						|
- L'interface reste dans l'état précédent
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
try {
 | 
						|
  await this.urlState.filterByFolder('NonExistent');
 | 
						|
} catch (error) {
 | 
						|
  console.error('Folder not found');
 | 
						|
  this.toast.warning('Dossier inexistant');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 4. Quick link invalide
 | 
						|
 | 
						|
**URL:**
 | 
						|
```
 | 
						|
https://app.example.com/viewer?quick=Invalid
 | 
						|
```
 | 
						|
 | 
						|
**Résultat:**
 | 
						|
- Message d'avertissement dans la console
 | 
						|
- L'état n'est pas mis à jour
 | 
						|
- L'interface reste dans l'état précédent
 | 
						|
 | 
						|
**Code:**
 | 
						|
```typescript
 | 
						|
try {
 | 
						|
  await this.urlState.filterByQuickLink('Invalid');
 | 
						|
} catch (error) {
 | 
						|
  console.error('Invalid quick link');
 | 
						|
  this.toast.warning('Quick link invalide');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Bonnes Pratiques
 | 
						|
 | 
						|
### 1. Toujours valider les données
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas de validation
 | 
						|
await this.urlState.openNote(userInput);
 | 
						|
 | 
						|
// ✅ Bon - Validation
 | 
						|
const note = this.vault.allNotes().find(n => n.filePath === userInput);
 | 
						|
if (note) {
 | 
						|
  await this.urlState.openNote(userInput);
 | 
						|
} else {
 | 
						|
  this.toast.error('Note introuvable');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 2. Gérer les erreurs
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas de gestion d'erreur
 | 
						|
await this.urlState.filterByTag(userInput);
 | 
						|
 | 
						|
// ✅ Bon - Gestion d'erreur
 | 
						|
try {
 | 
						|
  await this.urlState.filterByTag(userInput);
 | 
						|
} catch (error) {
 | 
						|
  console.error('Error:', error);
 | 
						|
  this.toast.error('Erreur lors du filtrage');
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 3. Utiliser les signaux
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas réactif
 | 
						|
const tag = this.urlState.currentState().tag;
 | 
						|
 | 
						|
// ✅ Bon - Réactif
 | 
						|
const tag = this.urlState.activeTag;
 | 
						|
```
 | 
						|
 | 
						|
### 4. Écouter les changements
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas d'écoute
 | 
						|
this.urlState.openNote('Note.md');
 | 
						|
 | 
						|
// ✅ Bon - Écouter les changements
 | 
						|
effect(() => {
 | 
						|
  const note = this.urlState.currentNote();
 | 
						|
  if (note) {
 | 
						|
    console.log('Note changed:', note.title);
 | 
						|
  }
 | 
						|
});
 | 
						|
```
 | 
						|
 | 
						|
### 5. Nettoyer les ressources
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas de nettoyage
 | 
						|
this.urlState.stateChange$.subscribe(event => {
 | 
						|
  console.log('State changed:', event);
 | 
						|
});
 | 
						|
 | 
						|
// ✅ Bon - Nettoyage
 | 
						|
private destroy$ = new Subject<void>();
 | 
						|
 | 
						|
constructor() {
 | 
						|
  this.urlState.stateChange$
 | 
						|
    .pipe(takeUntil(this.destroy$))
 | 
						|
    .subscribe(event => {
 | 
						|
      console.log('State changed:', event);
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
ngOnDestroy() {
 | 
						|
  this.destroy$.next();
 | 
						|
  this.destroy$.complete();
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
### 6. Utiliser les types
 | 
						|
 | 
						|
```typescript
 | 
						|
// ❌ Mauvais - Pas de types
 | 
						|
const state = this.urlState.currentState();
 | 
						|
 | 
						|
// ✅ Bon - Avec types
 | 
						|
const state: UrlState = this.urlState.currentState();
 | 
						|
```
 | 
						|
 | 
						|
### 7. Documenter les URLs
 | 
						|
 | 
						|
```typescript
 | 
						|
/**
 | 
						|
 * Ouvre une note spécifique
 | 
						|
 * 
 | 
						|
 * URL: /viewer?note=Docs/Architecture.md
 | 
						|
 * 
 | 
						|
 * @param notePath - Chemin de la note (ex: 'Docs/Architecture.md')
 | 
						|
 */
 | 
						|
async openNote(notePath: string): Promise<void> {
 | 
						|
  // ...
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
## Résumé
 | 
						|
 | 
						|
Le `UrlStateService` offre une solution flexible pour gérer l'état de l'interface via l'URL:
 | 
						|
 | 
						|
- ✅ Exemples simples pour les cas courants
 | 
						|
- ✅ Exemples combinés pour les cas complexes
 | 
						|
- ✅ Cas d'usage réels pour l'inspiration
 | 
						|
- ✅ Partage de liens facile
 | 
						|
- ✅ Gestion des erreurs robuste
 | 
						|
- ✅ Bonnes pratiques pour la qualité du code
 | 
						|
 | 
						|
Utilisez ces exemples comme base pour intégrer le service dans votre application.
 | 
						|
 |