diff --git a/Classes/GraphQL/Resolver/Type/MutationResolver.php b/Classes/GraphQL/Resolver/Type/MutationResolver.php index 3892b1489..825db41a4 100644 --- a/Classes/GraphQL/Resolver/Type/MutationResolver.php +++ b/Classes/GraphQL/Resolver/Type/MutationResolver.php @@ -23,6 +23,7 @@ use Flowpack\Media\Ui\GraphQL\Context\AssetSourceContext; use Flowpack\Media\Ui\Service\AssetCollectionService; use Neos\Flow\Annotations as Flow; +use Neos\Flow\I18n\Translator; use Neos\Flow\Persistence\Exception\IllegalObjectTypeException; use Neos\Flow\Persistence\Exception\InvalidQueryException; use Neos\Flow\Persistence\PersistenceManagerInterface; @@ -113,6 +114,23 @@ class MutationResolver implements ResolverInterface */ protected $assetCollectionService; + /** + * @Flow\Inject + * @var Translator + */ + protected $translator; + + protected function localizedMessage(string $id, string $fallback = '', array $arguments = []): string + { + return $this->translator->translateById($id, [], null, null, 'Main', 'Flowpack.Media.Ui') ?? $fallback; + } + + protected function localizedMessageFromException(\Exception $exception): string + { + $labelIdentifier = 'errors.' . $exception->getCode() . '.message'; + return $this->localizedMessage($labelIdentifier, $exception->getMessage()); + } + /** * @throws Exception */ @@ -125,23 +143,45 @@ public function deleteAsset($_, array $variables, AssetSourceContext $assetSourc $assetProxy = $assetSourceContext->getAssetProxy($id, $assetSourceId); if (!$assetProxy) { - return new MutationResult(false, ['Asset could not be resolved']); + return new MutationResult( + false, + [$this->localizedMessage( + 'actions.deleteAssets.noProxy', + 'Asset could not be resolved') + ] + ); } $asset = $assetSourceContext->getAssetForProxy($assetProxy); if (!$asset) { - return new MutationResult(false, ['Cannot delete asset that was never imported']); + return new MutationResult( + false, + [ + $this->localizedMessage( + 'actions.deleteAssets.noImportExists', + 'Cannot delete asset that was never imported' + ) + ] + ); } try { $this->assetRepository->remove($asset); } catch (AssetServiceException $e) { - return new MutationResult(false, [$e->getMessage()]); + return new MutationResult(false, [$this->localizedMessageFromException($e)]); } catch (\Exception $e) { throw new Exception('Failed to delete asset', 1591537315); } - return new MutationResult(true, ['Asset deleted']); + return new MutationResult( + true, + [ + $this->localizedMessage( + 'actions.deleteAssets.success', + 'Asset deleted' + ) + ] + ); } /** diff --git a/Classes/Transform/FlowErrorTransform.php b/Classes/Transform/FlowErrorTransform.php new file mode 100644 index 000000000..86846fe12 --- /dev/null +++ b/Classes/Transform/FlowErrorTransform.php @@ -0,0 +1,49 @@ +errors = array_map(function (Error $error) { + $previousError = $error->getPrevious(); + if (!$previousError instanceof Error) { + $message = $this->throwableStorage->logThrowable($previousError); + + if (!$this->includeExceptionMessageInOutput) { + $message = preg_replace('/.* - See also: (.+)\.txt$/s', 'Internal error ($1)', $message); + } + + $errorExtendedInformation = $error->getExtensions(); + $errorExtendedInformation['errorCode'] = $previousError->getCode(); + + return new Error( + $message, + $error->getNodes(), + $error->getSource(), + $error->getPositions(), + $error->getPath(), + $previousError, + $errorExtendedInformation + ); + } + + return $error; + }, $result->errors); + + return $result; + } +} diff --git a/Configuration/Settings.GraphQL.yaml b/Configuration/Settings.GraphQL.yaml index 73682b593..ce61b3db7 100644 --- a/Configuration/Settings.GraphQL.yaml +++ b/Configuration/Settings.GraphQL.yaml @@ -4,6 +4,7 @@ t3n: 'media-assets': logRequests: false context: 'Flowpack\Media\Ui\GraphQL\Context\AssetSourceContext' + errorTransform: 'Flowpack\Media\Ui\Transform\FlowErrorTransform' schemas: root: typeDefs: 'resource://Flowpack.Media.Ui/Private/GraphQL/schema.root.graphql' diff --git a/Resources/Private/JavaScript/asset-collections/src/components/CreateAssetCollectionDialog.tsx b/Resources/Private/JavaScript/asset-collections/src/components/CreateAssetCollectionDialog.tsx index c9898df57..827ac07e2 100644 --- a/Resources/Private/JavaScript/asset-collections/src/components/CreateAssetCollectionDialog.tsx +++ b/Resources/Private/JavaScript/asset-collections/src/components/CreateAssetCollectionDialog.tsx @@ -31,11 +31,8 @@ const CreateAssetCollectionDialog = () => { .then(() => { Notify.ok(translate('assetCollectionActions.create.success', 'Asset collection was created')); }) - .catch((error) => { - Notify.error( - translate('assetCollectionActions.create.error', 'Failed to create asset collection'), - error.message - ); + .catch(() => { + return; }); }, [setDialogVisible, createAssetCollection, title, selectedAssetCollection?.id, Notify, translate]); diff --git a/Resources/Private/JavaScript/asset-collections/src/components/DeleteButton.tsx b/Resources/Private/JavaScript/asset-collections/src/components/DeleteButton.tsx index edad69b60..9e3f4596c 100644 --- a/Resources/Private/JavaScript/asset-collections/src/components/DeleteButton.tsx +++ b/Resources/Private/JavaScript/asset-collections/src/components/DeleteButton.tsx @@ -49,11 +49,8 @@ const DeleteButton: React.FC = () => { ); setSelectedAssetCollectionAndTag({ tagId: null, assetCollectionId: null }); }) - .catch((error) => { - Notify.error( - translate('assetCollectionActions.delete.error', 'Failed to delete asset collection'), - error.message - ); + .catch(() => { + return; }); } }, [ diff --git a/Resources/Private/JavaScript/asset-tags/src/components/CreateTagDialog.tsx b/Resources/Private/JavaScript/asset-tags/src/components/CreateTagDialog.tsx index 760c4a58e..f2af832f0 100644 --- a/Resources/Private/JavaScript/asset-tags/src/components/CreateTagDialog.tsx +++ b/Resources/Private/JavaScript/asset-tags/src/components/CreateTagDialog.tsx @@ -28,8 +28,8 @@ const CreateTagDialog: React.FC = () => { .then(() => { Notify.ok(translate('tagActions.create.success', 'Tag was created')); }) - .catch((error) => { - Notify.error(translate('tagActions.create.error', 'Failed to create tag'), error.message); + .catch(() => { + return; }); }, [Notify, setDialogState, createTag, dialogState, translate, selectedAssetCollection]); const setLabel = useCallback((label) => setDialogState((state) => ({ ...state, label })), [setDialogState]); diff --git a/Resources/Private/JavaScript/asset-upload/src/components/Dialogs/NewAssetDialog.tsx b/Resources/Private/JavaScript/asset-upload/src/components/Dialogs/NewAssetDialog.tsx index aa19cd192..eeb616084 100644 --- a/Resources/Private/JavaScript/asset-upload/src/components/Dialogs/NewAssetDialog.tsx +++ b/Resources/Private/JavaScript/asset-upload/src/components/Dialogs/NewAssetDialog.tsx @@ -55,8 +55,8 @@ const NewAssetDialog: React.FC = () => { void refetch(); } }) - .catch((error) => { - Notify.error(translate('fileUpload.error', 'Upload failed'), error); + .catch(() => { + return; }); }, [uploadFiles, dialogState.files.selected, setFiles, Notify, translate, refetch]); diff --git a/Resources/Private/JavaScript/media-module/src/components/Main/AssetActions.tsx b/Resources/Private/JavaScript/media-module/src/components/Main/AssetActions.tsx index 19c030fc6..689e356bc 100644 --- a/Resources/Private/JavaScript/media-module/src/components/Main/AssetActions.tsx +++ b/Resources/Private/JavaScript/media-module/src/components/Main/AssetActions.tsx @@ -29,8 +29,8 @@ const AssetActions: React.FC = ({ asset }: ItemActionsProps) = .then(() => { Notify.ok(translate('assetActions.import.success', 'Asset was successfully imported')); }) - .catch((error) => { - Notify.error(translate('assetActions.import.error', 'Failed to import asset'), error.message); + .catch(() => { + return; }); }, [importAsset, asset, Notify, translate]); diff --git a/Resources/Private/JavaScript/media-module/src/core/CreateErrorHandler.ts b/Resources/Private/JavaScript/media-module/src/core/CreateErrorHandler.ts index 5dd8b6ab6..404a992a6 100644 --- a/Resources/Private/JavaScript/media-module/src/core/CreateErrorHandler.ts +++ b/Resources/Private/JavaScript/media-module/src/core/CreateErrorHandler.ts @@ -1,20 +1,27 @@ import { onError } from '@apollo/client/link/error'; const createErrorHandler = (notify: NeosNotification) => { + const translate = (id, value = null, args = {}, packageKey = 'Flowpack.Media.Ui', source = 'Main') => { + return window.NeosCMS.I18n.translate(id, value, packageKey, source, args); + }; + return onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) { graphQLErrors.map((data) => { - const isInternalError = data.extensions.code === 'INTERNAL_SERVER_ERROR'; - - console.error( - data.extensions.code === isInternalError ? '[Internal server error]' : '[GraphQL error]', - data.path, - data - ); + const isInternalError = data.extensions.category === 'internal'; + const defaultErrorTitle = isInternalError + ? translate('errors.internal.title', 'Internal server error') + : translate('errors.graphql.title', 'Communication error'); + let errorMessageLabel = ''; + let errorTitleLabel = ''; + if (data.extensions.errorCode) { + errorTitleLabel = `errors.${data.extensions.errorCode}.title`; + errorMessageLabel = `errors.${data.extensions.errorCode}.message`; + } notify.error( - data.extensions.code === isInternalError ? 'Internal server error' : 'Communication error', - data.message + translate(errorTitleLabel, defaultErrorTitle), + errorMessageLabel.length ? translate(errorMessageLabel) : data.message ); }); } diff --git a/Resources/Private/Translations/de/Main.xlf b/Resources/Private/Translations/de/Main.xlf index fdeb4ff54..1b985d9e1 100644 --- a/Resources/Private/Translations/de/Main.xlf +++ b/Resources/Private/Translations/de/Main.xlf @@ -45,6 +45,10 @@ Uploading… Hochladen… + + Upload finished + Der Upload wurde abgeschlossen + Successful uploads Erfolgreiche Uploads @@ -93,6 +97,18 @@ Cancel Abbrechen + + Some files could not be uploaded + Einige Dateien konnten nicht hochgeladen werden + + + The given file cannot be uploaded. + Die Datei kann nicht hochgeladen werden. + + + Upload failed + Upload fehlgeschlagen + You can only select any of the following types: {types} @@ -159,10 +175,26 @@ Error while trying to delete the assets Fehler beim Löschen der Dateien + + Asset could not be resolved + Datei konnte nicht gefunden werden + + + Cannot delete asset that was never imported + Die Datei kann nicht gelöscht werden, da sie nie importiert wurde. + + + Asset deleted + Datei gelöscht + Flush clipboard Zwischenablage leeren + + Cannot select asset as it couldn't be loaded + Die Datei konnte nicht geladen werden und kann daher nicht ausgewählt werden + Flush clipboard Zwischenablage leeren @@ -238,6 +270,38 @@ Yes, proceed with deleting the asset Ja, mit dem Löschen fortfahren + + The asset has been updated + Die Datei wurde aktualisiert + + + Error while updating the asset + Fehler beim Aktualisieren der Datei + + + The tag has been updated + Der Tag wurde aktualisiert + + + Error while updating the tag + Fehler beim Aktualisieren des Tags + + + The asset has been tagged + Die Tags der Datei wurde aktualisiert + + + Error while tagging the asset + Fehler beim Taggen der Datei + + + The asset collection has been updated + Die Sammlung wurde aktualisiert + + + Error while updating the asset collection + Fehler beim Aktualisieren der Sammlung + @@ -300,6 +364,15 @@ Untagged Nicht getaggt + + The parent collection has been set + Die übergeordnete Sammlung wurde gesetzt + + + Error while setting the parent collection + Fehler beim Setzen der übergeordneten Sammlung + + @@ -371,6 +444,15 @@ Error while trying to delete the tag Fehler beim Löschen des Tags + + Error while tagging the asset collection + Fehler beim Taggen der Sammlung + + + The asset collection has been tagged + Die Sammlung wurde getaggt + + @@ -609,6 +691,15 @@ Identifier Bezeichner + + The collections for the asset have been set + Die Sammlungen für die Datei wurden angepasst + + + Error while setting the collections for the asset + Fehler beim Anpassen der Sammlungen für die Datei + + @@ -662,6 +753,14 @@ Updating… Wird geändert… + + Update finished + Änderung abgeschlossen + + + Update failed + Änderung fehlgeschlagen + @@ -762,6 +861,184 @@ Gehe zu nächster Seite + + + + Internal server error + Interner Serverfehler + + + Communication error + Kommunikationsfehler + + + Failed to create tag + Tag-Erstellung fehlgeschlagen + + + This tag is already exists. Please choose a different one. + Dieser Tag existiert bereits. Bitte wählen Sie einen anderen aus. + + + The specified asset was not found. + Die angegebene Datei wurde nicht gefunden. + + + Parent must be an AssetCollection + Übergeordnetes Element muss eine Sammlung sein + + + Invalid metadata definition + Ungültige Metadaten-Definition + + + Failed to delete asset + Datei-Löschung fehlgeschlagen + + + Cannot update asset that was never imported + Die Datei kann nicht aktualisiert werden, da sie nie importiert wurde + + + Failed to update asset + Datei-Aktualisierung fehlgeschlagen + + + Cannot tag asset that was never imported + Die Datei kann nicht getaggt werden, da sie nie importiert wurde + + + Asset type does not support tagging + Datei-Typ unterstützt keine Tags + + + Cannot tag asset with tag that does not exist + Die Datei kann nicht mit einem nicht existierenden Tag versehen werden + + + Failed to update asset + Datei-Aktualisierung fehlgeschlagen + + + Cannot tag asset that was never imported + Die Datei kann nicht getaggt werden, da sie nie importiert wurde + + + Asset type does not support tagging + Datei-Typ unterstützt keine Tags + + + Cannot tag asset with tag that does not exist + Die Datei kann nicht mit einem nicht existierenden Tag versehen werden + + + Failed to set asset tags + Setzen der Datei-Tags fehlgeschlagen + + + Cannot assign collections to asset that was never imported + Sammlungen können nicht zu einer Datei zugewiesen werden, das nie importiert wurde + + + Asset type does not support collections + Datei-Typ unterstützt keine Sammlungen + + + Cannot assign non existing assign collection to asset + Nicht existierende Sammlung kann nicht zugewiesen werden + + + Failed to assign asset collections + Zuweisung der Datei-Sammlungen fehlgeschlagen + + + Cannot untag asset that was never imported + Das Tag der Datei kann nicht entfernt werden, da sie nie importiert wurde + + + Asset type does not support tagging + Datei-Typ unterstützt keine Tags + + + Cannot untag asset from tag that does not exist + Datei kann nicht von einem nicht existierenden Tag entfernt werden + + + Failed to update asset + Datei-Aktualisierung fehlgeschlagen + + + No proxy found for asset + Kein Proxy für diese Datei gefunden + + + Cannot replace asset that was never imported + Datei kann nicht ersetzt werden, da sie nie importiert wurde + + + Asset type does not support replacing + Datei-Typ unterstützt kein Ersetzen + + + Filename was empty + Dateiname war leer + + + No proxy found for asset + Kein Proxy für die Datei gefunden + + + Cannot rename asset that was never imported + Datei kann nicht umbenannt werden, da sie nie importiert wurde + + + Asset type does not support renaming + Datei-Typ unterstützt kein Umbenennen + + + Could not import asset + Datei konnte nicht importiert werden + + + Asset collection not found + Datei-Sammlung nicht gefunden + + + Asset collection not found + Datei-Sammlung nicht gefunden + + + Cannot tag asset collection with tag that does not exist + Die Datei-Sammlung kann nicht mit einem nicht existierenden Tag versehen werden + + + Asset collection not found + Datei-Sammlung nicht gefunden + + + Parent asset collection not found + Übergeordnete Datei-Sammlung nicht gefunden + + + Tag not found + Tag nicht gefunden + + + Tag not found + Tag nicht gefunden + + + Not supported: AssetProxyQueryInterface::setLimit does not accept `null`. + Nicht unterstützt: AssetProxyQueryInterface::setLimit akzeptiert kein `null`. + + + This method requires "flowpack/entity-usage-databasestorage" to be installed.' + Diese Methode erfordert die Installation von "flowpack/entity-usage-databasestorage". + + + Asset could not be deleted, because it is still in use. + Die Datei konnte nicht gelöscht werden, da sie noch verwendet wird. + diff --git a/Resources/Private/Translations/en/Main.xlf b/Resources/Private/Translations/en/Main.xlf index 8f08aab48..2cbd5f036 100644 --- a/Resources/Private/Translations/en/Main.xlf +++ b/Resources/Private/Translations/en/Main.xlf @@ -35,6 +35,9 @@ Uploading… + + Upload finished + Successful uploads @@ -71,6 +74,15 @@ Cancel + + Some files could not be uploaded + + + The given file cannot be uploaded. + + + Upload failed + You can only select any of the following types: {types} @@ -115,6 +127,15 @@ Yes, proceed with deleting the assets + + Asset could not be resolved + + + Cannot delete asset that was never imported + + + Asset deleted + The assets have been deleted @@ -124,6 +145,9 @@ Flush clipboard + + Cannot select asset as it couldn't be loaded + Flush clipboard @@ -181,6 +205,30 @@ Yes, proceed with deleting the asset + + The asset has been updated + + + Error while updating the asset + + + The tag has been updated + + + Error while updating the tag + + + The asset has been tagged + + + Error while tagging the asset + + + The asset collection has been updated + + + Error while updating the asset collection + @@ -229,6 +277,12 @@ Untagged + + The parent collection has been set + + + Error while setting the parent collection + @@ -283,6 +337,12 @@ Error while trying to delete the tag + + Error while tagging the asset collection + + + The asset collection has been tagged + @@ -467,6 +527,12 @@ IPTC Metadata + + The collections for the asset have been set + + + Error while setting the collections for the asset + @@ -509,6 +575,12 @@ Updating… + + Update finished + + + Update failed + @@ -586,6 +658,140 @@ Go to next page + + + + Internal server error + + + Communication error + + + Failed to create tag + + + This tag is already exists. Please choose a different one. + + + The specified asset was not found. + + + Parent must be an AssetCollection + + + Invalid metadata definition + + + Failed to delete asset + + + Cannot update asset that was never imported + + + Failed to update asset + + + Cannot tag asset that was never imported + + + Asset type does not support tagging + + + Cannot tag asset with tag that does not exist + + + Failed to update asset + + + Cannot tag asset that was never imported + + + Asset type does not support tagging + + + Cannot tag asset with tag that does not exist + + + Failed to set asset tags + + + Cannot assign collections to asset that was never imported + + + Asset type does not support collections + + + Cannot assign non existing assign collection to asset + + + Failed to assign asset collections + + + Cannot untag asset that was never imported + + + Asset type does not support tagging + + + Cannot untag asset from tag that does not exist + + + Failed to update asset + + + No proxy found for asset + + + Cannot replace asset that was never imported + + + Asset type does not support replacing + + + Filename was empty + + + No proxy found for asset + + + Cannot rename asset that was never imported + + + Asset type does not support renaming + + + Could not import asset + + + Asset collection not found + + + Asset collection not found + + + Cannot tag asset collection with tag that does not exist + + + Asset collection not found + + + Parent asset collection not found + + + Tag not found + + + Tag not found + + + Not supported: AssetProxyQueryInterface::setLimit does not accept `null`. + + + This method requires "flowpack/entity-usage-databasestorage" to be installed. + + + Asset could not be deleted, because it is still in use. +