diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 13d3e8d88..bd73f025a 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -111,6 +111,7 @@ (def grid-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/")) (def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot.app/penpothub/plugins")) (def plugins-whitelist (into #{} (obj/get global "penpotPluginsWhitelist" []))) +(def templates-uri (obj/get global "penpotTemplatesUri" "https://penpot.github.io/penpot-files/")) (defn- normalize-uri [uri-str] diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 752beded1..a7cbde8f0 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -70,7 +70,7 @@ (mf/defc dashboard-legacy-redirect* {::mf/props :obj ::mf/private true} - [{:keys [section team-id project-id search-term plugin-url]}] + [{:keys [section team-id project-id search-term plugin-url template-url]}] (let [section (case section :dashboard-legacy-search :dashboard-search @@ -97,7 +97,8 @@ (let [params {:team-id team-id :project-id project-id :search-term search-term - :plugin plugin-url}] + :plugin plugin-url + :template-url template-url}] (st/emit! (rt/nav section (d/without-nils params))))) [:> loader* @@ -211,11 +212,12 @@ :dashboard-invitations :dashboard-webhooks :dashboard-settings) - (let [params (get params :query) - team-id (some-> params :team-id uuid) - project-id (some-> params :project-id uuid) - search-term (some-> params :search-term) - plugin-url (some-> params :plugin)] + (let [params (get params :query) + team-id (some-> params :team-id uuid) + project-id (some-> params :project-id uuid) + search-term (some-> params :search-term) + plugin-url (some-> params :plugin) + template-url (some-> params :template)] [:? #_[:& app.main.ui.releases/release-notes-modal {:version "2.4"}] #_[:& app.main.ui.onboarding/onboarding-templates-modal] @@ -241,7 +243,8 @@ :team-id team-id :search-term search-term :plugin-url plugin-url - :project-id project-id}]]]) + :project-id project-id + :template-url template-url}]]]) :workspace (let [params (get params :query) @@ -322,13 +325,15 @@ (let [team-id (some-> params :path :team-id uuid) project-id (some-> params :path :project-id uuid) search-term (some-> params :query :search-term) - plugin-url (some-> params :query :plugin)] + plugin-url (some-> params :query :plugin) + template-url (some-> params :template)] [:> dashboard-legacy-redirect* {:team-id team-id :section section :project-id project-id :search-term search-term - :plugin-url plugin-url}]) + :plugin-url plugin-url + :template-url template-url}]) :viewer-legacy (let [{:keys [query-params path-params]} route diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index f5f495ac2..2c1a33a0f 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -15,6 +15,7 @@ [app.main.data.modal :as modal] [app.main.data.notifications :as notif] [app.main.data.plugins :as dp] + [app.main.data.project :as dpj] [app.main.refs :as refs] [app.main.router :as rt] [app.main.store :as st] @@ -33,9 +34,14 @@ [app.main.ui.workspace.plugins] [app.plugins.register :as preg] [app.util.dom :as dom] + [app.util.http :as http] + [app.util.i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.object :as obj] + [app.util.storage :as storage] + [app.util.webapi :as wapi] [beicon.v2.core :as rx] + [cuerdas.core :as str] [goog.events :as events] [okulary.core :as l] [potok.v2.core :as ptk] @@ -205,9 +211,47 @@ (fn [_] (st/emit! (notif/error "The plugin URL is incorrect"))))))))) +(defn use-templates-import + [can-edit? template-url default-project-id] + (mf/with-layout-effect + [can-edit? template-url default-project-id] + (when (and (some? template-url) (some? default-project-id)) + (if can-edit? + (let [valid-url? (and (str/ends-with? template-url ".penpot") + (str/starts-with? template-url cf/templates-uri)) + template-name (when valid-url? (subs template-url (count cf/templates-uri))) + on-import #(st/emit! (dpj/fetch-files default-project-id) + (dd/fetch-recent-files) + (dd/fetch-projects) + (dd/clear-selected-files) + (ptk/event ::ev/event {::ev/name "install-template-from-link-finished" + :name template-name + :url template-url}))] + (if valid-url? + (do + (st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})) + (->> (http/send! {:method :get + :uri template-url + :response-type :blob + :omit-default-headers true}) + (rx/subs! + (fn [result] + (if (or (< (:status result) 200) (>= (:status result) 300)) + (st/emit! (notif/error (tr "dashboard.import.error"))) + (st/emit! (modal/show + {:type :import + :project-id default-project-id + :entries [{:name template-name :uri (wapi/create-uri (:body result))}] + :on-finish-import on-import}))))))) + (st/emit! (notif/error (tr "dashboard.import.bad-url"))))) + (st/emit! (notif/error (tr "dashboard.import.no-perms")))) + + (binding [storage/*sync* true] + (swap! storage/session dissoc :template-url))))) + (mf/defc dashboard* {::mf/props :obj} - [{:keys [profile project-id team-id search-term plugin-url section]}] + [{:keys [profile project-id team-id search-term plugin-url template-url section]}] (let [team (mf/deref refs/team) projects (mf/deref refs/projects) @@ -216,6 +260,9 @@ (->> (vals projects) (filterv #(= team-id (:team-id %))))) + can-edit? (dm/get-in team [:permissions :can-edit]) + template-url (or template-url (:template-url storage/session)) + default-project (mf/with-memo [projects] (->> projects @@ -239,6 +286,7 @@ (events/unlistenByKey key)))) (use-plugin-register plugin-url team-id (:id default-project)) + (use-templates-import can-edit? template-url (:id default-project)) [:& (mf/provider ctx/current-project-id) {:value project-id} [:> modal-container*] diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs index 5a114cfc6..68b9acd10 100644 --- a/frontend/src/app/main/ui/routes.cljs +++ b/frontend/src/app/main/ui/routes.cljs @@ -14,6 +14,7 @@ [app.main.repo :as rp] [app.main.router :as rt] [app.main.store :as st] + [app.util.storage :as storage] [beicon.v2.core :as rx] [cuerdas.core :as str] [potok.v2.core :as ptk])) @@ -75,14 +76,23 @@ ["/workspace" :workspace] ["/workspace/:project-id/:file-id" :workspace-legacy]]) + +(defn- store-session-params + [{:keys [template]}] + (binding [storage/*sync* true] + (when (some? template) + (swap! storage/session assoc + :template-url template)))) + (defn on-navigate [router path] - (let [location (.-location js/document) - [base-path qs] (str/split path "?") - location-path (dm/str (.-origin location) (.-pathname location)) + (let [location (.-location js/document) + [base-path qs] (str/split path "?") + location-path (dm/str (.-origin location) (.-pathname location)) valid-location? (= location-path (dm/str cf/public-uri)) - match (rt/match router path) - empty-path? (or (= base-path "") (= base-path "/"))] + match (rt/match router path) + empty-path? (or (= base-path "") (= base-path "/")) + query-params (u/query-string->map qs)] (cond (not valid-location?) @@ -99,14 +109,15 @@ (rx/subs! (fn [{:keys [id] :as profile}] (cond (= id uuid/zero) - (st/emit! (rt/nav :auth-login)) + (do + (store-session-params query-params) + (st/emit! (rt/nav :auth-login))) empty-path? (let [team-id (or (dtm/get-last-team-id) (:default-team-id profile))] (st/emit! (rt/nav :dashboard-recent - (-> (u/query-string->map qs) - (assoc :team-id team-id))))) + (assoc query-params :team-id team-id)))) :else (st/emit! (rt/assign-exception {:type :not-found}))))))))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 0ce02d628..edb8c149c 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6966,6 +6966,15 @@ msgstr "None" msgid "dashboard.settings.notifications.submit" msgstr "Update settings" +msgid "dashboard.import.error" +msgstr "Import failed. Please try again" + +msgid "dashboard.import.bad-url" +msgstr "Import failed. The template URL is incorrect" + +msgid "dashboard.import.no-perms" +msgstr "You don’t have permission to import to this team" + msgid "labels.notifications" msgstr "Notifications" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 0344475bc..33c030f30 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6687,7 +6687,7 @@ msgstr "Nombre" #: src/app/main/ui/workspace/tokens/form.cljs msgid "workspace.token.enter-token-name" -msgstr "Introduce un nombre para el token %s" +msgstr "Introduce un nombre para el token %s" #: src/app/main/ui/workspace/tokens/form.cljs msgid "workspace.token.token-value" @@ -6923,6 +6923,15 @@ msgstr "Ninguna" msgid "dashboard.settings.notifications.submit" msgstr "Actualizar configuración" +msgid "dashboard.import.error" +msgstr "La importación ha fallado. Intentalo de nuevo, por favor" + +msgid "dashboard.import.bad-url" +msgstr "La importación ha fallado. La URL de la plantilla es incorrecta" + +msgid "dashboard.import.no-perms" +msgstr "No tienes permisos para importar en este equipo" + msgid "labels.notifications" msgstr "Notificaciones"