mirror of
https://github.com/penpot/penpot.git
synced 2025-05-30 15:46:12 +02:00
🎉 Add features assignation for teams
This commit is contained in:
parent
7db8d7b7ab
commit
6f93b41920
84 changed files with 2390 additions and 1777 deletions
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.data.common
|
||||
"A general purpose events."
|
||||
(:require
|
||||
[app.common.files.features :as ffeat]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.config :as cf]
|
||||
[app.main.data.messages :as msg]
|
||||
|
@ -90,9 +89,7 @@
|
|||
(ptk/reify ::show-shared-dialog
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [features (cond-> ffeat/enabled
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2"))
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
data (:workspace-data state)
|
||||
file (:workspace-file state)]
|
||||
(->> (if (and data file)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.uri :as u]
|
||||
|
@ -28,6 +29,7 @@
|
|||
[app.util.timers :as tm]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -43,11 +45,10 @@
|
|||
(ptk/reify ::initialize
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(du/set-current-team! id)
|
||||
(let [prev-team-id (:current-team-id state)]
|
||||
(cond-> state
|
||||
(not= prev-team-id id)
|
||||
(-> (assoc :current-team-id id)
|
||||
(-> (dissoc :current-team-id)
|
||||
(dissoc :dashboard-files)
|
||||
(dissoc :dashboard-projects)
|
||||
(dissoc :dashboard-shared-files)
|
||||
|
@ -58,27 +59,36 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/concat
|
||||
(rx/of (features/initialize))
|
||||
(rx/merge
|
||||
;; fetch teams must be first in case the team doesn't exist
|
||||
(ptk/watch (du/fetch-teams) state stream)
|
||||
(ptk/watch (df/load-team-fonts id) state stream)
|
||||
(ptk/watch (fetch-projects) state stream)
|
||||
(ptk/watch (fetch-team-members) state stream)
|
||||
(ptk/watch (du/fetch-users {:team-id id}) state stream)
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize) stream)
|
||||
profile-id (:profile-id state)]
|
||||
|
||||
(let [stoper (rx/filter (ptk/type? ::finalize) stream)
|
||||
profile-id (:profile-id state)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dws/message))
|
||||
(rx/map deref)
|
||||
(rx/filter (fn [{:keys [subs-id type] :as msg}]
|
||||
(and (or (= subs-id uuid/zero)
|
||||
(= subs-id profile-id))
|
||||
(= :notification type))))
|
||||
(rx/map handle-notification)
|
||||
(rx/take-until stoper))))))))
|
||||
(->> (rx/merge
|
||||
;; fetch teams must be first in case the team doesn't exist
|
||||
(ptk/watch (du/fetch-teams) state stream)
|
||||
(ptk/watch (df/load-team-fonts id) state stream)
|
||||
(ptk/watch (fetch-projects id) state stream)
|
||||
(ptk/watch (fetch-team-members id) state stream)
|
||||
(ptk/watch (du/fetch-users {:team-id id}) state stream)
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dws/message))
|
||||
(rx/map deref)
|
||||
(rx/filter (fn [{:keys [subs-id type] :as msg}]
|
||||
(and (or (= subs-id uuid/zero)
|
||||
(= subs-id profile-id))
|
||||
(= :notification type))))
|
||||
(rx/map handle-notification))
|
||||
|
||||
;; Once the teams are fecthed, initialize features related
|
||||
;; to currently active team
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::du/teams-fetched))
|
||||
(rx/observe-on :async)
|
||||
(rx/mapcat deref)
|
||||
(rx/filter #(= id (:id %)))
|
||||
(rx/map du/set-current-team)))
|
||||
|
||||
(rx/take-until stoper-s))))))
|
||||
|
||||
(defn finalize
|
||||
[params]
|
||||
|
@ -98,13 +108,12 @@
|
|||
(assoc state :dashboard-team-members (d/index-by :id members)))))
|
||||
|
||||
(defn fetch-team-members
|
||||
[]
|
||||
[team-id]
|
||||
(ptk/reify ::fetch-team-members
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-members {:team-id team-id})
|
||||
(rx/map team-members-fetched))))))
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-team-members {:team-id team-id})
|
||||
(rx/map team-members-fetched)))))
|
||||
|
||||
;; --- EVENT: fetch-team-stats
|
||||
|
||||
|
@ -116,13 +125,12 @@
|
|||
(assoc state :dashboard-team-stats stats))))
|
||||
|
||||
(defn fetch-team-stats
|
||||
[]
|
||||
[team-id]
|
||||
(ptk/reify ::fetch-team-stats
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-stats {:team-id team-id})
|
||||
(rx/map team-stats-fetched))))))
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-team-stats {:team-id team-id})
|
||||
(rx/map team-stats-fetched)))))
|
||||
|
||||
;; --- EVENT: fetch-team-invitations
|
||||
|
||||
|
@ -171,13 +179,12 @@
|
|||
(assoc state :dashboard-projects projects)))))
|
||||
|
||||
(defn fetch-projects
|
||||
[]
|
||||
[team-id]
|
||||
(ptk/reify ::fetch-projects
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-projects {:team-id team-id})
|
||||
(rx/map projects-fetched))))))
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-projects {:team-id team-id})
|
||||
(rx/map projects-fetched)))))
|
||||
|
||||
;; --- EVENT: search
|
||||
|
||||
|
@ -344,11 +351,12 @@
|
|||
(dm/assert! (string? name))
|
||||
(ptk/reify ::create-team
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [_ state _]
|
||||
(let [{:keys [on-success on-error]
|
||||
:or {on-success identity
|
||||
on-error rx/throw}} (meta params)]
|
||||
(->> (rp/cmd! :create-team {:name name})
|
||||
on-error rx/throw}} (meta params)
|
||||
features (features/get-enabled-features state)]
|
||||
(->> (rp/cmd! :create-team {:name name :features features})
|
||||
(rx/tap on-success)
|
||||
(rx/map team-created)
|
||||
(rx/catch on-error))))))
|
||||
|
@ -359,13 +367,15 @@
|
|||
[{:keys [name emails role] :as params}]
|
||||
(ptk/reify ::create-team-with-invitations
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [_ state _]
|
||||
(let [{:keys [on-success on-error]
|
||||
:or {on-success identity
|
||||
on-error rx/throw}} (meta params)
|
||||
params {:name name
|
||||
:emails #{emails}
|
||||
:role role}]
|
||||
features (features/get-enabled-features state)]
|
||||
params {:name name
|
||||
:emails #{emails}
|
||||
:role role
|
||||
:features features}
|
||||
(->> (rp/cmd! :create-team-with-invitations params)
|
||||
(rx/tap on-success)
|
||||
(rx/map team-created)
|
||||
|
@ -419,7 +429,7 @@
|
|||
params (assoc params :team-id team-id)]
|
||||
(->> (rp/cmd! :update-team-member-role params)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (fetch-team-members)
|
||||
(rx/of (fetch-team-members team-id)
|
||||
(du/fetch-teams)))))))))
|
||||
|
||||
(defn delete-team-member
|
||||
|
@ -432,7 +442,7 @@
|
|||
params (assoc params :team-id team-id)]
|
||||
(->> (rp/cmd! :delete-team-member params)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (fetch-team-members)
|
||||
(rx/of (fetch-team-members team-id)
|
||||
(du/fetch-teams)))))))))
|
||||
|
||||
(defn leave-team
|
||||
|
@ -846,9 +856,8 @@
|
|||
files (get state :dashboard-files)
|
||||
unames (cfh/get-used-names files)
|
||||
name (cfh/generate-unique-name unames (str (tr "dashboard.new-file-prefix") " 1"))
|
||||
features (cond-> #{}
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2"))
|
||||
features (-> (features/get-team-enabled-features state)
|
||||
(set/difference cfeat/frontend-only-features))
|
||||
params (-> params
|
||||
(assoc :name name)
|
||||
(assoc :features features))]
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.main.data.events :as ev]
|
||||
[app.main.data.media :as di]
|
||||
[app.main.data.websocket :as ws]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.i18n :as i18n]
|
||||
[app.util.router :as rt]
|
||||
|
@ -56,21 +57,20 @@
|
|||
|
||||
(defn teams-fetched
|
||||
[teams]
|
||||
(let [teams (d/index-by :id teams)
|
||||
ids (into #{} (keys teams))]
|
||||
(ptk/reify ::teams-fetched
|
||||
IDeref
|
||||
(-deref [_] teams)
|
||||
|
||||
(ptk/reify ::teams-fetched
|
||||
IDeref
|
||||
(-deref [_] teams)
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :teams (d/index-by :id teams)))
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :teams teams))
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
;; Check if current team-id is part of available teams
|
||||
;; if not, dissoc it from storage.
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
;; Check if current team-id is part of available teams
|
||||
;; if not, dissoc it from storage.
|
||||
(let [ids (into #{} (map :id) teams)]
|
||||
(when-let [ctid (::current-team-id @storage)]
|
||||
(when-not (contains? ids ctid)
|
||||
(swap! storage dissoc ::current-team-id)))))))
|
||||
|
@ -83,6 +83,23 @@
|
|||
(->> (rp/cmd! :get-teams)
|
||||
(rx/map teams-fetched)))))
|
||||
|
||||
(defn set-current-team
|
||||
[team]
|
||||
(ptk/reify ::set-current-team
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :team team)
|
||||
(assoc :current-team-id (:id team))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (features/initialize (:features team #{}))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(set-current-team! (:id team)))))
|
||||
|
||||
;; --- EVENT: fetch-profile
|
||||
|
||||
(declare logout)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.features :as ffeat]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.schema :as sm]
|
||||
|
@ -108,12 +107,8 @@
|
|||
(ptk/reify ::fetch-bundle
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [features (cond-> ffeat/enabled
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2")
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
|
||||
:always
|
||||
(conj "storage/pointer-map"))
|
||||
params' (cond-> {:file-id file-id :features features}
|
||||
(uuid? share-id)
|
||||
(assoc :share-id share-id))
|
||||
|
|
|
@ -9,17 +9,13 @@
|
|||
[app.common.attrs :as attrs]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.features :as ffeat]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.libraries-helpers :as cflh]
|
||||
[app.common.files.shapes-helpers :as cfsh]
|
||||
[app.common.geom.align :as gal]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.proportions :as gpp]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.grid-layout :as gslg]
|
||||
[app.common.logging :as log]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.text :as txt]
|
||||
|
@ -27,8 +23,6 @@
|
|||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
|
@ -39,7 +33,6 @@
|
|||
[app.main.data.events :as ev]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.data.workspace.bool :as dwb]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
|
@ -94,18 +87,12 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(declare ^:private workspace-initialized)
|
||||
(declare ^:private remove-graphics)
|
||||
(declare ^:private libraries-fetched)
|
||||
|
||||
;; --- Initialize Workspace
|
||||
|
||||
(defn initialize-layout
|
||||
[lname]
|
||||
;; (dm/assert!
|
||||
;; "expected valid layout"
|
||||
;; (and (keyword? lname)
|
||||
;; (contains? layout/presets lname)))
|
||||
|
||||
(ptk/reify ::initialize-layout
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -129,18 +116,10 @@
|
|||
(assoc :workspace-ready? true)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file (:workspace-data state)
|
||||
has-graphics? (-> file :media seq)
|
||||
components-v2 (features/active-feature? state :components-v2)]
|
||||
(rx/merge
|
||||
(rx/of (fbc/fix-bool-contents)
|
||||
(fdf/fix-deleted-fonts)
|
||||
(fbs/fix-broken-shapes))
|
||||
|
||||
(if (and has-graphics? components-v2)
|
||||
(rx/of (remove-graphics (:id file) (:name file)))
|
||||
(rx/empty)))))))
|
||||
(watch [_ _ _]
|
||||
(rx/of (fbc/fix-bool-contents)
|
||||
(fdf/fix-deleted-fonts)
|
||||
(fbs/fix-broken-shapes)))))
|
||||
|
||||
(defn- workspace-data-loaded
|
||||
[data]
|
||||
|
@ -171,39 +150,43 @@
|
|||
(assoc data :pages-index pages-index))))))
|
||||
|
||||
(defn- bundle-fetched
|
||||
[features [{:keys [id data] :as file} thumbnails project users comments-users]]
|
||||
[{:keys [features file thumbnails project team team-users comments-users]}]
|
||||
(ptk/reify ::bundle-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :users (d/index-by :id team-users))
|
||||
(assoc :workspace-thumbnails thumbnails)
|
||||
(assoc :workspace-file (dissoc file :data))
|
||||
(assoc :workspace-project project)
|
||||
(assoc :current-team-id (:team-id project))
|
||||
(assoc :users (d/index-by :id users))
|
||||
(assoc :current-file-comments-users (d/index-by :id comments-users))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [team-id (:team-id project)
|
||||
stoper (rx/filter (ptk/type? ::bundle-fetched) stream)]
|
||||
(let [team-id (:id team)
|
||||
file-id (:id file)
|
||||
file-data (:data file)
|
||||
stoper-s (rx/filter (ptk/type? ::bundle-fetched) stream)]
|
||||
|
||||
(->> (rx/concat
|
||||
;; Initialize notifications
|
||||
(rx/of (dwn/initialize team-id id)
|
||||
(rx/of (dwn/initialize team-id file-id)
|
||||
(dwsl/initialize))
|
||||
|
||||
;; Load team fonts. We must ensure custom fonts are
|
||||
;; fully loadad before mark workspace as initialized
|
||||
(rx/merge
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? :app.main.data.fonts/team-fonts-loaded))
|
||||
(rx/filter (ptk/type? ::df/team-fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
|
||||
(rx/of (df/load-team-fonts team-id))
|
||||
|
||||
;; FIXME: move to bundle fetch stages
|
||||
|
||||
;; Load main file
|
||||
(->> (resolve-file-data id data)
|
||||
(->> (resolve-file-data file-id file-data)
|
||||
(rx/mapcat (fn [{:keys [pages-index] :as data}]
|
||||
(->> (rx/from (seq pages-index))
|
||||
(rx/mapcat
|
||||
|
@ -217,7 +200,7 @@
|
|||
(rx/map workspace-data-loaded))
|
||||
|
||||
;; Load libraries
|
||||
(->> (rp/cmd! :get-file-libraries {:file-id id})
|
||||
(->> (rp/cmd! :get-file-libraries {:file-id file-id})
|
||||
(rx/mapcat identity)
|
||||
(rx/merge-map
|
||||
(fn [{:keys [id synced-at]}]
|
||||
|
@ -233,8 +216,10 @@
|
|||
(rx/map #(assoc file :thumbnails %)))))
|
||||
(rx/reduce conj [])
|
||||
(rx/map libraries-fetched)))
|
||||
(rx/of (with-meta (workspace-initialized) {:file-id id})))
|
||||
(rx/take-until stoper))))))
|
||||
|
||||
(rx/of (with-meta (workspace-initialized)
|
||||
{:file-id file-id})))
|
||||
(rx/take-until stoper-s))))))
|
||||
|
||||
(defn- libraries-fetched
|
||||
[libraries]
|
||||
|
@ -255,7 +240,7 @@
|
|||
(rx/concat (rx/timer 1000)
|
||||
(rx/of (dwl/notify-sync-file file-id))))))))
|
||||
|
||||
(defn- fetch-thumbnail-blob-uri
|
||||
(defn- datauri->blob-uri
|
||||
[uri]
|
||||
(->> (http/send! {:uri uri
|
||||
:response-type :blob
|
||||
|
@ -263,47 +248,86 @@
|
|||
(rx/map :body)
|
||||
(rx/map (fn [blob] (wapi/create-uri blob)))))
|
||||
|
||||
(defn- fetch-thumbnail-blobs
|
||||
(defn- fetch-file-object-thumbnails
|
||||
[file-id]
|
||||
(->> (rp/cmd! :get-file-object-thumbnails {:file-id file-id})
|
||||
(rx/mapcat (fn [thumbnails]
|
||||
(->> (rx/from thumbnails)
|
||||
(rx/mapcat (fn [[k v]]
|
||||
;; we only need to fetch the thumbnail if
|
||||
;; it is a data:uri, otherwise we can just
|
||||
;; use the value as is.
|
||||
(if (.startsWith v "data:")
|
||||
(->> (fetch-thumbnail-blob-uri v)
|
||||
(rx/map (fn [uri] [k uri])))
|
||||
(rx/of [k v])))))))
|
||||
(->> (rx/from thumbnails)
|
||||
(rx/mapcat (fn [[k v]]
|
||||
;; we only need to fetch the thumbnail if
|
||||
;; it is a data:uri, otherwise we can just
|
||||
;; use the value as is.
|
||||
(if (str/starts-with? v "data:")
|
||||
(->> (datauri->blob-uri v)
|
||||
(rx/map (fn [uri] [k uri])))
|
||||
(rx/of [k v])))))))
|
||||
(rx/reduce conj {})))
|
||||
|
||||
(defn- fetch-bundle
|
||||
(defn- fetch-bundle-stage-1
|
||||
[project-id file-id]
|
||||
(ptk/reify ::fetch-bundle
|
||||
(ptk/reify ::fetch-bundle-stage-1
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(->> (rp/cmd! :get-project {:id project-id})
|
||||
(rx/mapcat (fn [project]
|
||||
(->> (rp/cmd! :get-team {:id (:team-id project)})
|
||||
(rx/mapcat (fn [team]
|
||||
(let [bundle {:team team
|
||||
:project project
|
||||
:file-id file-id
|
||||
:project-id project-id}]
|
||||
(rx/of (du/set-current-team team)
|
||||
(ptk/data-event ::bundle-stage-1 bundle))))))))
|
||||
(rx/take-until
|
||||
(rx/filter (ptk/type? ::fetch-bundle) stream))))))
|
||||
|
||||
(defn- fetch-bundle-stage-2
|
||||
[{:keys [file-id project-id] :as bundle}]
|
||||
(ptk/reify ::fetch-bundle-stage-2
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [features (cond-> ffeat/enabled
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2")
|
||||
|
||||
;; We still put the feature here and not in the
|
||||
;; ffeat/enabled var because the pointers map is only
|
||||
;; supported on workspace bundle fetching mechanism.
|
||||
:always
|
||||
(conj "storage/pointer-map"))
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
|
||||
;; WTF is this?
|
||||
share-id (-> state :viewer-local :share-id)
|
||||
stoper (rx/filter (ptk/type? ::fetch-bundle) stream)]
|
||||
share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features :project-id project-id})
|
||||
(fetch-thumbnail-blobs file-id)
|
||||
(rp/cmd! :get-project {:id project-id})
|
||||
(fetch-file-object-thumbnails file-id)
|
||||
(rp/cmd! :get-team-users {:file-id file-id})
|
||||
(rp/cmd! :get-profiles-for-file-comments {:file-id file-id :share-id share-id}))
|
||||
(rx/take 1)
|
||||
(rx/map (partial bundle-fetched features))
|
||||
(rx/take-until stoper))))))
|
||||
(rx/map (fn [[file thumbnails team-users comments-users]]
|
||||
(let [bundle (-> bundle
|
||||
(assoc :file file)
|
||||
(assoc :thumbnails thumbnails)
|
||||
(assoc :team-users team-users)
|
||||
(assoc :comments-users comments-users))]
|
||||
(ptk/data-event ::bundle-stage-2 bundle))))
|
||||
(rx/take-until
|
||||
(rx/filter (ptk/type? ::fetch-bundle) stream)))))))
|
||||
|
||||
(defn- fetch-bundle
|
||||
"Multi-stage file bundle fetch coordinator"
|
||||
[project-id file-id]
|
||||
(ptk/reify ::fetch-bundle
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(->> (rx/merge
|
||||
(rx/of (fetch-bundle-stage-1 project-id file-id))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-stage-1))
|
||||
(rx/observe-on :async)
|
||||
(rx/map deref)
|
||||
(rx/map fetch-bundle-stage-2))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-stage-2))
|
||||
(rx/observe-on :async)
|
||||
(rx/map deref)
|
||||
(rx/map bundle-fetched)))
|
||||
|
||||
(rx/take-until
|
||||
(rx/filter (ptk/type? ::fetch-bundle) stream))))))
|
||||
|
||||
(defn initialize-file
|
||||
[project-id file-id]
|
||||
|
@ -322,7 +346,6 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of msg/hide
|
||||
(features/initialize)
|
||||
(dcm/retrieve-comment-threads file-id)
|
||||
(dwp/initialize-file-persistence file-id)
|
||||
(fetch-bundle project-id file-id)))
|
||||
|
@ -548,7 +571,7 @@
|
|||
(ptk/reify ::delete-page
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [components-v2 (features/active-feature? state :components-v2)
|
||||
(let [components-v2 (features/active-feature? state "components/v2")
|
||||
file-id (:current-file-id state)
|
||||
file (wsh/get-file state file-id)
|
||||
pages (get-in state [:workspace-data :pages])
|
||||
|
@ -1326,7 +1349,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [components-v2 (features/active-feature? state :components-v2)]
|
||||
(let [components-v2 (features/active-feature? state "components/v2")]
|
||||
(if components-v2
|
||||
(rx/of (go-to-main-instance nil component-id))
|
||||
(let [project-id (get-in state [:workspace-project :id])
|
||||
|
@ -1341,7 +1364,7 @@
|
|||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [components-v2 (features/active-feature? state :components-v2)
|
||||
(let [components-v2 (features/active-feature? state "components/v2")
|
||||
wrapper-id (str "component-shape-id-" component-id)]
|
||||
(when-not components-v2
|
||||
(tm/schedule-on-idle #(dom/scroll-into-view-if-needed! (dom/get-element wrapper-id))))))))
|
||||
|
@ -2007,143 +2030,6 @@
|
|||
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Remove graphics
|
||||
;; TODO: this should be deprecated and removed together with components-v2
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- initialize-remove-graphics
|
||||
[total]
|
||||
(ptk/reify ::initialize-remove-graphics
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :remove-graphics {:total total
|
||||
:current nil
|
||||
:error false
|
||||
:completed false}))))
|
||||
|
||||
(defn- update-remove-graphics
|
||||
[current]
|
||||
(ptk/reify ::update-remove-graphics
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:remove-graphics :current] current))))
|
||||
|
||||
(defn- error-in-remove-graphics
|
||||
[]
|
||||
(ptk/reify ::error-in-remove-graphics
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:remove-graphics :error] true))))
|
||||
|
||||
(defn clear-remove-graphics
|
||||
[]
|
||||
(ptk/reify ::clear-remove-graphics
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(dissoc state :remove-graphics))))
|
||||
|
||||
(defn- complete-remove-graphics
|
||||
[]
|
||||
(ptk/reify ::complete-remove-graphics
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:remove-graphics :completed] true))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-not (get-in state [:remove-graphics :error])
|
||||
(rx/of (modal/hide))))))
|
||||
|
||||
(defn- remove-graphic
|
||||
[it file-data page [index [media-obj pos]]]
|
||||
(let [process-shapes
|
||||
(fn [[shape children]]
|
||||
(let [changes1 (-> (pcb/empty-changes it)
|
||||
(pcb/set-save-undo? false)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page))
|
||||
(pcb/with-library-data file-data)
|
||||
(pcb/delete-media (:id media-obj))
|
||||
(pcb/add-objects (cons shape children)))
|
||||
|
||||
page' (reduce (fn [page shape]
|
||||
(ctst/add-shape (:id shape)
|
||||
shape
|
||||
page
|
||||
uuid/zero
|
||||
uuid/zero
|
||||
nil
|
||||
true))
|
||||
page
|
||||
(cons shape children))
|
||||
|
||||
[_ _ changes2] (cflh/generate-add-component it
|
||||
[shape]
|
||||
(:objects page')
|
||||
(:id page)
|
||||
(:id file-data)
|
||||
true
|
||||
nil
|
||||
cfsh/prepare-create-artboard-from-selection)
|
||||
|
||||
changes (pcb/concat-changes changes1 changes2)]
|
||||
|
||||
(dch/commit-changes changes)))
|
||||
|
||||
shapes (if (= (:mtype media-obj) "image/svg+xml")
|
||||
(->> (dwm/load-and-parse-svg media-obj)
|
||||
(rx/mapcat (partial dwm/create-shapes-svg (:id file-data) (:objects page) pos)))
|
||||
(dwm/create-shapes-img pos media-obj :wrapper-type :frame))]
|
||||
|
||||
(->> (rx/concat
|
||||
(rx/of (update-remove-graphics index))
|
||||
(rx/map process-shapes shapes))
|
||||
(rx/catch #(do
|
||||
(log/error :msg (str "Error removing " (:name media-obj))
|
||||
:hint (ex-message %)
|
||||
:error %)
|
||||
(js/console.log (.-stack %))
|
||||
(rx/of (error-in-remove-graphics)))))))
|
||||
|
||||
(defn- remove-graphics
|
||||
[file-id file-name]
|
||||
(ptk/reify ::remove-graphics
|
||||
ptk/WatchEvent
|
||||
(watch [it state stream]
|
||||
(let [file-data (wsh/get-file state file-id)
|
||||
|
||||
grid-gap 50
|
||||
|
||||
[file-data' page-id start-pos]
|
||||
(ctf/get-or-add-library-page file-data grid-gap)
|
||||
|
||||
new-page? (nil? (ctpl/get-page file-data page-id))
|
||||
page (ctpl/get-page file-data' page-id)
|
||||
media (vals (:media file-data'))
|
||||
|
||||
media-points
|
||||
(map #(assoc % :points (-> (grc/make-rect 0 0 (:width %) (:height %))
|
||||
(grc/rect->points)))
|
||||
media)
|
||||
|
||||
shape-grid
|
||||
(ctst/generate-shape-grid media-points start-pos grid-gap)
|
||||
|
||||
stoper (rx/filter (ptk/type? ::finalize-file) stream)]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (modal/show {:type :remove-graphics-dialog :file-name file-name})
|
||||
(initialize-remove-graphics (count media)))
|
||||
(when new-page?
|
||||
(rx/of (dch/commit-changes (-> (pcb/empty-changes it)
|
||||
(pcb/set-save-undo? false)
|
||||
(pcb/add-page (:id page) page)))))
|
||||
(->> (rx/mapcat (partial remove-graphic it file-data' page)
|
||||
(rx/from (d/enumerate (d/zip media shape-grid))))
|
||||
(rx/take-until stoper))
|
||||
(rx/of (complete-remove-graphics)))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Read only
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.features :as ffeat]
|
||||
[app.common.files.libraries-helpers :as cflh]
|
||||
[app.common.files.shapes-helpers :as cfsh]
|
||||
[app.common.geom.point :as gpt]
|
||||
|
@ -328,7 +327,7 @@
|
|||
selected (->> (wsh/lookup-selected state)
|
||||
(cph/clean-loops objects)
|
||||
(remove #(ctn/has-any-copy-parent? objects (get objects %)))) ;; We don't want to change the structure of component copies
|
||||
components-v2 (features/active-feature? state :components-v2)]
|
||||
components-v2 (features/active-feature? state "components/v2")]
|
||||
(rx/of (add-component2 selected components-v2))))))
|
||||
|
||||
(defn add-multiple-components
|
||||
|
@ -337,7 +336,7 @@
|
|||
(ptk/reify ::add-multiple-components
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [components-v2 (features/active-feature? state :components-v2)
|
||||
(let [components-v2 (features/active-feature? state "components/v2")
|
||||
objects (wsh/lookup-page-objects state)
|
||||
selected (->> (wsh/lookup-selected state)
|
||||
(cph/clean-loops objects)
|
||||
|
@ -364,7 +363,7 @@
|
|||
(rx/empty)
|
||||
(let [data (get state :workspace-data)
|
||||
[path name] (cph/parse-path-name new-name)
|
||||
components-v2 (features/active-feature? state :components-v2)
|
||||
components-v2 (features/active-feature? state "components/v2")
|
||||
|
||||
update-fn
|
||||
(fn [component]
|
||||
|
@ -411,7 +410,7 @@
|
|||
component (ctkl/get-component (:data library) component-id)
|
||||
new-name (:name component)
|
||||
|
||||
components-v2 (features/active-feature? state :components-v2)
|
||||
components-v2 (features/active-feature? state "components/v2")
|
||||
|
||||
main-instance-page (when components-v2
|
||||
(ctf/get-component-page (:data library) component))
|
||||
|
@ -447,7 +446,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (get state :workspace-data)]
|
||||
(if (features/active-feature? state :components-v2)
|
||||
(if (features/active-feature? state "components/v2")
|
||||
(let [component (ctkl/get-component data id)
|
||||
page-id (:main-instance-page component)
|
||||
root-id (:main-instance-id component)]
|
||||
|
@ -639,7 +638,7 @@
|
|||
container (cph/get-container file :page page-id)
|
||||
|
||||
components-v2
|
||||
(features/active-feature? state :components-v2)
|
||||
(features/active-feature? state "components/v2")
|
||||
|
||||
changes
|
||||
(-> (pcb/empty-changes it)
|
||||
|
@ -686,7 +685,7 @@
|
|||
local-file (wsh/get-local-file state)
|
||||
container (cph/get-container local-file :page page-id)
|
||||
shape (ctn/get-shape container id)
|
||||
components-v2 (features/active-feature? state :components-v2)]
|
||||
components-v2 (features/active-feature? state "components/v2")]
|
||||
|
||||
(when (ctk/instance-head? shape)
|
||||
(let [libraries (wsh/get-libraries state)
|
||||
|
@ -1016,7 +1015,7 @@
|
|||
(ptk/reify ::watch-component-changes
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [components-v2? (features/active-feature? state :components-v2)
|
||||
(let [components-v2? (features/active-feature? state "components/v2")
|
||||
|
||||
stopper-s
|
||||
(->> stream
|
||||
|
@ -1138,9 +1137,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [features (cond-> ffeat/enabled
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2"))]
|
||||
(let [features (features/get-team-enabled-features state)]
|
||||
(rx/merge
|
||||
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
||||
(rx/ignore))
|
||||
|
|
|
@ -139,19 +139,15 @@
|
|||
(ptk/reify ::persist-changes
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [;; this features set does not includes the ffeat/enabled
|
||||
;; because they are already available on the backend and
|
||||
;; this request provides a set of features to enable in
|
||||
;; this request.
|
||||
features (cond-> #{}
|
||||
(features/active-feature? state :components-v2)
|
||||
(conj "components/v2"))
|
||||
sid (:session-id state)
|
||||
(let [sid (:session-id state)
|
||||
|
||||
features (features/get-team-enabled-features state)
|
||||
params {:id file-id
|
||||
:revn file-revn
|
||||
:session-id sid
|
||||
:changes-with-metadata (into [] changes)
|
||||
:features features}]
|
||||
:features features
|
||||
}]
|
||||
|
||||
(->> (rp/cmd! :update-file params)
|
||||
(rx/mapcat (fn [lagged]
|
||||
|
@ -209,7 +205,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [features (cond-> #{}
|
||||
(features/active-feature? state :components-v2)
|
||||
(features/active-feature? state "components/v2")
|
||||
(conj "components/v2"))
|
||||
sid (:session-id state)
|
||||
file (dm/get-in state [:workspace-libraries file-id])
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
page (wsh/lookup-page state page-id)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
|
||||
components-v2 (features/active-feature? state :components-v2)
|
||||
components-v2 (features/active-feature? state "components/v2")
|
||||
|
||||
ids (cph/clean-loops objects ids)
|
||||
|
||||
|
|
|
@ -23,37 +23,41 @@
|
|||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn extract-name [url]
|
||||
(let [query-idx (str/last-index-of url "?")
|
||||
url (if (> query-idx 0) (subs url 0 query-idx) url)
|
||||
filename (->> (str/split url "/") (last))
|
||||
(defn extract-name [href]
|
||||
(let [query-idx (str/last-index-of href "?")
|
||||
href (if (> query-idx 0) (subs href 0 query-idx) href)
|
||||
filename (->> (str/split href "/") (last))
|
||||
ext-idx (str/last-index-of filename ".")]
|
||||
(if (> ext-idx 0) (subs filename 0 ext-idx) filename)))
|
||||
|
||||
(defn upload-images
|
||||
"Extract all bitmap images inside the svg data, and upload them, associated to the file.
|
||||
Return a map {<url> <image-data>}."
|
||||
Return a map {<href> <image-data>}."
|
||||
[svg-data file-id]
|
||||
(->> (rx/from (csvg/collect-images svg-data))
|
||||
(rx/map (fn [uri]
|
||||
(merge
|
||||
{:file-id file-id
|
||||
:is-local true
|
||||
:url uri}
|
||||
(if (str/starts-with? uri "data:")
|
||||
{:name "image"
|
||||
:content (wapi/data-uri->blob uri)}
|
||||
{:name (extract-name uri)}))))
|
||||
(rx/mapcat (fn [uri-data]
|
||||
(->> (rp/cmd! (if (contains? uri-data :content)
|
||||
(rx/map (fn [{:keys [href] :as item}]
|
||||
(let [item (-> item
|
||||
(assoc :file-id file-id)
|
||||
(assoc :is-local true)
|
||||
(assoc :name "image"))]
|
||||
(if (str/starts-with? href "data:")
|
||||
(assoc item :content (wapi/data-uri->blob href))
|
||||
(-> item
|
||||
(assoc :name (extract-name href))
|
||||
(assoc :url href))))))
|
||||
(rx/mapcat (fn [item]
|
||||
;; TODO: :create-file-media-object-from-url is
|
||||
;; deprecated and this should be resolved in
|
||||
;; frontend
|
||||
(->> (rp/cmd! (if (contains? item :content)
|
||||
:upload-file-media-object
|
||||
:create-file-media-object-from-url)
|
||||
uri-data)
|
||||
(dissoc item :href))
|
||||
;; When the image uploaded fail we skip the shape
|
||||
;; returning `nil` will afterward not create the shape.
|
||||
(rx/catch #(rx/of nil))
|
||||
(rx/map #(vector (:url uri-data) %)))))
|
||||
(rx/reduce (fn [acc [url image]] (assoc acc url image)) {})))
|
||||
(rx/map #(vector (:href item) %)))))
|
||||
(rx/reduce conj {})))
|
||||
|
||||
(defn add-svg-shapes
|
||||
[svg-data position]
|
||||
|
|
|
@ -165,6 +165,25 @@
|
|||
(defmethod ptk/handle-error :restriction
|
||||
[{:keys [code] :as error}]
|
||||
(cond
|
||||
(= :migration-in-progress code)
|
||||
(let [message (tr "errors.migration-in-progress" (:feature error))
|
||||
on-accept (constantly nil)]
|
||||
(st/emit! (modal/show {:type :alert :message message :on-accept on-accept})))
|
||||
|
||||
(= :team-feature-mismatch code)
|
||||
(let [message (tr "errors.team-feature-mismatch" (:feature error))
|
||||
on-accept (constantly nil)]
|
||||
(st/emit! (modal/show {:type :alert :message message :on-accept on-accept})))
|
||||
|
||||
(= :file-feature-mismatch code)
|
||||
(let [message (tr "errors.file-feature-mismatch" (:feature error))
|
||||
team-id (:current-team-id @st/state)
|
||||
project-id (:current-project-id @st/state)
|
||||
on-accept #(if (and project-id team-id)
|
||||
(st/emit! (rt/nav :dashboard-files {:team-id team-id :project-id project-id}))
|
||||
(set! (.-href glob/location) ""))]
|
||||
(st/emit! (modal/show {:type :alert :message message :on-accept on-accept})))
|
||||
|
||||
(= :feature-mismatch code)
|
||||
(let [message (tr "errors.feature-mismatch" (:feature error))
|
||||
team-id (:current-team-id @st/state)
|
||||
|
@ -174,7 +193,7 @@
|
|||
(set! (.-href glob/location) ""))]
|
||||
(st/emit! (modal/show {:type :alert :message message :on-accept on-accept})))
|
||||
|
||||
(= :features-not-supported code)
|
||||
(= :feature-not-supported code)
|
||||
(let [message (tr "errors.feature-not-supported" (:feature error))
|
||||
team-id (:current-team-id @st/state)
|
||||
project-id (:current-project-id @st/state)
|
||||
|
|
|
@ -5,103 +5,116 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.features
|
||||
"A thin, frontend centric abstraction layer and collection of
|
||||
helpers for `app.common.features` namespace."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.logging :as log]
|
||||
[app.config :as cf]
|
||||
[app.main.store :as st]
|
||||
[app.util.timers :as tm]
|
||||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(log/set-level! :warn)
|
||||
(log/set-level! :trace)
|
||||
|
||||
(def available-features
|
||||
#{:components-v2 :new-css-system :grid-layout})
|
||||
(def global-enabled-features
|
||||
(cfeat/get-enabled-features cf/flags))
|
||||
|
||||
(defn- toggle-feature
|
||||
(defn get-enabled-features
|
||||
[state]
|
||||
(-> (get state :features/runtime #{})
|
||||
(set/union global-enabled-features)))
|
||||
|
||||
(defn get-team-enabled-features
|
||||
[state]
|
||||
(-> global-enabled-features
|
||||
(set/union (get state :features/runtime #{}))
|
||||
(set/intersection cfeat/no-migration-features)
|
||||
(set/union (get state :features/team #{}))))
|
||||
|
||||
(def features-ref
|
||||
(l/derived get-team-enabled-features st/state =))
|
||||
|
||||
(defn active-feature?
|
||||
"Given a state and feature, check if feature is enabled"
|
||||
[state feature]
|
||||
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
||||
(or (contains? (get state :features/runtime) feature)
|
||||
(if (contains? cfeat/no-migration-features feature)
|
||||
(or (contains? global-enabled-features feature)
|
||||
(contains? (get state :features/team) feature))
|
||||
(contains? (get state :features/team state) feature))))
|
||||
|
||||
(defn use-feature
|
||||
"A react hook that checks if feature is currently enabled"
|
||||
[feature]
|
||||
(assert (contains? cfeat/supported-features feature) "Not supported feature")
|
||||
(let [enabled-features (mf/deref features-ref)]
|
||||
(contains? enabled-features feature)))
|
||||
|
||||
(defn toggle-feature
|
||||
"An event constructor for runtime feature toggle.
|
||||
|
||||
Warning: if a feature is active globally or by team, it can't be
|
||||
disabled."
|
||||
[feature]
|
||||
(ptk/reify ::toggle-feature
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [features (or (:features state) #{})]
|
||||
(if (contains? features feature)
|
||||
(do
|
||||
(log/debug :hint "feature disabled" :feature (d/name feature))
|
||||
(assoc state :features (disj features feature)))
|
||||
(do
|
||||
(log/debug :hint "feature enabled" :feature (d/name feature))
|
||||
(assoc state :features (conj features feature))))))))
|
||||
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
||||
(update state :features/runtime (fn [features]
|
||||
(if (contains? features feature)
|
||||
(do
|
||||
(log/trc :hint "feature disabled" :feature feature)
|
||||
(disj features feature))
|
||||
(do
|
||||
(log/trc :hint "feature enabled" :feature feature)
|
||||
(conj features feature))))))))
|
||||
|
||||
(defn- enable-feature
|
||||
(defn enable-feature
|
||||
[feature]
|
||||
(ptk/reify ::enable-feature
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [features (or (:features state) #{})]
|
||||
(if (contains? features feature)
|
||||
state
|
||||
(do
|
||||
(log/debug :hint "feature enabled" :feature (d/name feature))
|
||||
(assoc state :features (conj features feature))))))))
|
||||
|
||||
(defn toggle-feature!
|
||||
[feature]
|
||||
(assert (contains? available-features feature) "Not supported feature")
|
||||
(tm/schedule-on-idle #(st/emit! (toggle-feature feature))))
|
||||
|
||||
(defn enable-feature!
|
||||
[feature]
|
||||
(assert (contains? available-features feature) "Not supported feature")
|
||||
(tm/schedule-on-idle #(st/emit! (enable-feature feature))))
|
||||
|
||||
(defn active-feature?
|
||||
([feature]
|
||||
(active-feature? @st/state feature))
|
||||
([state feature]
|
||||
(assert (contains? available-features feature) "Not supported feature")
|
||||
(contains? (get state :features) feature)))
|
||||
|
||||
(def features
|
||||
(l/derived :features st/state))
|
||||
|
||||
(defn active-feature
|
||||
[feature]
|
||||
(l/derived #(contains? % feature) features))
|
||||
|
||||
(defn use-feature
|
||||
[feature]
|
||||
(assert (contains? available-features feature) "Not supported feature")
|
||||
(let [active-feature-ref (mf/use-memo (mf/deps feature) #(active-feature feature))
|
||||
active-feature? (mf/deref active-feature-ref)]
|
||||
active-feature?))
|
||||
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
||||
(if (active-feature? state feature)
|
||||
state
|
||||
(do
|
||||
(log/trc :hint "feature enabled" :feature feature)
|
||||
(update state :features/runtime (fnil conj #{}) feature))))))
|
||||
|
||||
(defn initialize
|
||||
[]
|
||||
(ptk/reify ::initialize
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(log/trace :hint "event:initialize" :fn "features")
|
||||
(rx/concat
|
||||
;; Enable all features set on the configuration
|
||||
(->> (rx/from cf/flags)
|
||||
(rx/map name)
|
||||
(rx/map (fn [flag]
|
||||
(when (str/starts-with? flag "frontend-feature-")
|
||||
(subs flag 17))))
|
||||
(rx/filter some?)
|
||||
(rx/map keyword)
|
||||
(rx/map enable-feature))
|
||||
([] (initialize #{}))
|
||||
([team-features]
|
||||
(assert (set? team-features) "expected a set of features")
|
||||
(assert (every? string? team-features) "expected a set of strings")
|
||||
|
||||
(ptk/reify ::initialize
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [runtime-features (get state :features/runtime #{})
|
||||
team-features (into cfeat/default-enabled-features
|
||||
cfeat/xf-supported-features
|
||||
team-features)]
|
||||
(-> state
|
||||
(assoc :features/runtime runtime-features)
|
||||
(assoc :features/team team-features))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(when *assert*
|
||||
(->> (rx/from cfeat/no-migration-features)
|
||||
(rx/filter #(not (contains? cfeat/backend-only-features %)))
|
||||
(rx/observe-on :async)
|
||||
(rx/map enable-feature))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(log/trc :hint "initialized features"
|
||||
:team (str/join "," (:features/team state))
|
||||
:runtime (str/join "," (:features/runtime state)))))))
|
||||
|
||||
;; Enable the rest of available configuration if we are on development
|
||||
;; environemnt (aka devenv).
|
||||
(when *assert*
|
||||
;; By default, all features disabled, except in development
|
||||
;; environment, that are enabled except components-v2 and new css
|
||||
(->> (rx/from available-features)
|
||||
(rx/filter #(not= % :components-v2))
|
||||
(rx/filter #(not= % :new-css-system))
|
||||
(rx/map enable-feature)))))))
|
||||
|
|
|
@ -425,10 +425,6 @@
|
|||
ids)))
|
||||
st/state =))
|
||||
|
||||
;; Remove this when deprecating components-v2
|
||||
(def remove-graphics
|
||||
(l/derived :remove-graphics st/state))
|
||||
|
||||
;; ---- Viewer refs
|
||||
|
||||
(defn lookup-viewer-objects-by-id
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
{::mf/wrap [#(mf/catch % {:fallback on-main-error})]}
|
||||
[{:keys [route profile]}]
|
||||
(let [{:keys [data params]} route
|
||||
new-css-system (features/use-feature :new-css-system)]
|
||||
new-css-system (features/use-feature "styles/v2")]
|
||||
[:& (mf/provider ctx/current-route) {:value route}
|
||||
[:& (mf/provider ctx/new-css-system) {:value new-css-system}
|
||||
(case (:name data)
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
(mf/with-effect [profile team-id]
|
||||
(st/emit! (dd/initialize {:id team-id}))
|
||||
(fn []
|
||||
(dd/finalize {:id team-id})))
|
||||
(st/emit! (dd/finalize {:id team-id}))))
|
||||
|
||||
(mf/with-effect []
|
||||
(let [key (events/listen goog/global "keydown"
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
::mf/register-as :export
|
||||
::mf/wrap-props false}
|
||||
[{:keys [team-id files has-libraries? binary?]}]
|
||||
(let [components-v2 (features/use-feature :components-v2)
|
||||
(let [components-v2 (features/use-feature "components/v2")
|
||||
state* (mf/use-state
|
||||
#(let [files (mapv (fn [file] (assoc file :loading? true)) files)]
|
||||
{:status :prepare
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.dashboard.grid
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.features :as ffeat]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.logging :as log]
|
||||
[app.main.data.dashboard :as dd]
|
||||
|
@ -51,22 +50,18 @@
|
|||
(defn- ask-for-thumbnail
|
||||
"Creates some hooks to handle the files thumbnails cache"
|
||||
[file-id revn]
|
||||
(let [features (cond-> ffeat/enabled
|
||||
(features/active-feature? :components-v2)
|
||||
(conj "components/v2"))]
|
||||
|
||||
(->> (wrk/ask! {:cmd :thumbnails/generate-for-file
|
||||
:revn revn
|
||||
:file-id file-id
|
||||
:features features})
|
||||
(rx/mapcat (fn [{:keys [fonts] :as result}]
|
||||
(->> (fonts/render-font-styles fonts)
|
||||
(rx/map (fn [styles]
|
||||
(assoc result
|
||||
:styles styles
|
||||
:width 250))))))
|
||||
(rx/mapcat thr/render)
|
||||
(rx/mapcat (partial persist-thumbnail file-id revn)))))
|
||||
(->> (wrk/ask! {:cmd :thumbnails/generate-for-file
|
||||
:revn revn
|
||||
:file-id file-id
|
||||
:features (features/get-team-enabled-features @st/state)})
|
||||
(rx/mapcat (fn [{:keys [fonts] :as result}]
|
||||
(->> (fonts/render-font-styles fonts)
|
||||
(rx/map (fn [styles]
|
||||
(assoc result
|
||||
:styles styles
|
||||
:width 250))))))
|
||||
(rx/mapcat thr/render)
|
||||
(rx/mapcat (partial persist-thumbnail file-id revn))))
|
||||
|
||||
(mf/defc grid-item-thumbnail
|
||||
{::mf/wrap-props false}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
(sort-by :modified-at)
|
||||
(reverse))))
|
||||
|
||||
components-v2 (features/use-feature :components-v2)
|
||||
components-v2 (features/use-feature "components/v2")
|
||||
|
||||
width (mf/use-state nil)
|
||||
rowref (mf/use-ref)
|
||||
|
|
|
@ -255,7 +255,7 @@
|
|||
(fn []
|
||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||
(dd/fetch-recent-files (:id team))
|
||||
(dd/fetch-projects)
|
||||
(dd/fetch-projects (:id team))
|
||||
(dd/clear-selected-files))))]
|
||||
|
||||
(mf/with-effect
|
||||
|
|
|
@ -336,7 +336,7 @@
|
|||
|
||||
on-leave-as-owner-clicked
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-team-members)
|
||||
(st/emit! (dd/fetch-team-members (:id team))
|
||||
(modal/show
|
||||
{:type :leave-and-reassign
|
||||
:profile profile
|
||||
|
|
|
@ -355,7 +355,7 @@
|
|||
(mf/use-fn
|
||||
(mf/deps profile team on-leave-accepted)
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-team-members)
|
||||
(st/emit! (dd/fetch-team-members (:id team))
|
||||
(modal/show
|
||||
{:type :leave-and-reassign
|
||||
:profile profile
|
||||
|
@ -452,8 +452,8 @@
|
|||
(tr "dashboard.your-penpot")
|
||||
(:name team)))))
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dd/fetch-team-members)))
|
||||
(mf/with-effect [team]
|
||||
(st/emit! (dd/fetch-team-members (:id team))))
|
||||
|
||||
[:*
|
||||
[:& header {:section :dashboard-team-members :team team}]
|
||||
|
@ -992,9 +992,10 @@
|
|||
(:name team)))))
|
||||
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dd/fetch-team-members)
|
||||
(dd/fetch-team-stats)))
|
||||
(mf/with-effect [team]
|
||||
(let [team-id (:id team)]
|
||||
(st/emit! (dd/fetch-team-members team-id)
|
||||
(dd/fetch-team-stats team-id))))
|
||||
|
||||
[:*
|
||||
[:& header {:section :dashboard-team-settings :team team}]
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
{::mf/wrap-props false}
|
||||
[]
|
||||
(let [modal (mf/deref modal-ref)
|
||||
new-css-system (features/use-feature :new-css-system)]
|
||||
new-css-system (features/use-feature "styles/v2")]
|
||||
(when modal
|
||||
[:& (mf/provider ctx/new-css-system) {:value new-css-system}
|
||||
[:& modal-wrapper {:data modal
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
(update profile :lang #(or % "")))
|
||||
form (fm/use-form :spec ::options-form
|
||||
:initial initial)
|
||||
new-css-system (features/use-feature :new-css-system)]
|
||||
new-css-system (features/use-feature "styles/v2")]
|
||||
|
||||
[:& fm/form {:class "options-form"
|
||||
:on-submit on-submit
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[goog.events :as events]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -177,8 +176,8 @@
|
|||
(make-file-ready-ref file-id))
|
||||
file-ready? (mf/deref file-ready*)
|
||||
|
||||
components-v2? (features/use-feature :components-v2)
|
||||
new-css-system (features/use-feature :new-css-system)
|
||||
components-v2? (features/use-feature "components/v2")
|
||||
new-css-system (features/use-feature "styles/v2")
|
||||
|
||||
background-color (:background-color wglobal)]
|
||||
|
||||
|
@ -236,49 +235,3 @@
|
|||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
[:& workspace-loader])])]]]]]]]))
|
||||
|
||||
(mf/defc remove-graphics-dialog
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :remove-graphics-dialog}
|
||||
[{:keys [] :as ctx}]
|
||||
(let [remove-state (mf/deref refs/remove-graphics)
|
||||
project (mf/deref refs/workspace-project)
|
||||
close #(modal/hide!)
|
||||
reload-file #(dom/reload-current-window)
|
||||
nav-out #(st/emit! (rt/navigate :dashboard-files
|
||||
{:team-id (:team-id project)
|
||||
:project-id (:id project)}))]
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
#(st/emit! (dw/clear-remove-graphics))))
|
||||
|
||||
[:div.modal-overlay
|
||||
[:div.modal-container.remove-graphics-dialog
|
||||
[:div.modal-header
|
||||
[:div.modal-header-title
|
||||
[:h2 (tr "workspace.remove-graphics.title" (:file-name ctx))]]
|
||||
(if (and (:completed remove-state) (:error remove-state))
|
||||
[:div.modal-close-button
|
||||
{:on-click close} i/close]
|
||||
[:div.modal-close-button
|
||||
{:on-click nav-out}
|
||||
i/close])]
|
||||
(if-not (and (:completed remove-state) (:error remove-state))
|
||||
[:div.modal-content
|
||||
[:p (tr "workspace.remove-graphics.text1")]
|
||||
[:p (tr "workspace.remove-graphics.text2")]
|
||||
[:p.progress-message (tr "workspace.remove-graphics.progress"
|
||||
(:current remove-state)
|
||||
(:total remove-state))]]
|
||||
[:*
|
||||
[:div.modal-content
|
||||
[:p.error-message [:span i/close] (tr "workspace.remove-graphics.error-msg")]
|
||||
[:p (tr "workspace.remove-graphics.error-hint")]]
|
||||
[:div.modal-footer
|
||||
[:div.action-buttons
|
||||
[:input.button-secondary {:type "button"
|
||||
:value (tr "labels.close")
|
||||
:on-click close}]
|
||||
[:input.button-primary {:type "button"
|
||||
:value (tr "labels.reload-file")
|
||||
:on-click reload-file}]]]])]]))
|
||||
|
|
|
@ -443,7 +443,7 @@
|
|||
|
||||
(mf/defc context-menu-component
|
||||
[{:keys [shapes]}]
|
||||
(let [components-v2 (features/use-feature :components-v2)
|
||||
(let [components-v2 (features/use-feature "components/v2")
|
||||
single? (= (count shapes) 1)
|
||||
objects (deref refs/workspace-page-objects)
|
||||
any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes))
|
||||
|
|
|
@ -665,7 +665,7 @@
|
|||
{::mf/register modal/components
|
||||
::mf/register-as :libraries-dialog}
|
||||
[{:keys [starting-tab] :as props :or {starting-tab :libraries}}]
|
||||
(let [new-css-system (features/use-feature :new-css-system)
|
||||
(let [new-css-system (features/use-feature "styles/v2")
|
||||
project (mf/deref refs/workspace-project)
|
||||
file-data (mf/deref refs/workspace-data)
|
||||
file (mf/deref ref:workspace-file)
|
||||
|
|
|
@ -1207,6 +1207,8 @@
|
|||
grid-justify-content-row (:layout-justify-content values)
|
||||
grid-justify-content-column (:layout-align-content values)
|
||||
|
||||
grid-enabled? (features/use-feature "layout/grid")
|
||||
|
||||
set-justify-grid
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
|
@ -1225,7 +1227,7 @@
|
|||
:class (stl/css-case :title-spacing-layout (not has-layout?))}
|
||||
(if (and (not multiple) (:layout values))
|
||||
[:div {:class (stl/css :title-actions)}
|
||||
(when (features/active-feature? :grid-layout)
|
||||
(when ^boolean grid-enabled?
|
||||
[:div {:class (stl/css :layout-options)}
|
||||
[:& radio-buttons {:selected (d/name layout-type)
|
||||
:on-change toggle-layout-style
|
||||
|
@ -1317,7 +1319,7 @@
|
|||
[:*
|
||||
[:span "Layout"]
|
||||
|
||||
(if (features/active-feature? :grid-layout)
|
||||
(if ^boolean grid-enabled?
|
||||
[:div.title-actions
|
||||
[:div.layout-btns
|
||||
[:button {:on-click set-flex
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
|
||||
(mf/defc object-svg
|
||||
[{:keys [page-id file-id share-id object-id render-embed?]}]
|
||||
(let [components-v2 (feat/use-feature :components-v2)
|
||||
(let [components-v2 (feat/use-feature "components/v2")
|
||||
fetch-state (mf/use-fn
|
||||
(mf/deps file-id page-id share-id object-id components-v2)
|
||||
(fn []
|
||||
|
@ -141,7 +141,7 @@
|
|||
|
||||
(mf/defc objects-svg
|
||||
[{:keys [page-id file-id share-id object-ids render-embed?]}]
|
||||
(let [components-v2 (feat/use-feature :components-v2)
|
||||
(let [components-v2 (feat/use-feature "components/v2")
|
||||
fetch-state (mf/use-fn
|
||||
(mf/deps file-id page-id share-id components-v2)
|
||||
(fn []
|
||||
|
|
|
@ -99,21 +99,21 @@
|
|||
(rf result input)))))
|
||||
|
||||
(defn prettify
|
||||
"Prepare x fror cleaner output when logged."
|
||||
"Prepare x for cleaner output when logged."
|
||||
[x]
|
||||
(cond
|
||||
(map? x) (d/mapm #(prettify %2) x)
|
||||
(vector? x) (mapv prettify x)
|
||||
(seq? x) (map prettify x)
|
||||
(set? x) (into #{} (map prettify x))
|
||||
(set? x) (into #{} (map prettify) x)
|
||||
(number? x) (mth/precision x 4)
|
||||
(uuid? x) (str "#uuid " x)
|
||||
(uuid? x) (str/concat "#uuid " x)
|
||||
:else x))
|
||||
|
||||
(defn ^:export logjs
|
||||
([str] (tap (partial logjs str)))
|
||||
([str val]
|
||||
(js/console.log str (clj->js (prettify val)))
|
||||
(js/console.log str (clj->js (prettify val) :keyword-fn (fn [v] (str/concat v))))
|
||||
val))
|
||||
|
||||
(when (exists? js/window)
|
||||
|
@ -403,7 +403,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [features (cond-> #{}
|
||||
(features/active-feature? state :components-v2)
|
||||
(features/active-feature? state "components/v2")
|
||||
(conj "components/v2"))
|
||||
sid (:session-id state)
|
||||
file (get state :workspace-file)
|
||||
|
|
|
@ -7,18 +7,23 @@
|
|||
;; This namespace is only to export the functions for toggle features
|
||||
(ns features
|
||||
(:require
|
||||
[app.main.features :as features]))
|
||||
|
||||
(defn ^:export components-v2 []
|
||||
(features/toggle-feature! :components-v2)
|
||||
nil)
|
||||
[app.main.features :as features]
|
||||
[app.main.store :as st]
|
||||
[app.util.timers :as tm]))
|
||||
|
||||
(defn ^:export is-components-v2 []
|
||||
(let [active? (features/active-feature :components-v2)]
|
||||
@active?))
|
||||
(features/active-feature? @st/state "components/v2"))
|
||||
|
||||
(defn ^:export new-css-system []
|
||||
(features/toggle-feature! :new-css-system))
|
||||
(tm/schedule-on-idle #(st/emit! (features/toggle-feature "styles/v2")))
|
||||
nil)
|
||||
|
||||
(defn ^:export grid []
|
||||
(features/toggle-feature! :grid-layout))
|
||||
(tm/schedule-on-idle #(st/emit! (features/toggle-feature "layout/grid")))
|
||||
nil)
|
||||
|
||||
(defn ^:export get-enabled []
|
||||
(clj->js (features/get-enabled-features @st/state)))
|
||||
|
||||
(defn ^:export get-team-enabled []
|
||||
(clj->js (features/get-team-enabled-features @st/state)))
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
:pages []
|
||||
:pages-index {}}
|
||||
:workspace-libraries {}
|
||||
:features {:components-v2 true}})
|
||||
:features/team #{"components/v2"}})
|
||||
|
||||
(def ^:private idmap (atom {}))
|
||||
|
||||
|
|
|
@ -4174,35 +4174,6 @@ msgstr "Oddělit uzly (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Přichytit uzly (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Chcete-li to zkusit znovu, můžete tento soubor znovu načíst. Pokud problém "
|
||||
"přetrvává, doporučujeme vám podívat se na seznam a zvážit odstranění "
|
||||
"poškozené grafiky."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Některé grafiky nebylo možné aktualizovat."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Převádí se %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Grafiky knihovny jsou od nynějška komponenty, díky čemuž budou mnohem "
|
||||
"výkonnější."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Tato aktualizace je jednorázová."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Aktualizace %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Přidat flexibilní rozložení"
|
||||
|
|
|
@ -4453,35 +4453,6 @@ msgstr "Ankerpunkte trennen (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "An Ankerpunkten ausrichten (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Um es erneut zu versuchen, können Sie diese Datei neu laden. Wenn das "
|
||||
"Problem weiterhin besteht, empfehlen wir Ihnen, einen Blick auf die Liste "
|
||||
"zu werfen und zu überlegen, ob Sie defekte Grafiken löschen wollen."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Einige Grafiken konnten nicht aktualisiert werden."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Konvertieren von %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Von nun an sind Grafiken in der Bibliothek auch Komponenten. Das macht sie "
|
||||
"viel leistungsfähiger."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Diese Aktualisierung ist eine einmalige Aktion."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Aktualisierung von %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Flex-Layout hinzufügen"
|
||||
|
|
|
@ -879,10 +879,21 @@ msgstr ""
|
|||
"Looks like you are opening a file that has the feature '%s' enabled but "
|
||||
"your penpot frontend does not supports it or has it disabled."
|
||||
|
||||
#: src/app/main/errors.cljs
|
||||
msgid "errors.file-feature-mismatch"
|
||||
msgstr ""
|
||||
"It seems that there is a mismatch between the enabled features and the "
|
||||
"features of the file you are trying to open. Migrations for '%s' need "
|
||||
"to be applied before the file can be opened."
|
||||
|
||||
#: src/app/main/errors.cljs
|
||||
msgid "errors.feature-not-supported"
|
||||
msgstr "Feature '%s' is not supported."
|
||||
|
||||
#: src/app/main/errors.cljs
|
||||
msgid "errors.team-feature-mismatch"
|
||||
msgstr "Detected incompatible feature '%s'"
|
||||
|
||||
#: src/app/main/ui/auth/verify_token.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/dashboard/team.cljs
|
||||
msgid "errors.generic"
|
||||
msgstr "Something wrong has happened."
|
||||
|
@ -4561,35 +4572,6 @@ msgstr "Separate nodes (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Snap nodes (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"To try it again, you can reload this file. If the problem persists, we "
|
||||
"suggest you to take a look at the list and consider to delete broken "
|
||||
"graphics."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Some graphics could not be updated."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Converting %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Library Graphics are Components from now on, which will make them much more "
|
||||
"powerful."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "This update is a one time action."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Updating %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Add flex layout"
|
||||
|
|
|
@ -903,6 +903,13 @@ msgstr ""
|
|||
"pero la aplicacion web de penpot que esta usando no tiene soporte para ella "
|
||||
"o esta deshabilitada."
|
||||
|
||||
#: src/app/main/errors.cljs
|
||||
msgid "errors.file-feature-mismatch"
|
||||
msgstr ""
|
||||
"Parece que hay discordancia entre las features habilitadas y las features "
|
||||
"del fichero que se esta intentando abrir. Falta aplicar migraciones para "
|
||||
"'%s' antes de poder abrir el fichero."
|
||||
|
||||
#: src/app/main/errors.cljs
|
||||
msgid "errors.feature-not-supported"
|
||||
msgstr "Caracteristica no soportada: '%s'."
|
||||
|
@ -4650,35 +4657,6 @@ msgstr "Separar nodos (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Alinear nodos (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Para intentarlo de nuevo, puedes recargar este archivo. Si el problema "
|
||||
"persiste, te sugerimos que compruebes la lista y consideres borrar los "
|
||||
"gráficos que estén mal."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Algunos gráficos no han podido ser actualizados."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Convirtiendo %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Desde ahora los gráficos de la librería serán componentes, lo cual los hará "
|
||||
"mucho más potentes."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Esta actualización sólo ocurrirá una vez."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Actualizando %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Añadir flex layout"
|
||||
|
|
|
@ -4173,35 +4173,6 @@ msgstr "Banatu nodoak (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Atxikitu nodoak (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Berriz saiatzeko, fitxategi hau berriz kargatu dezakezu. Hala ere arazoa "
|
||||
"izaten jarraitzen baduzu, begiratu zerrenda eta ezabatu apurtutako "
|
||||
"grafikoak."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Grafiko batzuk ezin izan dira eguneratu."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Bihurtzen %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Liburutegiko grafikoak osagaiak izango dira orain, horrek ahaltsuago egingo "
|
||||
"ditu."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Eguneraketa hau behin bakarrik gertatuko da."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Eguneratzen %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Gehitu flex diseinua"
|
||||
|
|
|
@ -4457,32 +4457,6 @@ msgstr "הפרדת מפרקים (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "הצמדת מפרקים (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"כדי לנסות שוב, אפשר לרענן את הקובץ הזה. אם הבעיה נמשכת, אנו ממליצים לך "
|
||||
"להביט ברשימה ולשקול למחוק גרפיקה פגומה."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "לא ניתן לעדכן חלק מהגרפיקה."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "מתבצעת המרה %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr "גרפיקות ספרייה הן רכיבים מעתה ואילך, מה שהופך אותן להרבה יותר עוצמתיות."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "העדכון הזה הוא חד־פעמי."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "%s מתעדכן…"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "הוספת פריסת flex"
|
||||
|
|
|
@ -4585,35 +4585,6 @@ msgstr "Simpul terpisah (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Tancap simpul (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Untuk mencoba lagi, Anda dapat memuat ulang berkas ini. Jika masalah tetap "
|
||||
"ada, kami menyarankan Anda untuk melihat daftar dan mempertimbangkan untuk "
|
||||
"menghapus grafis yang rusak."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Beberapa grafis tidak dapat diperbarui."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Mengubah %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Grafis Pustaka itu Komponen dari sekarang, yang akan membuatnya lebih "
|
||||
"berdaya."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Pembaruan ini adalah tindakan satu kali."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Memperbarui %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Tambahkan tata letak flex"
|
||||
|
|
|
@ -4568,34 +4568,6 @@ msgstr "Atdalīt mezglus (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Pieķert mezglus (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Lai to mēģinātu vēlreiz, varat atkārtoti ielādēt šo failu. Ja problēma "
|
||||
"joprojām pastāv, ieteicams apskatīt sarakstu un dzēst bojātās grafikas."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Dažas grafikas nevar atjaunināt."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "%s/%s pārvēršana"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Bibliotēkas grafikas turpmāk sauksies Komponentes, kas padarīs tās daudz "
|
||||
"jaudīgākas."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Šis atjauninājums ir vienreizēja darbība."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Notiek %s atjaunināšana..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Pievienot elastīgo izkārtojumu"
|
||||
|
|
|
@ -4537,35 +4537,6 @@ msgstr "Verschillende knooppunten (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Snap knooppunten (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Om het opnieuw te proberen, kun je dit bestand opnieuw laden. Als het "
|
||||
"probleem zich blijft voordoen, raden we aan de lijst te bekijken en te "
|
||||
"overwegen om kapotte afbeeldingen te verwijderen."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Sommige afbeeldingen kunnen niet worden bijgewerkt."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "%s/%s converteren"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Bibliotheekafbeeldingen zijn vanaf nu componenten, waardoor ze veel "
|
||||
"krachtiger worden."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Deze update is een eenmalige actie."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "%s bijwerken..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Flex-indeling toevoegen"
|
||||
|
|
|
@ -4011,35 +4011,6 @@ msgstr "Rozłącz węzły (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Przyciągnij węzły (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Aby spróbować ponownie, możesz ponownie załadować ten plik. Jeśli problem "
|
||||
"będzie się powtarzał, sugerujemy przejrzenie listy i rozważenie usunięcia "
|
||||
"uszkodzonej grafiki."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Niektórych grafik nie udało się zaktualizować."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Konwersja %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Grafika biblioteczna jest od teraz komponentami, co sprawi, że będą "
|
||||
"znacznie potężniejsze."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Ta aktualizacja jest działaniem jednorazowym."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Aktualizowanie %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Dodaj układ flex"
|
||||
|
|
|
@ -3994,35 +3994,6 @@ msgstr "Separar pontos (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Aderir aos pontos (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Para tentar novamente, recarregue este arquivo. Se o problema persistir, "
|
||||
"sugerimos olhar a lista e considerar excluir gráficos que não estejam "
|
||||
"funcionando."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Alguns gráficos não puderam ser atualizados."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Convertendo %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"A partir de agora os gráficos da biblioteca são Componentes, o que os "
|
||||
"tornarão bem mais poderosos."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Essa atualização acontecerá apenas uma vez."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Atualizando %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Adicionar Flex Layout"
|
||||
|
|
|
@ -4588,35 +4588,6 @@ msgstr "Separar nós (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Ajustar nós (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Para tentar de novo, podes recarregar este ficheiro. Se o problema "
|
||||
"persistir, sugerimos que observes a lista e consideres em apagar os "
|
||||
"gráficos problemáticos."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Não foi possível atualizar alguns gráficos."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "A converter %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"A partir de agora, os Gráficos da biblioteca passarão a ser Componentes, o "
|
||||
"que os tornará mais poderosos."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Esta atualização só ocorrerá uma única vez."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "A atualizar %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Adicionar layout flex"
|
||||
|
|
|
@ -4626,35 +4626,6 @@ msgstr "Separă noduri (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Trage noduri (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Pentru a încerca din nou, puteți reîncărca acest fișier. Dacă problema "
|
||||
"persistă, vă sugerăm să aruncați o privire pe listă și să luați în "
|
||||
"considerare ștergerea graficii rupte."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Unele elemente grafice nu au putut fi actualizate."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "Se convertește %s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Bibliotecile Grafice sunt Componente de acum înainte, ceea ce le va face "
|
||||
"mult mai puternice."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Această actualizare este o acțiune unică."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "Actualizare %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Adăugați aspect flexibil"
|
||||
|
|
|
@ -4087,35 +4087,6 @@ msgstr "Düğümleri ayır (%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "Düğümleri tuttur (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr ""
|
||||
"Tekrar denemek için bu dosyayı yeniden yükleyebilirsiniz. Sorun devam "
|
||||
"ederse, listeye bir göz atmanızı ve bozuk grafikleri silmeyi düşünmenizi "
|
||||
"öneririz."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "Bazı grafikler güncellenemedi."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "%s/%s dönüştürülüyor"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr ""
|
||||
"Kütüphane Grafikleri bundan böyle Bileşenlerdir ve bu da onları çok daha "
|
||||
"güçlü kılacaktır."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "Bu güncelleme tek seferlik bir işlemdir."
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "%s güncelleniyor..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Düzen esnekliği ekle"
|
||||
|
|
|
@ -4069,30 +4069,6 @@ msgstr "拆分节点(%s)"
|
|||
msgid "workspace.path.actions.snap-nodes"
|
||||
msgstr "对接节点 (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-hint"
|
||||
msgstr "要重试,您可以重新加载此文件。如果问题仍然存在,我们建议您查看列表并考虑删除损坏的图形。"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.error-msg"
|
||||
msgstr "某些图形无法更新。"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.progress"
|
||||
msgstr "转换%s/%s"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text1"
|
||||
msgstr "从现在开始,库图形是组件,这将使它们更加强大。"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.text2"
|
||||
msgstr "此更新是一次性操作。"
|
||||
|
||||
#: src/app/main/ui/workspace.cljs
|
||||
msgid "workspace.remove-graphics.title"
|
||||
msgstr "正在更新 %s..."
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "添加弹性布局"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue