-
Notifications
You must be signed in to change notification settings - Fork 0
feat(form-assistant): wire Settings toggle and extend to all connectors #279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,6 +81,7 @@ export class SettingsPageController { | |
| private readonly shippedConnectorCatalog: readonly ConnectorMeta[]; | ||
| private readonly resetAvailability: LocalDataResetRuntimeAvailability; | ||
| private readonly unsubscribeProfileMessages = this.subscribeProfileMessages(); | ||
| private readonly unsubscribeFormAssistMessages = this.subscribeFormAssistMessages(); | ||
| private readonly unsubscribeSettingsSnapshots: () => void; | ||
|
|
||
| private readonly profileActor = createProfileStore({ | ||
|
|
@@ -127,6 +128,14 @@ export class SettingsPageController { | |
| connectedPendingDownloads = $state(0); | ||
| connectedSyncError = $state<string | null>(null); | ||
|
|
||
| /** | ||
| * Form Assistant activation (Machine D — src/models/form-assistant.model.md). | ||
| * Miroir de l'état persisté dans le SW (chrome.storage.local). Le toggle ne | ||
| * écrit JAMAIS directement en storage : il émet FORM_ASSIST_ENABLE via bridge. | ||
| */ | ||
| formAssistEnabled = $state(false); | ||
| formAssistStatus = $state<'loading' | 'ready' | 'error'>('loading'); | ||
|
|
||
| showResetConfirm = $state(false); | ||
| resetError = $state<string | null>(null); | ||
|
|
||
|
|
@@ -173,8 +182,26 @@ export class SettingsPageController { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Racolement Machine D : le SW diffuse FORM_ASSIST_ENABLED après toute | ||
| * mutation persistée. Le panel est un miroir, jamais la source primaire. | ||
| */ | ||
| private subscribeFormAssistMessages(): () => void { | ||
| try { | ||
| return subscribeMessages((message) => { | ||
| if (message.type === 'FORM_ASSIST_ENABLED') { | ||
| this.formAssistEnabled = Boolean(message.payload.enabled); | ||
| this.formAssistStatus = 'ready'; | ||
| } | ||
| }); | ||
| } catch { | ||
| return () => {}; | ||
| } | ||
| } | ||
|
|
||
| destroy(): void { | ||
| this.unsubscribeProfileMessages(); | ||
| this.unsubscribeFormAssistMessages(); | ||
| this.unsubscribeSettingsSnapshots(); | ||
| } | ||
|
|
||
|
|
@@ -201,6 +228,7 @@ export class SettingsPageController { | |
| this.loadSettings(), | ||
| this.loadConnectedAccount(), | ||
| this.loadScanHistory(), | ||
| this.loadFormAssist(), | ||
| ]); | ||
| } | ||
|
|
||
|
|
@@ -237,6 +265,51 @@ export class SettingsPageController { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Lit l'état persisté du Form Assistant auprès du SW (Machine D — INIT). | ||
| * Échec (SW injoignable) → état `error` mais la page reste utilisable. | ||
| */ | ||
| async loadFormAssist(): Promise<void> { | ||
| this.formAssistStatus = 'loading'; | ||
| try { | ||
| const result = (await sendMessage({ type: 'FORM_ASSIST_STATUS' })) as | ||
| { type: 'FORM_ASSIST_STATUS_RESULT'; payload: { enabled: boolean } } | undefined; | ||
| this.formAssistEnabled = Boolean(result?.payload.enabled); | ||
| this.formAssistStatus = 'ready'; | ||
| } catch { | ||
| this.formAssistStatus = 'error'; | ||
| } | ||
| } | ||
|
Comment on lines
+272
to
+282
|
||
|
|
||
| /** | ||
| * Bascule l'activation du Form Assistant. Le SW persiste et diffuse | ||
| * FORM_ASSIST_ENABLED (racolement). L'UI reste optimiste : on met à jour | ||
| * immédiatement pour la réactivité, et le message SW confirme/rétablit. | ||
| */ | ||
| async toggleFormAssist(): Promise<void> { | ||
| if (this.formAssistStatus === 'loading') { | ||
| return; | ||
| } | ||
| const next = !this.formAssistEnabled; | ||
| const previous = this.formAssistEnabled; | ||
| this.formAssistEnabled = next; | ||
| this.formAssistStatus = 'loading'; | ||
| try { | ||
| const result = (await sendMessage({ | ||
| type: 'FORM_ASSIST_ENABLE', | ||
| payload: { enabled: next }, | ||
| })) as { type: 'FORM_ASSIST_ENABLED'; payload: { enabled: boolean } } | undefined; | ||
| // La réponse du SW est la source de vérité (elle peut différer de | ||
| // l'optimisme en cas d'erreur persistée côté SW). | ||
| this.formAssistEnabled = Boolean(result?.payload.enabled); | ||
| this.formAssistStatus = 'ready'; | ||
|
Comment on lines
+304
to
+305
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a user disables an enabled assistant and AGENTS.md reference: AGENTS.md:L89-L94 Useful? React with 👍 / 👎. |
||
| } catch { | ||
| this.formAssistEnabled = previous; | ||
| this.formAssistStatus = 'error'; | ||
| await showToast("Impossible d'activer l'assistant de candidature", 'error'); | ||
| } | ||
| } | ||
|
Comment on lines
+289
to
+311
|
||
|
|
||
| async loadSettings(): Promise<void> { | ||
| try { | ||
| const settings = await getSettings(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -912,6 +912,44 @@ | |
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- Form Assistant (Machine D — src/models/form-assistant.model.md) --> | ||
| <div class="section-card rounded-xl p-5 space-y-3"> | ||
| <div class="flex items-start gap-3"> | ||
| <div | ||
| class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-blueprint-blue/6" | ||
| > | ||
| <Icon name="file-text" size={14} class="text-blueprint-blue" /> | ||
| </div> | ||
| <div class="min-w-0 flex-1"> | ||
| <h3 class="text-body-lg font-medium text-text-primary">Assistant de candidature</h3> | ||
| <p class="mt-1 text-meta text-text-subtle"> | ||
| Au focus sur un champ d'un formulaire de candidature, propose une valeur issue de | ||
| votre profil. Vous restez seul à valider l'insertion (rien n'est jamais rempli | ||
| automatiquement). | ||
| </p> | ||
| </div> | ||
| <Toggle | ||
| checked={settings.formAssistEnabled} | ||
| disabled={settings.formAssistStatus === 'loading'} | ||
| aria-label="Activer l'assistant de candidature" | ||
| onclick={() => settings.toggleFormAssist()} | ||
| /> | ||
| </div> | ||
| <div class="rounded-lg border border-blueprint-blue/15 bg-blueprint-blue/5 px-3 py-3"> | ||
| <div class="flex items-start gap-2"> | ||
| <Icon name="shield-check" size={14} class="mt-0.5 shrink-0 text-blueprint-blue" /> | ||
| <div class="min-w-0"> | ||
| <p class="text-meta font-medium text-text-primary">Périmètre et confidentialité</p> | ||
| <p class="mt-1 text-caption leading-5 text-text-subtle"> | ||
| Actif uniquement sur les plateformes connecteurs compatibles (Free-Work pour la | ||
| phase pilote). La génération utilise Gemini Nano en local ; aucune donnée de page | ||
|
Comment on lines
+945
to
+946
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The five non-Free-Work catalog entries are now marked Useful? React with 👍 / 👎. |
||
| n'est envoyée à un serveur. | ||
|
Comment on lines
+945
to
+947
|
||
| </p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section id="settings-data" class="scroll-mt-4 space-y-4" aria-labelledby="settings-data-title"> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For every newly opted-in connector, this flag injects the assistant across the connector's entire host pattern, but
content/form-assistant/field-detector.ts:110-132accepts every writable text-like input and the classifier maps unmatched or unlabeled fields tofree-text. The widget will therefore arm on login email boxes, global search bars, chat inputs, and other non-application fields throughout LeHibou and the other newly enabled sites, contrary to the application-form scope described byform-assistant.model.md. Add an application-context or eligible-field guard before enabling these whole origins.Useful? React with 👍 / 👎.