From 66876f16b275c67152dc909bdda511889f5cfbf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Valderrama?= Date: Tue, 15 Sep 2026 07:24:55 +0200 Subject: [PATCH] :sparkles: Error page for instances without admin-console configuration (#11649) * :sparkles: Error page for instances without admin-console configuration * :paperclip: Code review --- backend/src/app/http/errors.clj | 7 +++++++ backend/src/app/nitrate.clj | 18 ++++++++++++------ backend/src/app/rpc/commands/profile.clj | 2 +- frontend/src/app/main/errors.cljs | 1 + frontend/src/app/main/repo.cljs | 4 ++++ frontend/src/app/main/ui/static.cljs | 24 ++++++++++++++++++++++++ frontend/src/app/main/ui/static.scss | 8 ++++++++ frontend/translations/en.po | 16 ++++++++++++++++ frontend/translations/es.po | 16 ++++++++++++++++ 9 files changed, 89 insertions(+), 7 deletions(-) diff --git a/backend/src/app/http/errors.clj b/backend/src/app/http/errors.clj index 4d5df93153..faf6fd6b2f 100644 --- a/backend/src/app/http/errors.clj +++ b/backend/src/app/http/errors.clj @@ -166,6 +166,13 @@ {::yres/status 503 ::yres/body {:type :nitrate-unavailable}})) +(defmethod handle-error :nitrate-not-configured + [err request _] + (binding [l/*context* (request->context request)] + (l/warn :hint "nitrate is not configured; blocking request" :cause err) + {::yres/status 503 + ::yres/body {:type :nitrate-not-configured}})) + (defmethod handle-error :internal [error request parent-cause] (binding [l/*context* (request->context request)] diff --git a/backend/src/app/nitrate.clj b/backend/src/app/nitrate.clj index 6cc5dcde91..3b4b41eff0 100644 --- a/backend/src/app/nitrate.clj +++ b/backend/src/app/nitrate.clj @@ -156,9 +156,13 @@ (defn call [cfg method params] (when (contains? cf/flags :admin-console) - (let [client (get cfg ::client) - method (get client method)] - (method params)))) + (let [uri (cf/get :admin-console-uri)] + (if (nil? uri) + (ex/raise :type :nitrate-not-configured + :hint "admin console is not configured; refer to the documentation to complete the setup") + (let [client (get cfg ::client) + method (get client method)] + (method params)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -499,6 +503,8 @@ (defmethod ig/init-key ::client [_ cfg] (when (contains? cf/flags :admin-console) + (when (nil? (cf/get :admin-console-uri)) + (l/warn :hint "admin console is not configured; nitrate calls will fail until the setup is complete")) {:get-team-organization (partial get-team-organization-api cfg) :get-teams-organizations (partial get-teams-organizations-api cfg) :set-team-organization (partial set-team-organization-api cfg) @@ -593,14 +599,14 @@ "Enriches a profile map with subscription information from Nitrate. Adds a :subscription field containing the user's license details. Returns the original profile unchanged if the request fails for a reason - other than Nitrate being unreachable. When Nitrate is unreachable the - `:nitrate-unavailable` exception propagates so the request is rejected." + other than Nitrate being unreachable or unconfigured. When Nitrate is + unreachable or unconfigured the exception propagates so the request is rejected." [cfg profile] (try (let [subscription (call cfg :get-subscription {:profile-id (:id profile)})] (assoc profile :subscription subscription)) (catch Throwable cause - (if (= :nitrate-unavailable (-> cause ex-data :type)) + (if (contains? #{:nitrate-unavailable :nitrate-not-configured} (-> cause ex-data :type)) (throw cause) (do (l/error :hint "failed to get nitrate licence" diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj index 6d878e0ebd..b1ad98c8eb 100644 --- a/backend/src/app/rpc/commands/profile.clj +++ b/backend/src/app/rpc/commands/profile.clj @@ -139,7 +139,7 @@ (catch Throwable cause (if (= :not-found (-> cause ex-data :type)) - {:id uuid/zero :fullname "Anonymous User"} + (with-nitrate-licence {:id uuid/zero :fullname "Anonymous User"} cfg) (throw cause))))) (defn get-profile diff --git a/frontend/src/app/main/errors.cljs b/frontend/src/app/main/errors.cljs index 85c0e9be3e..e1abff9542 100644 --- a/frontend/src/app/main/errors.cljs +++ b/frontend/src/app/main/errors.cljs @@ -450,6 +450,7 @@ (defmethod ptk/handle-error :bad-gateway [error] (handle-exceptional-state error)) (defmethod ptk/handle-error :service-unavailable [error] (handle-exceptional-state error)) (defmethod ptk/handle-error :nitrate-unavailable [error] (handle-exceptional-state error)) +(defmethod ptk/handle-error :nitrate-not-configured [error] (handle-exceptional-state error)) (defn- redirect-to-dashboard [] diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index 68749a7f45..9f6703f6bf 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -90,6 +90,10 @@ (= :nitrate-unavailable (:type body))) (rx/throw (ex-info "http error" {:type :nitrate-unavailable})) + (and (= 503 status) + (= :nitrate-not-configured (:type body))) + (rx/throw (ex-info "http error" {:type :nitrate-not-configured})) + (= 503 status) (rx/throw (ex-info "http error" {:type :service-unavailable})) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 41f20a6710..7dbe18906e 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -342,6 +342,27 @@ [:p {:class (stl/css :nitrate-unavailable-footer)} (tr "labels.copyright-period")]]) +(mf/defc nitrate-not-configured-page* + [] + [:section {:class (stl/css :nitrate-unavailable-layout)} + [:div {:class (stl/css :nitrate-unavailable-content)} + [:> raw-svg* {:id "logo-nitrate-unavailable" :class (stl/css :nitrate-unavailable-logo)}] + [:div {:class (stl/css :nitrate-unavailable-message)} + (tr "labels.nitrate-not-configured.main-message")] + [:div {:class (stl/css :nitrate-not-configured-message)} + (tr "labels.nitrate-not-configured.desc-message")] + [:div {:class (stl/css :nitrate-not-configured-message)} + [:span + (tr "labels.nitrate-not-configured.learn-more") + " " + [:a {:href "https://help.penpot.app/technical-guide/getting-started/" + :target "_blank" + :rel "noopener noreferrer"} + (tr "labels.nitrate-not-configured.technical-guide")]]]] + + [:p {:class (stl/css :nitrate-unavailable-footer)} + (tr "labels.copyright-period")]]) + (mf/defc webgl-context-lost* [] (let [on-reload (mf/use-fn #(js/location.reload))] @@ -562,6 +583,9 @@ :nitrate-unavailable [:> nitrate-unavailable*] + :nitrate-not-configured + [:> nitrate-not-configured-page*] + :sso-error [:> sso-error-section* {:organization-id (get data :organization-id) :organization-name (get data :organization-name) diff --git a/frontend/src/app/main/ui/static.scss b/frontend/src/app/main/ui/static.scss index 8c0e8d4516..77e7961895 100644 --- a/frontend/src/app/main/ui/static.scss +++ b/frontend/src/app/main/ui/static.scss @@ -51,6 +51,14 @@ font-weight: 500; } +.nitrate-not-configured-message { + @include t.use-typography("title-medium"); + + color: var(--color-foreground-secondary); + max-width: 32rem; + text-align: center; +} + .nitrate-unavailable-footer { @include t.use-typography("title-medium"); diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 8e7da556fa..03c72569c6 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3289,6 +3289,22 @@ msgstr "" "Penpot is temporarily unavailable due to a system issue. Please try again " "shortly." +#: src/app/main/ui/static.cljs:344 +msgid "labels.nitrate-not-configured.main-message" +msgstr "Penpot can't start yet." + +#: src/app/main/ui/static.cljs:345 +msgid "labels.nitrate-not-configured.desc-message" +msgstr "This instance needs a setup step that comes with the latest version." + +#: src/app/main/ui/static.cljs:346 +msgid "labels.nitrate-not-configured.learn-more" +msgstr "Check out our" + +#: src/app/main/ui/static.cljs:346 +msgid "labels.nitrate-not-configured.technical-guide" +msgstr "technical guide" + #: src/app/main/ui/dashboard/comments.cljs:120, src/app/main/ui/workspace/comments.cljs:162 msgid "labels.no-comments-available" msgstr "You're all caught up! New comment notifications will appear here." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 4b45306c07..e49bdd33e3 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3199,6 +3199,22 @@ msgstr "" "Penpot no está disponible temporalmente debido a un problema del sistema. " "Por favor, inténtalo de nuevo en unos momentos." +#: src/app/main/ui/static.cljs:344 +msgid "labels.nitrate-not-configured.main-message" +msgstr "Penpot no puede iniciarse aún." + +#: src/app/main/ui/static.cljs:345 +msgid "labels.nitrate-not-configured.desc-message" +msgstr "Esta instancia requiere un paso de configuración que se incluye en la versión más reciente." + +#: src/app/main/ui/static.cljs:346 +msgid "labels.nitrate-not-configured.learn-more" +msgstr "Echa un vistazo a nuestra" + +#: src/app/main/ui/static.cljs:346 +msgid "labels.nitrate-not-configured.technical-guide" +msgstr "technical guide" + #: src/app/main/ui/dashboard/comments.cljs:120, src/app/main/ui/workspace/comments.cljs:162 msgid "labels.no-comments-available" msgstr "¡Ya estás al día! Nuevas notificaciones de comentarios aparecerán aquí."