diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json
index 3ebbd8ebb4a..0141deb57b9 100644
--- a/invokeai/frontend/web/package.json
+++ b/invokeai/frontend/web/package.json
@@ -75,6 +75,8 @@
"idb-keyval": "^6.2.1",
"jsondiffpatch": "^0.6.0",
"konva": "^9.3.15",
+ "linkify-react": "^4.2.0",
+ "linkifyjs": "^4.2.0",
"lodash-es": "^4.17.21",
"lru-cache": "^11.0.1",
"mtwist": "^1.0.2",
diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml
index b81b3c23e5d..21282bca51d 100644
--- a/invokeai/frontend/web/pnpm-lock.yaml
+++ b/invokeai/frontend/web/pnpm-lock.yaml
@@ -74,6 +74,12 @@ dependencies:
konva:
specifier: ^9.3.15
version: 9.3.15
+ linkify-react:
+ specifier: ^4.2.0
+ version: 4.2.0(linkifyjs@4.2.0)(react@18.3.1)
+ linkifyjs:
+ specifier: ^4.2.0
+ version: 4.2.0
lodash-es:
specifier: ^4.17.21
version: 4.17.21
@@ -6714,6 +6720,20 @@ packages:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: false
+ /linkify-react@4.2.0(linkifyjs@4.2.0)(react@18.3.1):
+ resolution: {integrity: sha512-dIcDGo+n4FP2FPIHDcqB7cUE+omkcEgQJpc7sNNP4+XZ9FUhFAkKjGnHMzsZM+B4yF93sK166z9K5cKTe/JpzA==}
+ peerDependencies:
+ linkifyjs: ^4.0.0
+ react: '>= 15.0.0'
+ dependencies:
+ linkifyjs: 4.2.0
+ react: 18.3.1
+ dev: false
+
+ /linkifyjs@4.2.0:
+ resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==}
+ dev: false
+
/liqe@3.8.0:
resolution: {integrity: sha512-cZ1rDx4XzxONBTskSPBp7/KwJ9qbUdF8EPnY4VjKXwHF1Krz9lgnlMTh1G7kd+KtPYvUte1mhuZeQSnk7KiSBg==}
engines: {node: '>=12.0'}
diff --git a/invokeai/frontend/web/public/locales/fr.json b/invokeai/frontend/web/public/locales/fr.json
index 68ddac8f7f0..0097ac8ed09 100644
--- a/invokeai/frontend/web/public/locales/fr.json
+++ b/invokeai/frontend/web/public/locales/fr.json
@@ -98,7 +98,22 @@
"close": "Fermer",
"clipboard": "Presse-papier",
"loadingModel": "Chargement du modèle",
- "generating": "En Génération"
+ "generating": "En Génération",
+ "warnings": "Alertes",
+ "layout": "Disposition",
+ "row": "Ligne",
+ "column": "Colonne",
+ "start": "Commencer",
+ "board": "Planche",
+ "count": "Quantité",
+ "step": "Étape",
+ "end": "Fin",
+ "min": "Min",
+ "max": "Max",
+ "values": "Valeurs",
+ "resetToDefaults": "Réinitialiser par défaut",
+ "seed": "Graine",
+ "combinatorial": "Combinatoire"
},
"gallery": {
"galleryImageSize": "Taille de l'image",
@@ -165,7 +180,9 @@
"imagesSettings": "Paramètres des images de la galerie",
"assetsTab": "Fichiers que vous avez importés pour vos projets.",
"imagesTab": "Images que vous avez créées et enregistrées dans Invoke.",
- "boardsSettings": "Paramètres des planches"
+ "boardsSettings": "Paramètres des planches",
+ "assets": "Ressources",
+ "images": "Images"
},
"modelManager": {
"modelManager": "Gestionnaire de modèle",
@@ -289,7 +306,7 @@
"usingDefaultSettings": "Utilisation des paramètres par défaut du modèle",
"defaultSettingsOutOfSync": "Certain paramètres ne correspondent pas aux valeurs par défaut du modèle :",
"restoreDefaultSettings": "Cliquez pour utiliser les paramètres par défaut du modèle.",
- "hfForbiddenErrorMessage": "Nous vous recommandons de visiter la page du modèle sur HuggingFace.com. Le propriétaire peut exiger l'acceptation des conditions pour pouvoir télécharger.",
+ "hfForbiddenErrorMessage": "Nous vous recommandons de visiter la page du modèle. Le propriétaire peut exiger l'acceptation des conditions pour pouvoir télécharger.",
"hfTokenRequired": "Vous essayez de télécharger un modèle qui nécessite un token HuggingFace valide.",
"clipLEmbed": "CLIP-L Embed",
"hfTokenSaved": "Token HF enregistré",
@@ -303,7 +320,10 @@
"hfForbidden": "Vous n'avez pas accès à ce modèle HF.",
"hfTokenInvalidErrorMessage2": "Mettre à jour dans le ",
"controlLora": "Controle LoRA",
- "urlUnauthorizedErrorMessage2": "Découvrir comment ici."
+ "urlUnauthorizedErrorMessage2": "Découvrir comment ici.",
+ "urlUnauthorizedErrorMessage": "Vous devrez peut-être configurer un jeton API pour accéder à ce modèle.",
+ "urlForbidden": "Vous n'avez pas accès à ce modèle",
+ "urlForbiddenErrorMessage": "Vous devrez peut-être demander l'autorisation du site qui distribue le modèle."
},
"parameters": {
"images": "Images",
@@ -345,19 +365,31 @@
"fluxModelIncompatibleBboxHeight": "$t(parameters.invoke.fluxRequiresDimensionsToBeMultipleOf16), la hauteur de la bounding box est {{height}}",
"fluxModelIncompatibleScaledBboxHeight": "$t(parameters.invoke.fluxRequiresDimensionsToBeMultipleOf16), la hauteur de la bounding box est {{height}}",
"noFLUXVAEModelSelected": "Aucun modèle VAE sélectionné pour la génération FLUX",
- "canvasIsTransforming": "La Toile se transforme",
- "canvasIsRasterizing": "La Toile se rastérise",
+ "canvasIsTransforming": "La Toile est occupée (en transformation)",
+ "canvasIsRasterizing": "La Toile est occupée (en rastérisation)",
"noCLIPEmbedModelSelected": "Aucun modèle CLIP Embed sélectionné pour la génération FLUX",
- "canvasIsFiltering": "La Toile est en train de filtrer",
+ "canvasIsFiltering": "La Toile est occupée (en filtration)",
"fluxModelIncompatibleBboxWidth": "$t(parameters.invoke.fluxRequiresDimensionsToBeMultipleOf16), la largeur de la bounding box est {{width}}",
"noT5EncoderModelSelected": "Aucun modèle T5 Encoder sélectionné pour la génération FLUX",
"fluxModelIncompatibleScaledBboxWidth": "$t(parameters.invoke.fluxRequiresDimensionsToBeMultipleOf16), la largeur de la bounding box mise à l'échelle est {{width}}",
- "canvasIsCompositing": "La toile est en train de composer",
- "collectionTooFewItems": "{{nodeLabel}} -> {{fieldLabel}} : trop peu d'éléments, minimum {{minItems}}",
- "collectionTooManyItems": "{{nodeLabel}} -> {{fieldLabel}} : trop d'éléments, maximum {{maxItems}}",
+ "canvasIsCompositing": "La Toile est occupée (en composition)",
+ "collectionTooFewItems": "trop peu d'éléments, minimum {{minItems}}",
+ "collectionTooManyItems": "trop d'éléments, maximum {{maxItems}}",
"canvasIsSelectingObject": "La toile est occupée (sélection d'objet)",
"emptyBatches": "lots vides",
- "batchNodeNotConnected": "Noeud de lots non connecté : {{label}}"
+ "batchNodeNotConnected": "Noeud de lots non connecté : {{label}}",
+ "fluxModelMultipleControlLoRAs": "Vous ne pouvez utiliser qu'un seul Control LoRA à la fois",
+ "collectionNumberLTMin": "{{value}} < {{minimum}} (incl. min)",
+ "collectionNumberGTMax": "{{value}} > {{maximum}} (incl. max)",
+ "collectionNumberGTExclusiveMax": "{{value}} >= {{exclusiveMaximum}} (max exc)",
+ "batchNodeEmptyCollection": "Certains nœuds de lot ont des collections vides",
+ "batchNodeCollectionSizeMismatch": "Non-concordance de taille de collection sur le lot {{batchGroupId}}",
+ "collectionStringTooLong": "trop long, max {{maxLength}}",
+ "collectionNumberNotMultipleOf": "{{value}} n'est pas un multiple de {{multipleOf}}",
+ "collectionEmpty": "collection vide",
+ "collectionStringTooShort": "trop court, min {{minLength}}",
+ "collectionNumberLTExclusiveMin": "{{value}} <= {{exclusiveMinimum}} (min exc)",
+ "batchNodeCollectionSizeMismatchNoGroupId": "Taille de collection de groupe par lot non conforme"
},
"negativePromptPlaceholder": "Prompt Négatif",
"positivePromptPlaceholder": "Prompt Positif",
@@ -501,7 +533,13 @@
"uploadFailedInvalidUploadDesc_withCount_one": "Doit être au maximum une image PNG ou JPEG.",
"uploadFailedInvalidUploadDesc_withCount_many": "Doit être au maximum {{count}} images PNG ou JPEG.",
"uploadFailedInvalidUploadDesc_withCount_other": "Doit être au maximum {{count}} images PNG ou JPEG.",
- "addedToUncategorized": "Ajouté aux ressources de la planche $t(boards.uncategorized)"
+ "addedToUncategorized": "Ajouté aux ressources de la planche $t(boards.uncategorized)",
+ "pasteSuccess": "Collé à {{destination}}",
+ "pasteFailed": "Échec du collage",
+ "outOfMemoryErrorDescLocal": "Suivez notre guide Low VRAM pour réduire les OOMs.",
+ "unableToCopy": "Incapable de Copier",
+ "unableToCopyDesc": "Votre navigateur ne prend pas en charge l'accès au presse-papiers. Les utilisateurs de Firefox peuvent peut-être résoudre ce problème en suivant ",
+ "unableToCopyDesc_theseSteps": "ces étapes"
},
"accessibility": {
"uploadImage": "Importer une image",
@@ -659,7 +697,14 @@
"iterations_many": "Itérations",
"iterations_other": "Itérations",
"back": "fin",
- "batchSize": "Taille de lot"
+ "batchSize": "Taille de lot",
+ "retryFailed": "Problème de nouvelle tentative de l'élément",
+ "retrySucceeded": "Élément Retenté",
+ "retryItem": "Réessayer l'élement",
+ "cancelAllExceptCurrentQueueItemAlertDialog": "Annuler tous les éléments de la file d'attente, sauf celui en cours, arrêtera les éléments en attente mais permettra à celui en cours de se terminer.",
+ "cancelAllExceptCurrentQueueItemAlertDialog2": "Êtes-vous sûr de vouloir annuler tous les éléments en attente dans la file d'attente ?",
+ "cancelAllExceptCurrentTooltip": "Annuler tout sauf l'élément actuel",
+ "confirm": "Confirmer"
},
"prompt": {
"noMatchingTriggers": "Pas de déclancheurs correspondants",
@@ -1031,7 +1076,9 @@
"controlNetWeight": {
"heading": "Poids",
"paragraphs": [
- "Poids du Control Adapter. Un poids plus élevé aura un impact plus important sur l'image finale."
+ "Poids du Control Adapter. Un poids plus élevé aura un impact plus important sur l'image finale.",
+ "• Poids plus élevé (.75-2) : Crée un impact plus significatif sur le résultat final.",
+ "• Poids inférieur (0-.75) : Crée un impact plus faible sur le résultat final."
]
},
"compositingMaskAdjustments": {
@@ -1076,8 +1123,9 @@
"controlNetBeginEnd": {
"heading": "Pourcentage de début / de fin d'étape",
"paragraphs": [
- "La partie du processus de débruitage à laquelle le Control Adapter sera appliqué.",
- "En général, les Control Adapter appliqués au début du processus guident la composition, tandis que les Control Adapter appliqués à la fin guident les détails."
+ "Ce paramètre détérmine quelle portion du processus de débruitage (génération) utilisera cette couche comme guide.",
+ "En général, les Control Adapter appliqués au début du processus guident la composition, tandis que les Control Adapter appliqués à la fin guident les détails.",
+ "• Étape de fin (%): Spécifie quand arrêter d'appliquer le guide de cette couche et revenir aux guides généraux du modèle et aux autres paramètres."
]
},
"controlNetControlMode": {
@@ -1442,7 +1490,8 @@
"showDynamicPrompts": "Afficher les Prompts dynamiques",
"dynamicPrompts": "Prompts Dynamiques",
"promptsPreview": "Prévisualisation des Prompts",
- "loading": "Génération des Pompts Dynamiques..."
+ "loading": "Génération des Pompts Dynamiques...",
+ "promptsToGenerate": "Prompts à générer"
},
"metadata": {
"positivePrompt": "Prompt Positif",
@@ -1653,7 +1702,22 @@
"internalDesc": "Cette invocation est utilisée internalement par Invoke. En fonction des mises à jours il est possible que des changements y soit effectués ou qu'elle soit supprimé sans prévention.",
"splitOn": "Diviser sur",
"generatorNoValues": "vide",
- "addItem": "Ajouter un élément"
+ "addItem": "Ajouter un élément",
+ "specialDesc": "Cette invocation nécessite un traitement spécial dans l'application. Par exemple, les nœuds Batch sont utilisés pour mettre en file d'attente plusieurs graphes à partir d'un seul workflow.",
+ "unableToUpdateNode": "La mise à jour du nœud a échoué : nœud {{node}} de type {{type}} (peut nécessiter la suppression et la recréation).",
+ "deletedMissingNodeFieldFormElement": "Champ de formulaire manquant supprimé : nœud {{nodeId}} champ {{fieldName}}",
+ "nodeName": "Nom du nœud",
+ "description": "Description",
+ "loadWorkflowDesc": "Charger le workflow ?",
+ "missingSourceOrTargetNode": "Nœud source ou cible manquant",
+ "generatorImagesCategory": "Catégorie",
+ "generatorImagesFromBoard": "Images de la Planche",
+ "missingSourceOrTargetHandle": "Manque de gestionnaire source ou cible",
+ "loadingTemplates": "Chargement de {{name}}",
+ "loadWorkflowDesc2": "Votre workflow actuel contient des modifications non enregistrées.",
+ "generatorImages_one": "{{count}} image",
+ "generatorImages_many": "{{count}} images",
+ "generatorImages_other": "{{count}} images"
},
"models": {
"noMatchingModels": "Aucun modèle correspondant",
@@ -1712,13 +1776,41 @@
"deleteWorkflow2": "Êtes-vous sûr de vouloir supprimer ce Workflow ? Cette action ne peut pas être annulé.",
"download": "Télécharger",
"copyShareLinkForWorkflow": "Copier le lien de partage pour le Workflow",
- "delete": "Supprimer"
+ "delete": "Supprimer",
+ "builder": {
+ "component": "Composant",
+ "numberInput": "Entrée de nombre",
+ "slider": "Curseur",
+ "both": "Les deux",
+ "singleLine": "Ligne unique",
+ "multiLine": "Multi Ligne",
+ "headingPlaceholder": "En-tête vide",
+ "emptyRootPlaceholderEditMode": "Faites glisser un élément de formulaire ou un champ de nœud ici pour commencer.",
+ "emptyRootPlaceholderViewMode": "Cliquez sur Modifier pour commencer à créer un formulaire pour ce workflow.",
+ "containerPlaceholder": "Conteneur Vide",
+ "row": "Ligne",
+ "column": "Colonne",
+ "layout": "Mise en page",
+ "nodeField": "Champ de nœud",
+ "zoomToNode": "Zoomer sur le nœud",
+ "nodeFieldTooltip": "Pour ajouter un champ de nœud, cliquez sur le petit bouton plus sur le champ dans l'Éditeur de Workflow, ou faites glisser le champ par son nom dans le formulaire.",
+ "addToForm": "Ajouter au formulaire",
+ "label": "Étiquette",
+ "textPlaceholder": "Texte vide",
+ "builder": "Constructeur de Formulaire",
+ "resetAllNodeFields": "Réinitialiser tous les champs de nœud",
+ "deleteAllElements": "Supprimer tous les éléments de formulaire",
+ "workflowBuilderAlphaWarning": "Le constructeur de workflow est actuellement en version alpha. Il peut y avoir des changements majeurs avant la version stable.",
+ "showDescription": "Afficher la description"
+ },
+ "openLibrary": "Ouvrir la Bibliothèque"
},
"whatsNew": {
"whatsNewInInvoke": "Quoi de neuf dans Invoke",
"watchRecentReleaseVideos": "Regarder les vidéos des dernières versions",
"items": [
- "FLUX Guidage Régional (bêta) : Notre version bêta de FLUX Guidage Régional est en ligne pour le contrôle des prompt régionaux."
+ "FLUX Guidage Régional (bêta) : Notre version bêta de FLUX Guidage Régional est en ligne pour le contrôle des prompt régionaux.",
+ "Autres améliorations : mise en file d'attente par lots plus rapide, meilleur redimensionnement, sélecteur de couleurs amélioré et nœuds de métadonnées."
],
"readReleaseNotes": "Notes de version",
"watchUiUpdatesOverview": "Aperçu des mises à jour de l'interface utilisateur"
@@ -1832,7 +1924,49 @@
"cancel": "Annuler",
"advanced": "Avancé",
"processingLayerWith": "Calque de traitement avec le filtre {{type}}.",
- "forMoreControl": "Pour plus de contrôle, cliquez sur Avancé ci-dessous."
+ "forMoreControl": "Pour plus de contrôle, cliquez sur Avancé ci-dessous.",
+ "adjust_image": {
+ "b": "B (LAB)",
+ "blue": "Bleu (RGBA)",
+ "alpha": "Alpha (RGBA)",
+ "magenta": "Magenta (CMJN)",
+ "yellow": "Jaune (CMJN)",
+ "cb": "Cb (YCbCr)",
+ "cr": "Cr (YCbCr)",
+ "cyan": "Cyan (CMJN)",
+ "label": "Ajuster l'image",
+ "description": "Ajuste le canal sélectionné d'une image.",
+ "channel": "Canal",
+ "value_setting": "Valeur",
+ "scale_values": "Valeurs d'échelle",
+ "red": "Rouge (RGBA)",
+ "green": "Vert (RGBA)",
+ "black": "Noir (CMJN)",
+ "hue": "Teinte (HSV)",
+ "saturation": "Saturation (HSV)",
+ "value": "Valeur (HSV)",
+ "luminosity": "Luminosité (LAB)",
+ "a": "A (LAB)",
+ "y": "Y (YCbCr)"
+ },
+ "img_blur": {
+ "label": "Flou de l'image",
+ "blur_type": "Type de flou",
+ "box_type": "Boîte",
+ "description": "Floute la couche sélectionnée.",
+ "blur_radius": "Rayon",
+ "gaussian_type": "Gaussien"
+ },
+ "img_noise": {
+ "label": "Image de bruit",
+ "description": "Ajoute du bruit à la couche sélectionnée.",
+ "gaussian_type": "Gaussien",
+ "size": "Taille du bruit",
+ "noise_amount": "Quantité",
+ "noise_type": "Type de bruit",
+ "salt_and_pepper_type": "Sel et Poivre",
+ "noise_color": "Bruit coloré"
+ }
},
"canvasContextMenu": {
"saveToGalleryGroup": "Enregistrer dans la galerie",
@@ -1846,7 +1980,10 @@
"newGlobalReferenceImage": "Nouvelle image de référence globale",
"newControlLayer": "Nouveau couche de contrôle",
"newInpaintMask": "Nouveau Masque Inpaint",
- "newRegionalGuidance": "Nouveau Guide Régional"
+ "newRegionalGuidance": "Nouveau Guide Régional",
+ "copyToClipboard": "Copier dans le presse-papiers",
+ "copyBboxToClipboard": "Copier Bbox dans le presse-papiers",
+ "copyCanvasToClipboard": "Copier la Toile dans le presse-papiers"
},
"bookmark": "Marque-page pour Changement Rapide",
"saveLayerToAssets": "Enregistrer la couche dans les ressources",
@@ -2012,7 +2149,10 @@
"ipAdapterMethod": "Méthode d'IP Adapter",
"full": "Complet",
"style": "Style uniquement",
- "composition": "Composition uniquement"
+ "composition": "Composition uniquement",
+ "fullDesc": "Applique le style visuel (couleurs, textures) et la composition (mise en page, structure).",
+ "styleDesc": "Applique un style visuel (couleurs, textures) sans tenir compte de sa mise en page.",
+ "compositionDesc": "Réplique la mise en page et la structure tout en ignorant le style de la référence."
},
"fitBboxToLayers": "Ajuster la bounding box aux calques",
"regionIsEmpty": "La zone sélectionnée est vide",
@@ -2095,7 +2235,40 @@
"asRasterLayerResize": "En tant que $t(controlLayers.rasterLayer) (Redimensionner)",
"asControlLayer": "En tant que $t(controlLayers.controlLayer)",
"asControlLayerResize": "En $t(controlLayers.controlLayer) (Redimensionner)",
- "newSession": "Nouvelle session"
+ "newSession": "Nouvelle session",
+ "warnings": {
+ "controlAdapterIncompatibleBaseModel": "modèle de base de la couche de contrôle incompatible",
+ "controlAdapterNoControl": "aucun contrôle sélectionné/dessiné",
+ "rgNoPromptsOrIPAdapters": "pas de textes d'instructions ni d'images de référence",
+ "rgAutoNegativeNotSupported": "Auto-négatif non pris en charge pour le modèle de base sélectionné",
+ "rgNoRegion": "aucune région dessinée",
+ "ipAdapterNoModelSelected": "aucun modèle d'image de référence sélectionné",
+ "rgReferenceImagesNotSupported": "Les images de référence régionales ne sont pas prises en charge pour le modèle de base sélectionné",
+ "problemsFound": "Problèmes trouvés",
+ "unsupportedModel": "couche non prise en charge pour le modèle de base sélectionné",
+ "rgNegativePromptNotSupported": "Prompt négatif non pris en charge pour le modèle de base sélectionné",
+ "ipAdapterIncompatibleBaseModel": "modèle de base d'image de référence incompatible",
+ "controlAdapterNoModelSelected": "aucun modèle de couche de contrôle sélectionné",
+ "ipAdapterNoImageSelected": "Aucune image de référence sélectionnée."
+ },
+ "pasteTo": "Coller vers",
+ "pasteToAssets": "Ressources",
+ "pasteToAssetsDesc": "Coller dans les ressources",
+ "pasteToBbox": "Bbox",
+ "regionCopiedToClipboard": "{{region}} Copié dans le presse-papiers",
+ "copyRegionError": "Erreur de copie {{region}}",
+ "pasteToCanvas": "Toile",
+ "errors": {
+ "unableToFindImage": "Impossible de trouver l'image",
+ "unableToLoadImage": "Impossible de charger l'image"
+ },
+ "referenceImageRegional": "Image de référence (régionale)",
+ "pasteToBboxDesc": "Nouvelle couche (dans Bbox)",
+ "pasteToCanvasDesc": "Nouvelle couche (dans la Toile)",
+ "useImage": "Utiliser l'image",
+ "pastedTo": "Collé à {{destination}}",
+ "referenceImageEmptyState": "Séléctionner une image ou faites glisser une image depuis la galerie sur cette couche pour commencer.",
+ "referenceImageGlobal": "Image de référence (Globale)"
},
"upscaling": {
"exceedsMaxSizeDetails": "La limite maximale d'agrandissement est de {{maxUpscaleDimension}}x{{maxUpscaleDimension}} pixels. Veuillez essayer une image plus petite ou réduire votre sélection d'échelle.",
@@ -2175,7 +2348,8 @@
"queue": "File d'attente",
"events": "Événements",
"metadata": "Métadonnées",
- "gallery": "Galerie"
+ "gallery": "Galerie",
+ "dnd": "Glisser et déposer"
},
"logLevel": {
"trace": "Trace",
@@ -2192,7 +2366,8 @@
"toGetStarted": "Pour commencer, saisissez un prompt dans la boîte et cliquez sur Invoke pour générer votre première image. Sélectionnez un template de prompt pour améliorer les résultats. Vous pouvez choisir de sauvegarder vos images directement dans la Galerie ou de les modifier sur la Toile.",
"gettingStartedSeries": "Vous souhaitez plus de conseils ? Consultez notre Série de démarrage pour des astuces sur l'exploitation du plein potentiel de l'Invoke Studio.",
"noModelsInstalled": "Il semble qu'aucun modèle ne soit installé",
- "toGetStartedLocal": "Pour commencer, assurez-vous de télécharger ou d'importer des modèles nécessaires pour exécuter Invoke. Ensuite, saisissez le prompt dans la boîte et cliquez sur Invoke pour générer votre première image. Sélectionnez un template de prompt pour améliorer les résultats. Vous pouvez choisir de sauvegarder vos images directement sur Galerie ou les modifier sur la Toile."
+ "toGetStartedLocal": "Pour commencer, assurez-vous de télécharger ou d'importer des modèles nécessaires pour exécuter Invoke. Ensuite, saisissez le prompt dans la boîte et cliquez sur Invoke pour générer votre première image. Sélectionnez un template de prompt pour améliorer les résultats. Vous pouvez choisir de sauvegarder vos images directement sur Galerie ou les modifier sur la Toile.",
+ "lowVRAMMode": "Pour de meilleures performances, suivez notre guide Low VRAM."
},
"upsell": {
"shareAccess": "Partager l'accès",
@@ -2240,7 +2415,8 @@
"description": "Introduction à l'ajout d'images de référence et IP Adapters globaux."
},
"howDoIUseInpaintMasks": {
- "title": "Comment utiliser les masques d'inpainting ?"
+ "title": "Comment utiliser les masques d'inpainting ?",
+ "description": "Comment appliquer des masques de retourche pour la correction et la variation d'image."
},
"creatingYourFirstImage": {
"title": "Créer votre première image",
@@ -2260,5 +2436,10 @@
"studioSessionsDesc2": "Rejoignez notre pour participer aux sessions en direct et poser vos questions. Les sessions sont ajoutée dans la playlist la semaine suivante.",
"supportVideos": "Vidéos d'assistance",
"controlCanvas": "Contrôler la toile"
+ },
+ "modelCache": {
+ "clear": "Effacer le cache du modèle",
+ "clearSucceeded": "Cache du modèle effacée",
+ "clearFailed": "Problème de nettoyage du cache du modèle"
}
}
diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json
index 240320e9daf..a4421cb969e 100644
--- a/invokeai/frontend/web/public/locales/it.json
+++ b/invokeai/frontend/web/public/locales/it.json
@@ -2277,11 +2277,7 @@
"watchUiUpdatesOverview": "Guarda le novità dell'interfaccia",
"items": [
"Impostazioni predefinite VRAM migliorate",
- "Cancellazione della cache del modello su richiesta",
- "Compatibilità estesa FLUX LoRA",
- "Filtro Regola Immagine su Tela",
- "Annulla tutto tranne l'elemento della coda corrente",
- "Copia da e incolla sulla Tela"
+ "Cancellazione della cache del modello su richiesta"
]
},
"system": {
diff --git a/invokeai/frontend/web/public/locales/ja.json b/invokeai/frontend/web/public/locales/ja.json
index c29bfa4af55..79fb2f8e481 100644
--- a/invokeai/frontend/web/public/locales/ja.json
+++ b/invokeai/frontend/web/public/locales/ja.json
@@ -329,7 +329,13 @@
"redo": {
"title": "やり直し"
},
- "title": "ワークフロー"
+ "title": "ワークフロー",
+ "pasteSelection": {
+ "title": "ペースト"
+ },
+ "copySelection": {
+ "title": "コピー"
+ }
},
"app": {
"toggleLeftPanel": {
@@ -390,7 +396,10 @@
"desc": "カーソルをポジティブプロンプト欄に移動します。"
}
},
- "hotkeys": "ホットキー"
+ "hotkeys": "ホットキー",
+ "gallery": {
+ "title": "ギャラリー"
+ }
},
"modelManager": {
"modelManager": "モデルマネージャ",
@@ -452,7 +461,8 @@
"loraModels": "LoRA",
"edit": "編集",
"install": "インストール",
- "huggingFacePlaceholder": "owner/model-name"
+ "huggingFacePlaceholder": "owner/model-name",
+ "variant": "Variant"
},
"parameters": {
"images": "画像",
@@ -507,7 +517,8 @@
"resetWebUIDesc2": "もしギャラリーに画像が表示されないなど、何か問題が発生した場合はGitHubにissueを提出する前にリセットを試してください。",
"resetComplete": "WebUIはリセットされました。",
"ui": "ユーザーインターフェイス",
- "beta": "ベータ"
+ "beta": "ベータ",
+ "developer": "開発者"
},
"toast": {
"uploadFailed": "アップロード失敗",
@@ -556,7 +567,8 @@
"negativePrompt": "ネガティブプロンプト",
"generationMode": "生成モード",
"vae": "VAE",
- "cfgRescaleMultiplier": "$t(parameters.cfgRescaleMultiplier)"
+ "cfgRescaleMultiplier": "$t(parameters.cfgRescaleMultiplier)",
+ "canvasV2Metadata": "キャンバス"
},
"queue": {
"queueEmpty": "キューが空です",
@@ -690,7 +702,8 @@
"notes": "ノート",
"workflow": "ワークフロー",
"workflowName": "名前",
- "workflowNotes": "ノート"
+ "workflowNotes": "ノート",
+ "enum": "Enum"
},
"boards": {
"autoAddBoard": "自動追加するボード",
@@ -823,6 +836,15 @@
},
"lora": {
"heading": "LoRA"
+ },
+ "loraWeight": {
+ "heading": "重み"
+ },
+ "patchmatchDownScaleSize": {
+ "heading": "Downscale"
+ },
+ "controlNetWeight": {
+ "heading": "重み"
}
},
"accordions": {
@@ -865,7 +887,8 @@
"queue": "キュー",
"canvas": "キャンバス",
"workflows": "ワークフロー",
- "models": "モデル"
+ "models": "モデル",
+ "gallery": "ギャラリー"
}
},
"controlLayers": {
@@ -880,7 +903,8 @@
"bboxGroup": "バウンディングボックスから作成",
"cropCanvasToBbox": "キャンバスをバウンディングボックスでクロップ",
"newGlobalReferenceImage": "新規全域参照画像",
- "newRegionalReferenceImage": "新規領域参照画像"
+ "newRegionalReferenceImage": "新規領域参照画像",
+ "canvasGroup": "キャンバス"
},
"regionalGuidance": "領域ガイダンス",
"globalReferenceImage": "全域参照画像",
@@ -901,7 +925,8 @@
"brush": "ブラシ",
"rectangle": "矩形",
"move": "移動",
- "eraser": "消しゴム"
+ "eraser": "消しゴム",
+ "bbox": "Bbox"
},
"saveCanvasToGallery": "キャンバスをギャラリーに保存",
"saveBboxToGallery": "バウンディングボックスをギャラリーへ保存",
@@ -919,7 +944,27 @@
"canvas": "キャンバス",
"fitBboxToLayers": "バウンディングボックスをレイヤーにフィット",
"removeBookmark": "ブックマークを外す",
- "savedToGalleryOk": "ギャラリーに保存しました"
+ "savedToGalleryOk": "ギャラリーに保存しました",
+ "controlMode": {
+ "prompt": "プロンプト"
+ },
+ "prompt": "プロンプト",
+ "settings": {
+ "snapToGrid": {
+ "off": "オフ",
+ "on": "オン"
+ }
+ },
+ "filter": {
+ "filter": "フィルター",
+ "spandrel_filter": {
+ "model": "モデル"
+ },
+ "apply": "適用",
+ "reset": "リセット",
+ "cancel": "キャンセル"
+ },
+ "weight": "重み"
},
"stylePresets": {
"clearTemplateSelection": "選択したテンプレートをクリア",
@@ -934,7 +979,10 @@
"toggleViewMode": "表示モードを切り替え",
"negativePromptColumn": "'negative_prompt'",
"preview": "プレビュー",
- "nameColumn": "'name'"
+ "nameColumn": "'name'",
+ "type": "タイプ",
+ "private": "プライベート",
+ "name": "名称"
},
"upscaling": {
"upscaleModel": "アップスケールモデル",
@@ -946,7 +994,8 @@
"denoisingStrength": "ノイズ除去強度",
"scheduler": "スケジューラー",
"loading": "ロード中...",
- "steps": "ステップ"
+ "steps": "ステップ",
+ "refiner": "Refiner"
},
"modelCache": {
"clear": "モデルキャッシュを消去",
@@ -958,5 +1007,23 @@
"ascending": "昇順",
"name": "名前",
"descending": "降順"
+ },
+ "system": {
+ "logNamespaces": {
+ "system": "システム",
+ "gallery": "ギャラリー",
+ "workflows": "ワークフロー",
+ "models": "モデル",
+ "canvas": "キャンバス",
+ "metadata": "メタデータ",
+ "queue": "キュー"
+ },
+ "logLevel": {
+ "debug": "Debug",
+ "info": "Info",
+ "error": "Error",
+ "fatal": "Fatal",
+ "warn": "Warn"
+ }
}
}
diff --git a/invokeai/frontend/web/public/locales/vi.json b/invokeai/frontend/web/public/locales/vi.json
index e65aaa350c6..fc0dc33c3d4 100644
--- a/invokeai/frontend/web/public/locales/vi.json
+++ b/invokeai/frontend/web/public/locales/vi.json
@@ -2311,11 +2311,7 @@
"watchUiUpdatesOverview": "Xem Tổng Quan Về Những Cập Nhật Cho Giao Diện Người Dùng",
"items": [
"Cải thiện các thiết lập mặc định của VRAM",
- "Xoá bộ nhớ đệm của model theo yêu cầu",
- "Mở rộng khả năng tương thích LoRA trên FLUX",
- "Bộ lọc điều chỉnh ảnh trên Canvas",
- "Huỷ tất cả trừ mục đang xếp hàng hiện tại",
- "Sao chép và dán trên Canvas"
+ "Xoá bộ nhớ đệm của model theo yêu cầu"
]
},
"upsell": {
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts
index 66997785690..53301f6a9d4 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts
@@ -3,6 +3,7 @@ import { enqueueRequested } from 'app/store/actions';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
import { extractMessageFromAssertionError } from 'common/util/extractMessageFromAssertionError';
import { withResult, withResultAsync } from 'common/util/result';
+import { parseify } from 'common/util/serialize';
import { $canvasManager } from 'features/controlLayers/store/ephemeral';
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
import { buildFLUXGraph } from 'features/nodes/util/graph/generation/buildFLUXGraph';
@@ -13,7 +14,6 @@ import { toast } from 'features/toast/toast';
import { serializeError } from 'serialize-error';
import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue';
import { assert, AssertionError } from 'tsafe';
-import type { JsonObject } from 'type-fest';
const log = logger('generation');
@@ -80,16 +80,15 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
const req = dispatch(
queueApi.endpoints.enqueueBatch.initiate(prepareBatchResult.value, enqueueMutationFixedCacheKeyOptions)
);
- req.reset();
- const enqueueResult = await withResultAsync(() => req.unwrap());
-
- if (enqueueResult.isErr()) {
- log.error({ error: serializeError(enqueueResult.error) }, 'Failed to enqueue batch');
- return;
+ try {
+ await req.unwrap();
+ log.debug(parseify({ batchConfig: prepareBatchResult.value }), 'Enqueued batch');
+ } catch (error) {
+ log.error({ error: serializeError(error) }, 'Failed to enqueue batch');
+ } finally {
+ req.reset();
}
-
- log.debug({ batchConfig: prepareBatchResult.value } as JsonObject, 'Enqueued batch');
},
});
};
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
index 6a14028ad91..838019c428b 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
@@ -1,5 +1,7 @@
+import { logger } from 'app/logging/logger';
import { enqueueRequested } from 'app/store/actions';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
+import { parseify } from 'common/util/serialize';
import { $templates } from 'features/nodes/store/nodesSlice';
import { selectNodesSlice } from 'features/nodes/store/selectors';
import { isBatchNode, isInvocationNode } from 'features/nodes/types/invocation';
@@ -7,9 +9,12 @@ import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
import { resolveBatchValue } from 'features/nodes/util/node/resolveBatchValue';
import { buildWorkflowWithValidation } from 'features/nodes/util/workflow/buildWorkflow';
import { groupBy } from 'lodash-es';
+import { serializeError } from 'serialize-error';
import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue';
import type { Batch, BatchConfig } from 'services/api/types';
+const log = logger('generation');
+
export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) => {
startAppListening({
predicate: (action): action is ReturnType =>
@@ -101,6 +106,9 @@ export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) =
const req = dispatch(queueApi.endpoints.enqueueBatch.initiate(batchConfig, enqueueMutationFixedCacheKeyOptions));
try {
await req.unwrap();
+ log.debug(parseify({ batchConfig }), 'Enqueued batch');
+ } catch (error) {
+ log.error({ error: serializeError(error) }, 'Failed to enqueue batch');
} finally {
req.reset();
}
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts
index 022fc99716f..62e70263158 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts
@@ -1,9 +1,14 @@
+import { logger } from 'app/logging/logger';
import { enqueueRequested } from 'app/store/actions';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
+import { parseify } from 'common/util/serialize';
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
import { buildMultidiffusionUpscaleGraph } from 'features/nodes/util/graph/buildMultidiffusionUpscaleGraph';
+import { serializeError } from 'serialize-error';
import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue';
+const log = logger('generation');
+
export const addEnqueueRequestedUpscale = (startAppListening: AppStartListening) => {
startAppListening({
predicate: (action): action is ReturnType =>
@@ -19,6 +24,9 @@ export const addEnqueueRequestedUpscale = (startAppListening: AppStartListening)
const req = dispatch(queueApi.endpoints.enqueueBatch.initiate(batchConfig, enqueueMutationFixedCacheKeyOptions));
try {
await req.unwrap();
+ log.debug(parseify({ batchConfig }), 'Enqueued batch');
+ } catch (error) {
+ log.error({ error: serializeError(error) }, 'Failed to enqueue batch');
} finally {
req.reset();
}
diff --git a/invokeai/frontend/web/src/common/components/linkify.ts b/invokeai/frontend/web/src/common/components/linkify.ts
new file mode 100644
index 00000000000..4ac639468f7
--- /dev/null
+++ b/invokeai/frontend/web/src/common/components/linkify.ts
@@ -0,0 +1,17 @@
+import type { SystemStyleObject } from '@invoke-ai/ui-library';
+import type { Opts as LinkifyOpts } from 'linkifyjs';
+
+export const linkifySx: SystemStyleObject = {
+ a: {
+ fontWeight: 'semibold',
+ },
+ 'a:hover': {
+ textDecoration: 'underline',
+ },
+};
+
+export const linkifyOptions: LinkifyOpts = {
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ validate: (value) => /^https?:\/\//.test(value),
+};
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopPanel/TopPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopPanel/TopPanel.tsx
index 42651bdbed2..e45eb937dc9 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopPanel/TopPanel.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopPanel/TopPanel.tsx
@@ -1,16 +1,21 @@
-import { Flex, Spacer } from '@invoke-ai/ui-library';
+import { Flex, IconButton, Spacer } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import AddNodeButton from 'features/nodes/components/flow/panels/TopPanel/AddNodeButton';
import ClearFlowButton from 'features/nodes/components/flow/panels/TopPanel/ClearFlowButton';
import SaveWorkflowButton from 'features/nodes/components/flow/panels/TopPanel/SaveWorkflowButton';
import UpdateNodesButton from 'features/nodes/components/flow/panels/TopPanel/UpdateNodesButton';
+import { useWorkflowEditorSettingsModal } from 'features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings';
import { WorkflowName } from 'features/nodes/components/sidePanel/WorkflowName';
import { selectWorkflowName } from 'features/nodes/store/workflowSlice';
-import WorkflowLibraryMenu from 'features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu';
import { memo } from 'react';
+import { useTranslation } from 'react-i18next';
+import { PiGearSixFill } from 'react-icons/pi';
const TopCenterPanel = () => {
const name = useAppSelector(selectWorkflowName);
+ const modal = useWorkflowEditorSettingsModal();
+
+ const { t } = useTranslation();
return (
@@ -22,7 +27,12 @@ const TopCenterPanel = () => {
-
+ }
+ onClick={modal.setTrue}
+ />
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowDescription.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowDescription.tsx
index c16c7fcd9f9..4b31c85823a 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowDescription.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowDescription.tsx
@@ -1,6 +1,8 @@
import { Text } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
+import { linkifyOptions, linkifySx } from 'common/components/linkify';
import { selectWorkflowDescription } from 'features/nodes/store/workflowSlice';
+import Linkify from 'linkify-react';
import { memo } from 'react';
export const ActiveWorkflowDescription = memo(() => {
@@ -11,8 +13,8 @@ export const ActiveWorkflowDescription = memo(() => {
}
return (
-
- {description}
+
+ {description}
);
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowNameAndActions.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowNameAndActions.tsx
index 31bb655522f..3bb2dff02bb 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowNameAndActions.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowNameAndActions.tsx
@@ -1,9 +1,9 @@
import { Flex, Spacer } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
-import { NewWorkflowButton } from 'features/nodes/components/sidePanel/NewWorkflowButton';
import { WorkflowListMenuTrigger } from 'features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuTrigger';
import { WorkflowViewEditToggleButton } from 'features/nodes/components/sidePanel/WorkflowViewEditToggleButton';
import { selectWorkflowMode } from 'features/nodes/store/workflowSlice';
+import { WorkflowLibraryMenu } from 'features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu';
import { memo } from 'react';
import SaveWorkflowButton from './SaveWorkflowButton';
@@ -17,7 +17,7 @@ export const ActiveWorkflowNameAndActions = memo(() => {
{mode === 'edit' && }
-
+
);
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuTrigger.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuTrigger.tsx
index 5e851242c36..c2fe14669f4 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuTrigger.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuTrigger.tsx
@@ -15,6 +15,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { useWorkflowListMenu } from 'features/nodes/store/workflowListMenu';
import { selectWorkflowName } from 'features/nodes/store/workflowSlice';
+import { NewWorkflowButton } from 'features/workflowLibrary/components/NewWorkflowButton';
import UploadWorkflowButton from 'features/workflowLibrary/components/UploadWorkflowButton';
import { useRef } from 'react';
import { useTranslation } from 'react-i18next';
@@ -63,6 +64,7 @@ export const WorkflowListMenuTrigger = () => {
+
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx
index 69755c98ca5..8e9a119a5f8 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx
@@ -50,7 +50,7 @@ const ContainerElement = memo(({ id }: { id: string }) => {
ContainerElement.displayName = 'ContainerElementComponent';
const containerViewModeSx: SystemStyleObject = {
- gap: 4,
+ gap: 2,
'&[data-self-layout="column"]': {
flexDir: 'column',
alignItems: 'stretch',
@@ -197,7 +197,7 @@ const rootViewModeSx: SystemStyleObject = {
borderRadius: 'base',
w: 'full',
h: 'full',
- gap: 4,
+ gap: 2,
display: 'flex',
flex: 1,
maxW: '768px',
@@ -232,6 +232,7 @@ RootContainerElementViewMode.displayName = 'RootContainerElementViewMode';
const rootEditModeSx: SystemStyleObject = {
...rootViewModeSx,
+ gap: 4,
'&[data-is-dragging-over="true"]': {
opacity: 1,
bg: 'base.850',
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/HeadingElementContent.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/HeadingElementContent.tsx
index 144c7a121d4..dc89d50f8a9 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/HeadingElementContent.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/HeadingElementContent.tsx
@@ -1,5 +1,7 @@
import type { HeadingProps, SystemStyleObject } from '@invoke-ai/ui-library';
import { Text } from '@invoke-ai/ui-library';
+import { linkifyOptions, linkifySx } from 'common/components/linkify';
+import Linkify from 'linkify-react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -9,13 +11,14 @@ const headingSx: SystemStyleObject = {
'&[data-is-empty="true"]': {
opacity: 0.3,
},
+ ...linkifySx,
};
export const HeadingElementContent = memo(({ content, ...rest }: { content: string } & HeadingProps) => {
const { t } = useTranslation();
return (
- {content || t('workflows.builder.headingPlaceholder')}
+ {content || t('workflows.builder.headingPlaceholder')}
);
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementDescriptionEditable.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementDescriptionEditable.tsx
index 63acf2918b7..fa49391c22c 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementDescriptionEditable.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementDescriptionEditable.tsx
@@ -1,10 +1,12 @@
import { FormHelperText, Textarea } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
+import { linkifyOptions, linkifySx } from 'common/components/linkify';
import { useEditable } from 'common/hooks/useEditable';
import { useInputFieldDescription } from 'features/nodes/hooks/useInputFieldDescription';
import { useInputFieldTemplate } from 'features/nodes/hooks/useInputFieldTemplate';
import { fieldDescriptionChanged } from 'features/nodes/store/nodesSlice';
import type { NodeFieldElement } from 'features/nodes/types/workflow';
+import Linkify from 'linkify-react';
import { memo, useCallback, useRef } from 'react';
export const NodeFieldElementDescriptionEditable = memo(({ el }: { el: NodeFieldElement }) => {
@@ -36,7 +38,11 @@ export const NodeFieldElementDescriptionEditable = memo(({ el }: { el: NodeField
});
if (!editable.isEditing) {
- return {editable.value};
+ return (
+
+ {editable.value}
+
+ );
}
return (
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementViewMode.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementViewMode.tsx
index f028ea4da18..2e5ba213771 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementViewMode.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/NodeFieldElementViewMode.tsx
@@ -1,5 +1,6 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex, FormControl, FormHelperText } from '@invoke-ai/ui-library';
+import { linkifyOptions, linkifySx } from 'common/components/linkify';
import { InputFieldRenderer } from 'features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer';
import { useContainerContext } from 'features/nodes/components/sidePanel/builder/contexts';
import { NodeFieldElementLabel } from 'features/nodes/components/sidePanel/builder/NodeFieldElementLabel';
@@ -7,6 +8,7 @@ import { useInputFieldDescription } from 'features/nodes/hooks/useInputFieldDesc
import { useInputFieldTemplate } from 'features/nodes/hooks/useInputFieldTemplate';
import type { NodeFieldElement } from 'features/nodes/types/workflow';
import { NODE_FIELD_CLASS_NAME } from 'features/nodes/types/workflow';
+import Linkify from 'linkify-react';
import { memo, useMemo } from 'react';
const sx: SystemStyleObject = {
@@ -18,6 +20,9 @@ const sx: SystemStyleObject = {
flex: '1 1 0',
minW: 32,
},
+ '&[data-with-description="false"]': {
+ pb: 2,
+ },
};
export const NodeFieldElementViewMode = memo(({ el }: { el: NodeFieldElement }) => {
@@ -33,7 +38,13 @@ export const NodeFieldElementViewMode = memo(({ el }: { el: NodeFieldElement })
);
return (
-
+
@@ -43,7 +54,11 @@ export const NodeFieldElementViewMode = memo(({ el }: { el: NodeFieldElement })
settings={data.settings}
/>
- {showDescription && _description && {_description}}
+ {showDescription && _description && (
+
+ {_description}
+
+ )}
);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/TextElementContent.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/TextElementContent.tsx
index d62b56de7c5..c81d2bddb36 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/TextElementContent.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/TextElementContent.tsx
@@ -1,5 +1,7 @@
import type { SystemStyleObject, TextProps } from '@invoke-ai/ui-library';
import { Text } from '@invoke-ai/ui-library';
+import { linkifyOptions, linkifySx } from 'common/components/linkify';
+import Linkify from 'linkify-react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -9,13 +11,14 @@ const textSx: SystemStyleObject = {
'&[data-is-empty="true"]': {
opacity: 0.3,
},
+ ...linkifySx,
};
export const TextElementContent = memo(({ content, ...rest }: { content: string } & TextProps) => {
const { t } = useTranslation();
return (
- {content || t('workflows.builder.textPlaceholder')}
+ {content || t('workflows.builder.textPlaceholder')}
);
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/NewWorkflowButton.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/NewWorkflowButton.tsx
similarity index 98%
rename from invokeai/frontend/web/src/features/nodes/components/sidePanel/NewWorkflowButton.tsx
rename to invokeai/frontend/web/src/features/workflowLibrary/components/NewWorkflowButton.tsx
index 1fa11e2dbec..e51ff78eb29 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/NewWorkflowButton.tsx
+++ b/invokeai/frontend/web/src/features/workflowLibrary/components/NewWorkflowButton.tsx
@@ -23,7 +23,6 @@ export const NewWorkflowButton = memo(() => {
}
diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem.tsx
deleted file mode 100644
index 59699427951..00000000000
--- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { MenuItem } from '@invoke-ai/ui-library';
-import { useWorkflowEditorSettingsModal } from 'features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings';
-import { memo } from 'react';
-import { useTranslation } from 'react-i18next';
-import { PiGearSixFill } from 'react-icons/pi';
-
-const DownloadWorkflowMenuItem = () => {
- const { t } = useTranslation();
- const modal = useWorkflowEditorSettingsModal();
-
- return (
- } onClick={modal.setTrue}>
- {t('nodes.workflowSettings')}
-
- );
-};
-
-export default memo(DownloadWorkflowMenuItem);
diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx
index 73e9f5d4ba6..25da6bd4dea 100644
--- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx
+++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx
@@ -13,13 +13,12 @@ import LoadWorkflowFromGraphMenuItem from 'features/workflowLibrary/components/W
import { NewWorkflowMenuItem } from 'features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem';
import SaveWorkflowAsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowAsMenuItem';
import SaveWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowMenuItem';
-import SettingsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem';
import UploadWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/UploadWorkflowMenuItem';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiDotsThreeOutlineFill } from 'react-icons/pi';
-const WorkflowLibraryMenu = () => {
+export const WorkflowLibraryMenu = memo(() => {
const { t } = useTranslation();
const { isOpen, onOpen, onClose } = useDisclosure();
const shift = useShiftModifier();
@@ -31,6 +30,8 @@ const WorkflowLibraryMenu = () => {
aria-label={t('workflows.workflowEditorMenu')}
icon={}
pointerEvents="auto"
+ size="sm"
+ variant="ghost"
/>
@@ -39,13 +40,10 @@ const WorkflowLibraryMenu = () => {
-
-
{shift && }
{shift && }
);
-};
-
-export default memo(WorkflowLibraryMenu);
+});
+WorkflowLibraryMenu.displayName = 'WorkflowLibraryMenu';
diff --git a/invokeai/version/invokeai_version.py b/invokeai/version/invokeai_version.py
index 7f4ce2d4c31..28a77fe053e 100644
--- a/invokeai/version/invokeai_version.py
+++ b/invokeai/version/invokeai_version.py
@@ -1 +1 @@
-__version__ = "5.7.0"
+__version__ = "5.7.1"