mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
Merge tag '2.6.0'
This commit is contained in:
commit
faead09174
@ -1,6 +1,6 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
## 2.6.0 (Unreleased)
|
## 2.6.0
|
||||||
|
|
||||||
### :rocket: Epics and highlights
|
### :rocket: Epics and highlights
|
||||||
|
|
||||||
@ -25,6 +25,7 @@
|
|||||||
- [DESIGN TOKENS] Import and export tokens from a JSON file.
|
- [DESIGN TOKENS] Import and export tokens from a JSON file.
|
||||||
- [DESIGN TOKENS] Apply Themes and Sets at document level.
|
- [DESIGN TOKENS] Apply Themes and Sets at document level.
|
||||||
- Add more descriptive tooltip to boards for first time users [Taiga #9426](https://tree.taiga.io/project/penpot/us/9426)
|
- Add more descriptive tooltip to boards for first time users [Taiga #9426](https://tree.taiga.io/project/penpot/us/9426)
|
||||||
|
- First State of a Project Changes Consolidation [Taia #10605](https://tree.taiga.io/project/penpot/us/10605)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
@ -47,6 +48,7 @@
|
|||||||
- Fix available size of resize handler [Taiga #10639](https://tree.taiga.io/project/penpot/issue/10639)
|
- Fix available size of resize handler [Taiga #10639](https://tree.taiga.io/project/penpot/issue/10639)
|
||||||
- Internal error when install a plugin by penpothub - Try plugin [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
- Internal error when install a plugin by penpothub - Try plugin [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
||||||
- Add character limitation to asset inputs [Taiga #10669](https://tree.taiga.io/project/penpot/issue/10669)
|
- Add character limitation to asset inputs [Taiga #10669](https://tree.taiga.io/project/penpot/issue/10669)
|
||||||
|
- Fix Storybook link 'list of all available icons' wrong path [Taiga #10705](https://tree.taiga.io/project/penpot/issue/10705)
|
||||||
|
|
||||||
## 2.5.4
|
## 2.5.4
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC",
|
"author": "Kaleidos INC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728",
|
"packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/penpot/penpot"
|
"url": "https://github.com/penpot/penpot"
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
(let [claims (-> {}
|
(let [claims (-> {}
|
||||||
(into (::session/token-claims request))
|
(into (::session/token-claims request))
|
||||||
(into (::actoken/token-claims request)))]
|
(into (::actoken/token-claims request)))]
|
||||||
|
|
||||||
{:request/path (:path request)
|
{:request/path (:path request)
|
||||||
:request/method (:method request)
|
:request/method (:method request)
|
||||||
:request/params (:params request)
|
:request/params (:params request)
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
(contains? cf/flags :login-with-password))
|
(contains? cf/flags :login-with-password))
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :login-disabled
|
:code :login-disabled
|
||||||
:hint "login is disabled in this instance"))
|
:hint "login is disabled"))
|
||||||
|
|
||||||
(letfn [(check-password [cfg profile password]
|
(letfn [(check-password [cfg profile password]
|
||||||
(if (= (:password profile) "!")
|
(if (= (:password profile) "!")
|
||||||
@ -79,7 +79,8 @@
|
|||||||
:code :wrong-credentials))
|
:code :wrong-credentials))
|
||||||
(when (:is-blocked profile)
|
(when (:is-blocked profile)
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :profile-blocked))
|
:code :profile-blocked
|
||||||
|
:hint "profile is marked as blocked"))
|
||||||
(when-not (check-password cfg profile password)
|
(when-not (check-password cfg profile password)
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :wrong-credentials))
|
:code :wrong-credentials))
|
||||||
@ -183,11 +184,11 @@
|
|||||||
(defn- validate-register-attempt!
|
(defn- validate-register-attempt!
|
||||||
[cfg params]
|
[cfg params]
|
||||||
|
|
||||||
(when (or
|
(when (or (not (contains? cf/flags :registration))
|
||||||
(not (contains? cf/flags :registration))
|
(not (contains? cf/flags :login-with-password)))
|
||||||
(not (contains? cf/flags :login-with-password)))
|
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :registration-disabled))
|
:code :registration-disabled
|
||||||
|
:hint "registration disabled"))
|
||||||
|
|
||||||
(when (contains? params :invitation-token)
|
(when (contains? params :invitation-token)
|
||||||
(let [invitation (tokens/verify (::setup/props cfg)
|
(let [invitation (tokens/verify (::setup/props cfg)
|
||||||
@ -201,12 +202,14 @@
|
|||||||
(when (and (email.blacklist/enabled? cfg)
|
(when (and (email.blacklist/enabled? cfg)
|
||||||
(email.blacklist/contains? cfg (:email params)))
|
(email.blacklist/contains? cfg (:email params)))
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :email-domain-is-not-allowed))
|
:code :email-domain-is-not-allowed
|
||||||
|
:hint "email domain in blacklist"))
|
||||||
|
|
||||||
(when (and (email.whitelist/enabled? cfg)
|
(when (and (email.whitelist/enabled? cfg)
|
||||||
(not (email.whitelist/contains? cfg (:email params))))
|
(not (email.whitelist/contains? cfg (:email params))))
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :email-domain-is-not-allowed))
|
:code :email-domain-is-not-allowed
|
||||||
|
:hint "email domain not in whitelist"))
|
||||||
|
|
||||||
;; Perform a basic validation of email & password
|
;; Perform a basic validation of email & password
|
||||||
(when (= (str/lower (:email params))
|
(when (= (str/lower (:email params))
|
||||||
@ -219,13 +222,13 @@
|
|||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :email-has-permanent-bounces
|
:code :email-has-permanent-bounces
|
||||||
:email (:email params)
|
:email (:email params)
|
||||||
:hint "looks like the email has bounce reports"))
|
:hint "email has bounce reports"))
|
||||||
|
|
||||||
(when (eml/has-complaint-reports? cfg (:email params))
|
(when (eml/has-complaint-reports? cfg (:email params))
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :email-has-complaints
|
:code :email-has-complaints
|
||||||
:email (:email params)
|
:email (:email params)
|
||||||
:hint "looks like the email has complaint reports")))
|
:hint "email has complaint reports")))
|
||||||
|
|
||||||
(defn prepare-register
|
(defn prepare-register
|
||||||
[{:keys [::db/pool] :as cfg} {:keys [email] :as params}]
|
[{:keys [::db/pool] :as cfg} {:keys [email] :as params}]
|
||||||
|
|||||||
@ -328,7 +328,7 @@
|
|||||||
|
|
||||||
(-> (cfeat/get-team-enabled-features cf/flags team)
|
(-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
(cfeat/check-client-features! (:features params))
|
||||||
(cfeat/check-file-features! (:features file) (:features params)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
;; This operation is needed for backward comapatibility with frontends that
|
;; This operation is needed for backward comapatibility with frontends that
|
||||||
;; does not support pointer-map resolution mechanism; this just resolves the
|
;; does not support pointer-map resolution mechanism; this just resolves the
|
||||||
@ -490,7 +490,7 @@
|
|||||||
|
|
||||||
_ (-> (cfeat/get-team-enabled-features cf/flags team)
|
_ (-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
(cfeat/check-client-features! (:features params))
|
||||||
(cfeat/check-file-features! (:features file) (:features params)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
page (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)]
|
page (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)]
|
||||||
(let [page-id (or page-id (-> file :data :pages first))
|
(let [page-id (or page-id (-> file :data :pages first))
|
||||||
@ -737,7 +737,7 @@
|
|||||||
|
|
||||||
(-> (cfeat/get-team-enabled-features cf/flags team)
|
(-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
(cfeat/check-client-features! (:features params))
|
||||||
(cfeat/check-file-features! (:features file) (:features params)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)]
|
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)]
|
||||||
{:name (:name file)
|
{:name (:name file)
|
||||||
|
|||||||
@ -91,9 +91,6 @@
|
|||||||
:project-id project-id)
|
:project-id project-id)
|
||||||
team-id (:id team)
|
team-id (:id team)
|
||||||
|
|
||||||
;; When we create files, we only need to respect the team
|
|
||||||
;; features, because some features can be enabled
|
|
||||||
;; globally, but the team is still not migrated properly.
|
|
||||||
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params)))
|
(cfeat/check-client-features! (:features params)))
|
||||||
|
|
||||||
@ -107,7 +104,7 @@
|
|||||||
|
|
||||||
params (-> params
|
params (-> params
|
||||||
(assoc :profile-id profile-id)
|
(assoc :profile-id profile-id)
|
||||||
(assoc :features (set/difference features cfeat/frontend-only-features)))]
|
(assoc :features features))]
|
||||||
|
|
||||||
(quotes/check! cfg {::quotes/id ::quotes/files-per-project
|
(quotes/check! cfg {::quotes/id ::quotes/files-per-project
|
||||||
::quotes/team-id team-id
|
::quotes/team-id team-id
|
||||||
@ -120,7 +117,7 @@
|
|||||||
;; to lost team features updating
|
;; to lost team features updating
|
||||||
|
|
||||||
;; When newly computed features does not match exactly with
|
;; When newly computed features does not match exactly with
|
||||||
;; the features defined on team row, we update it.
|
;; the features defined on team row, we update it
|
||||||
(when (not= features (:features team))
|
(when (not= features (:features team))
|
||||||
(let [features (db/create-array conn "text" features)]
|
(let [features (db/create-array conn "text" features)]
|
||||||
(db/update! conn :team
|
(db/update! conn :team
|
||||||
|
|||||||
@ -212,7 +212,7 @@
|
|||||||
|
|
||||||
(-> (cfeat/get-team-enabled-features cf/flags team)
|
(-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
(cfeat/check-client-features! (:features params))
|
||||||
(cfeat/check-file-features! (:features file) (:features params)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
{:file-id file-id
|
{:file-id file-id
|
||||||
:revn (:revn file)
|
:revn (:revn file)
|
||||||
|
|||||||
@ -142,7 +142,7 @@
|
|||||||
|
|
||||||
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
(cfeat/check-client-features! (:features params))
|
||||||
(cfeat/check-file-features! (:features file) (:features params)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
changes (if changes-with-metadata
|
changes (if changes-with-metadata
|
||||||
(->> changes-with-metadata (mapcat :changes) vec)
|
(->> changes-with-metadata (mapcat :changes) vec)
|
||||||
|
|||||||
@ -209,100 +209,116 @@
|
|||||||
This method allows send flash notifications to specified target destinations.
|
This method allows send flash notifications to specified target destinations.
|
||||||
The message can be a free text or a preconfigured one.
|
The message can be a free text or a preconfigured one.
|
||||||
|
|
||||||
The destination can be: all, profile-id, team-id, or a coll of them."
|
The destination can be: all, profile-id, team-id, or a coll of them.
|
||||||
[{:keys [::mbus/msgbus ::db/pool]} & {:keys [dest code message level]
|
It also can be:
|
||||||
:or {code :generic level :info}
|
|
||||||
:as params}]
|
{:email \"some@example.com\"}
|
||||||
|
[[:email \"some@example.com\"], ...]
|
||||||
|
|
||||||
|
Command examples:
|
||||||
|
|
||||||
|
(notify! :dest :all :code :maintenance)
|
||||||
|
(notify! :dest :all :code :upgrade-version)
|
||||||
|
"
|
||||||
|
[& {:keys [dest code message level]
|
||||||
|
:or {code :generic level :info}
|
||||||
|
:as params}]
|
||||||
|
|
||||||
(when-not (contains? #{:success :error :info :warning} level)
|
(when-not (contains? #{:success :error :info :warning} level)
|
||||||
(ex/raise :type :assertion
|
(ex/raise :type :assertion
|
||||||
:code :incorrect-level
|
:code :incorrect-level
|
||||||
:hint (str "level '" level "' not supported")))
|
:hint (str "level '" level "' not supported")))
|
||||||
|
|
||||||
(letfn [(send [dest]
|
(let [{:keys [::mbus/msgbus ::db/pool]} main/system
|
||||||
(l/inf :hint "sending notification" :dest (str dest))
|
|
||||||
(let [message {:type :notification
|
|
||||||
:code code
|
|
||||||
:level level
|
|
||||||
:version (:full cf/version)
|
|
||||||
:subs-id dest
|
|
||||||
:message message}
|
|
||||||
message (->> (dissoc params :dest :code :message :level)
|
|
||||||
(merge message))]
|
|
||||||
(mbus/pub! msgbus
|
|
||||||
:topic (str dest)
|
|
||||||
:message message)))
|
|
||||||
|
|
||||||
(resolve-profile [email]
|
send
|
||||||
(some-> (db/get* pool :profile {:email (str/lower email)} {:columns [:id]}) :id vector))
|
(fn [dest]
|
||||||
|
(l/inf :hint "sending notification" :dest (str dest))
|
||||||
|
(let [message {:type :notification
|
||||||
|
:code code
|
||||||
|
:level level
|
||||||
|
:version (:full cf/version)
|
||||||
|
:subs-id dest
|
||||||
|
:message message}
|
||||||
|
message (->> (dissoc params :dest :code :message :level)
|
||||||
|
(merge message))]
|
||||||
|
(mbus/pub! msgbus
|
||||||
|
:topic dest
|
||||||
|
:message message)))
|
||||||
|
|
||||||
(resolve-team [team-id]
|
resolve-profile
|
||||||
(->> (db/query pool :team-profile-rel
|
(fn [email]
|
||||||
{:team-id team-id}
|
(some-> (db/get* pool :profile {:email (str/lower email)} {:columns [:id]}) :id vector))
|
||||||
{:columns [:profile-id]})
|
|
||||||
(map :profile-id)))
|
|
||||||
|
|
||||||
(resolve-dest [dest]
|
resolve-team
|
||||||
(cond
|
(fn [team-id]
|
||||||
(= :all dest)
|
(->> (db/query pool :team-profile-rel
|
||||||
[uuid/zero]
|
{:team-id team-id}
|
||||||
|
{:columns [:profile-id]})
|
||||||
|
(map :profile-id)))
|
||||||
|
|
||||||
(uuid? dest)
|
resolve-dest
|
||||||
[dest]
|
(fn resolve-dest [dest]
|
||||||
|
(cond
|
||||||
|
(= :all dest)
|
||||||
|
[uuid/zero]
|
||||||
|
|
||||||
(string? dest)
|
(uuid? dest)
|
||||||
(some-> dest h/parse-uuid resolve-dest)
|
[dest]
|
||||||
|
|
||||||
(nil? dest)
|
(string? dest)
|
||||||
(resolve-dest uuid/zero)
|
(some-> dest h/parse-uuid resolve-dest)
|
||||||
|
|
||||||
(map? dest)
|
(nil? dest)
|
||||||
(sequence (comp
|
[uuid/zero]
|
||||||
(map vec)
|
|
||||||
(mapcat resolve-dest))
|
|
||||||
dest)
|
|
||||||
|
|
||||||
(and (vector? dest)
|
(map? dest)
|
||||||
(every? vector? dest))
|
(sequence (comp
|
||||||
(sequence (comp
|
(map vec)
|
||||||
(map vec)
|
(mapcat resolve-dest))
|
||||||
(mapcat resolve-dest))
|
dest)
|
||||||
dest)
|
|
||||||
|
|
||||||
(and (vector? dest)
|
(and (vector? dest)
|
||||||
(keyword? (first dest)))
|
(every? vector? dest))
|
||||||
(let [[op param] dest]
|
(sequence (comp
|
||||||
|
(map vec)
|
||||||
|
(mapcat resolve-dest))
|
||||||
|
dest)
|
||||||
|
|
||||||
|
(and (vector? dest)
|
||||||
|
(keyword? (first dest)))
|
||||||
|
(let [[op param] dest]
|
||||||
|
(cond
|
||||||
|
(= op :email)
|
||||||
(cond
|
(cond
|
||||||
(= op :email)
|
(and (coll? param)
|
||||||
(cond
|
(every? string? param))
|
||||||
(and (coll? param)
|
(sequence (comp
|
||||||
(every? string? param))
|
(keep resolve-profile)
|
||||||
(sequence (comp
|
(mapcat identity))
|
||||||
(keep resolve-profile)
|
param)
|
||||||
(mapcat identity))
|
|
||||||
param)
|
|
||||||
|
|
||||||
(string? param)
|
(string? param)
|
||||||
(resolve-profile param))
|
(resolve-profile param))
|
||||||
|
|
||||||
(= op :team-id)
|
(= op :team-id)
|
||||||
(cond
|
(cond
|
||||||
(coll? param)
|
(coll? param)
|
||||||
(sequence (comp
|
(sequence (comp
|
||||||
(mapcat resolve-team)
|
(mapcat resolve-team)
|
||||||
(keep h/parse-uuid))
|
(keep h/parse-uuid))
|
||||||
param)
|
param)
|
||||||
|
|
||||||
(uuid? param)
|
(uuid? param)
|
||||||
(resolve-team param)
|
(resolve-team param)
|
||||||
|
|
||||||
(string? param)
|
(string? param)
|
||||||
(some-> param h/parse-uuid resolve-team))
|
(some-> param h/parse-uuid resolve-team))
|
||||||
|
|
||||||
(= op :profile-id)
|
(= op :profile-id)
|
||||||
(if (coll? param)
|
(if (coll? param)
|
||||||
(sequence (keep h/parse-uuid) param)
|
(sequence (keep h/parse-uuid) param)
|
||||||
(resolve-dest param))))))]
|
(resolve-dest param))))))]
|
||||||
|
|
||||||
(->> (resolve-dest dest)
|
(->> (resolve-dest dest)
|
||||||
(filter some?)
|
(filter some?)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC",
|
"author": "Kaleidos INC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728",
|
"packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@ -85,12 +85,11 @@
|
|||||||
;; be applied (per example backend can operate in both modes with or
|
;; be applied (per example backend can operate in both modes with or
|
||||||
;; without migration applied)
|
;; without migration applied)
|
||||||
(def no-migration-features
|
(def no-migration-features
|
||||||
(-> #{"fdata/objects-map"
|
(-> #{"layout/grid"
|
||||||
"fdata/pointer-map"
|
|
||||||
"layout/grid"
|
|
||||||
"fdata/shape-data-type"
|
"fdata/shape-data-type"
|
||||||
"design-tokens/v1"}
|
"design-tokens/v1"}
|
||||||
(into frontend-only-features)))
|
(into frontend-only-features)
|
||||||
|
(into backend-only-features)))
|
||||||
|
|
||||||
(sm/register!
|
(sm/register!
|
||||||
^{::sm/type ::features}
|
^{::sm/type ::features}
|
||||||
@ -158,7 +157,6 @@
|
|||||||
team-features (into #{} xf-remove-ephimeral (:features team))]
|
team-features (into #{} xf-remove-ephimeral (:features team))]
|
||||||
(-> enabled-features
|
(-> enabled-features
|
||||||
(set/intersection no-migration-features)
|
(set/intersection no-migration-features)
|
||||||
(set/difference frontend-only-features)
|
|
||||||
(set/union team-features))))
|
(set/union team-features))))
|
||||||
|
|
||||||
(defn check-client-features!
|
(defn check-client-features!
|
||||||
@ -167,6 +165,8 @@
|
|||||||
frontend client"
|
frontend client"
|
||||||
[enabled-features client-features]
|
[enabled-features client-features]
|
||||||
(when (set? client-features)
|
(when (set? client-features)
|
||||||
|
;; Check if client declares support for features enabled on
|
||||||
|
;; backend side
|
||||||
(let [not-supported (-> enabled-features
|
(let [not-supported (-> enabled-features
|
||||||
(set/difference client-features)
|
(set/difference client-features)
|
||||||
(set/difference frontend-only-features)
|
(set/difference frontend-only-features)
|
||||||
@ -176,14 +176,6 @@
|
|||||||
:code :feature-not-supported
|
:code :feature-not-supported
|
||||||
:feature (first not-supported)
|
:feature (first not-supported)
|
||||||
:hint (str/ffmt "client declares no support for '%' features"
|
:hint (str/ffmt "client declares no support for '%' features"
|
||||||
(str/join "," not-supported)))))
|
|
||||||
|
|
||||||
(let [not-supported (set/difference client-features supported-features)]
|
|
||||||
(when (seq not-supported)
|
|
||||||
(ex/raise :type :restriction
|
|
||||||
:code :feature-not-supported
|
|
||||||
:feature (first not-supported)
|
|
||||||
:hint (str/ffmt "backend does not support '%' features requested by client"
|
|
||||||
(str/join "," not-supported))))))
|
(str/join "," not-supported))))))
|
||||||
|
|
||||||
enabled-features)
|
enabled-features)
|
||||||
@ -194,57 +186,49 @@
|
|||||||
supported by the current backend"
|
supported by the current backend"
|
||||||
[enabled-features]
|
[enabled-features]
|
||||||
(let [not-supported (set/difference enabled-features supported-features)]
|
(let [not-supported (set/difference enabled-features supported-features)]
|
||||||
(when (seq not-supported)
|
(when-let [not-supported (first not-supported)]
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :feature-not-supported
|
:code :feature-not-supported
|
||||||
:feature (first not-supported)
|
:feature not-supported
|
||||||
:hint (str/ffmt "features '%' not supported"
|
:hint (str/ffmt "feature '%' not supported on this backend" not-supported)))
|
||||||
(str/join "," not-supported)))))
|
enabled-features))
|
||||||
enabled-features)
|
|
||||||
|
|
||||||
(defn check-file-features!
|
(defn check-file-features!
|
||||||
"Function used for check feature compability between currently
|
"Function used for check feature compability between currently
|
||||||
enabled features set on backend with the provided featured set by
|
enabled features set on backend with the provided featured set by
|
||||||
the penpot file"
|
the penpot file"
|
||||||
([enabled-features file-features]
|
[enabled-features file-features]
|
||||||
(check-file-features! enabled-features file-features #{}))
|
(let [file-features (into #{} xf-remove-ephimeral file-features)
|
||||||
([enabled-features file-features client-features]
|
not-supported (-> enabled-features
|
||||||
(let [file-features (into #{} xf-remove-ephimeral file-features)
|
(set/difference file-features)
|
||||||
;; We should ignore all features that does not match with the
|
;; NOTE: we don't want to raise a feature-mismatch
|
||||||
;; `no-migration-features` set because we can't enable them
|
;; exception for features which don't require an
|
||||||
;; as-is, because they probably need migrations
|
;; explicit file migration process or has no real
|
||||||
client-features (set/intersection client-features no-migration-features)]
|
;; effect on file data structure
|
||||||
(let [not-supported (-> enabled-features
|
(set/difference no-migration-features))]
|
||||||
(set/union client-features)
|
|
||||||
(set/difference file-features)
|
|
||||||
;; NOTE: we don't want to raise a feature-mismatch
|
|
||||||
;; exception for features which don't require an
|
|
||||||
;; explicit file migration process or has no real
|
|
||||||
;; effect on file data structure
|
|
||||||
(set/difference no-migration-features))]
|
|
||||||
(when (seq not-supported)
|
|
||||||
(ex/raise :type :restriction
|
|
||||||
:code :file-feature-mismatch
|
|
||||||
:feature (first not-supported)
|
|
||||||
:hint (str/ffmt "enabled features '%' not present in file (missing migration)"
|
|
||||||
(str/join "," not-supported)))))
|
|
||||||
|
|
||||||
(check-supported-features! file-features)
|
(when-let [not-supported (first not-supported)]
|
||||||
|
(ex/raise :type :restriction
|
||||||
|
:code :file-feature-mismatch
|
||||||
|
:feature not-supported
|
||||||
|
:hint (str/ffmt "enabled feature '%' not present in file (missing migration)"
|
||||||
|
not-supported)))
|
||||||
|
|
||||||
(let [not-supported (-> file-features
|
(check-supported-features! file-features)
|
||||||
(set/difference enabled-features)
|
|
||||||
(set/difference client-features)
|
|
||||||
(set/difference backend-only-features)
|
|
||||||
(set/difference frontend-only-features))]
|
|
||||||
|
|
||||||
(when (seq not-supported)
|
(let [not-supported (-> file-features
|
||||||
(ex/raise :type :restriction
|
(set/difference enabled-features)
|
||||||
:code :file-feature-mismatch
|
(set/difference backend-only-features)
|
||||||
:feature (first not-supported)
|
(set/difference frontend-only-features))]
|
||||||
:hint (str/ffmt "file features '%' not enabled"
|
|
||||||
(str/join "," not-supported))))))
|
|
||||||
|
|
||||||
enabled-features))
|
;; Check if file has a feature but that feature is not enabled
|
||||||
|
(when-let [not-supported (first not-supported)]
|
||||||
|
(ex/raise :type :restriction
|
||||||
|
:code :file-feature-mismatch
|
||||||
|
:feature not-supported
|
||||||
|
:hint (str/ffmt "file feature '%' not enabled" not-supported))))
|
||||||
|
|
||||||
|
enabled-features))
|
||||||
|
|
||||||
(defn check-teams-compatibility!
|
(defn check-teams-compatibility!
|
||||||
[{source-features :features} {destination-features :features}]
|
[{source-features :features} {destination-features :features}]
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC",
|
"author": "Kaleidos INC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "yarn@4.7.0+sha512.5a0afa1d4c1d844b3447ee3319633797bcd6385d9a44be07993ae52ff4facabccafb4af5dcd1c2f9a94ac113e5e9ff56f6130431905884414229e284e37bb7c9",
|
"packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/penpot/penpot"
|
"url": "https://github.com/penpot/penpot"
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC",
|
"author": "Kaleidos INC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "yarn@4.7.0+sha512.5a0afa1d4c1d844b3447ee3319633797bcd6385d9a44be07993ae52ff4facabccafb4af5dcd1c2f9a94ac113e5e9ff56f6130431905884414229e284e37bb7c9",
|
"packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6",
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
],
|
],
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
[app.main.data.profile :as dp]
|
[app.main.data.profile :as dp]
|
||||||
[app.main.data.websocket :as ws]
|
[app.main.data.websocket :as ws]
|
||||||
[app.main.errors]
|
[app.main.errors]
|
||||||
[app.main.features :as feat]
|
|
||||||
[app.main.rasterizer :as thr]
|
[app.main.rasterizer :as thr]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui :as ui]
|
[app.main.ui :as ui]
|
||||||
@ -67,7 +66,6 @@
|
|||||||
(watch [_ _ stream]
|
(watch [_ _ stream]
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(rx/of (ev/initialize)
|
(rx/of (ev/initialize)
|
||||||
(feat/initialize)
|
|
||||||
(dp/refresh-profile))
|
(dp/refresh-profile))
|
||||||
|
|
||||||
;; Watch for profile deletion events
|
;; Watch for profile deletion events
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.helpers :as dsh]
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
@ -182,8 +181,8 @@
|
|||||||
(let [file-id (or file-id (:current-file-id state))
|
(let [file-id (or file-id (:current-file-id state))
|
||||||
uchg (vec undo-changes)
|
uchg (vec undo-changes)
|
||||||
rchg (vec redo-changes)
|
rchg (vec redo-changes)
|
||||||
features (features/get-team-enabled-features state)
|
features (get state :features)
|
||||||
permissions (:permissions state)]
|
permissions (get state :permissions)]
|
||||||
|
|
||||||
;; Prevent commit changes by a viewer team member (it really should never happen)
|
;; Prevent commit changes by a viewer team member (it really should never happen)
|
||||||
(when (:can-edit permissions)
|
(when (:can-edit permissions)
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.notifications :as ntf]
|
[app.main.data.notifications :as ntf]
|
||||||
[app.main.data.persistence :as-alias dps]
|
[app.main.data.persistence :as-alias dps]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.router :as rt]
|
[app.main.router :as rt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
@ -73,7 +72,7 @@
|
|||||||
(st/emit! (ntf/hide)))
|
(st/emit! (ntf/hide)))
|
||||||
|
|
||||||
(defn handle-notification
|
(defn handle-notification
|
||||||
[{:keys [message code level] :as params}]
|
[{:keys [message code] :as params}]
|
||||||
(ptk/reify ::show-notification
|
(ptk/reify ::show-notification
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
@ -81,9 +80,6 @@
|
|||||||
:upgrade-version
|
:upgrade-version
|
||||||
(rx/of (ntf/dialog
|
(rx/of (ntf/dialog
|
||||||
:content (tr "notifications.by-code.upgrade-version")
|
:content (tr "notifications.by-code.upgrade-version")
|
||||||
:controls :inline-actions
|
|
||||||
:type :inline
|
|
||||||
:level level
|
|
||||||
:accept {:label (tr "labels.refresh")
|
:accept {:label (tr "labels.refresh")
|
||||||
:callback force-reload!}
|
:callback force-reload!}
|
||||||
:tag :notification))
|
:tag :notification))
|
||||||
@ -91,16 +87,14 @@
|
|||||||
:maintenance
|
:maintenance
|
||||||
(rx/of (ntf/dialog
|
(rx/of (ntf/dialog
|
||||||
:content (tr "notifications.by-code.maintenance")
|
:content (tr "notifications.by-code.maintenance")
|
||||||
:controls :inline-actions
|
|
||||||
:type level
|
|
||||||
:accept {:label (tr "labels.accept")
|
:accept {:label (tr "labels.accept")
|
||||||
:callback hide-notifications!}
|
:callback hide-notifications!}
|
||||||
:tag :notification))
|
:tag :notification))
|
||||||
|
|
||||||
(rx/of (ntf/dialog
|
(rx/of (ntf/dialog
|
||||||
:content message
|
:content message
|
||||||
:controls :close
|
:accept {:label (tr "labels.close")
|
||||||
:type level
|
:callback hide-notifications!}
|
||||||
:tag :notification))))))
|
:tag :notification))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@ -112,7 +106,7 @@
|
|||||||
(ptk/reify ::show-shared-dialog
|
(ptk/reify ::show-shared-dialog
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [features (get state :features)
|
||||||
file (dsh/lookup-file state)
|
file (dsh/lookup-file state)
|
||||||
data (get file :data)]
|
data (get file :data)]
|
||||||
|
|
||||||
@ -169,8 +163,8 @@
|
|||||||
(ptk/reify ::export-files
|
(ptk/reify ::export-files
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [features (get state :features)
|
||||||
team-id (:current-team-id state)]
|
team-id (get state :current-team-id)]
|
||||||
(->> (rx/from files)
|
(->> (rx/from files)
|
||||||
(rx/mapcat
|
(rx/mapcat
|
||||||
(fn [file]
|
(fn [file]
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
[app.main.data.helpers :as dsh]
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.websocket :as dws]
|
[app.main.data.websocket :as dws]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.sse :as sse]
|
[app.util.sse :as sse]
|
||||||
@ -57,8 +56,7 @@
|
|||||||
(rx/filter (fn [{:keys [topic] :as msg}]
|
(rx/filter (fn [{:keys [topic] :as msg}]
|
||||||
(or (= topic uuid/zero)
|
(or (= topic uuid/zero)
|
||||||
(= topic profile-id))))
|
(= topic profile-id))))
|
||||||
(rx/map process-message)
|
(rx/map process-message)))
|
||||||
(rx/ignore)))
|
|
||||||
|
|
||||||
(rx/take-until stopper))))))
|
(rx/take-until stopper))))))
|
||||||
|
|
||||||
@ -497,7 +495,7 @@
|
|||||||
base-name (tr "dashboard.new-file-prefix")
|
base-name (tr "dashboard.new-file-prefix")
|
||||||
name (or name
|
name (or name
|
||||||
(cfh/generate-unique-name base-name unames :immediate-suffix? true))
|
(cfh/generate-unique-name base-name unames :immediate-suffix? true))
|
||||||
features (-> (features/get-team-enabled-features state)
|
features (-> (get state :features)
|
||||||
(set/difference cfeat/frontend-only-features))
|
(set/difference cfeat/frontend-only-features))
|
||||||
params (-> params
|
params (-> params
|
||||||
(assoc :name name)
|
(assoc :name name)
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
@ -47,7 +46,7 @@
|
|||||||
(ptk/reify ::export-files
|
(ptk/reify ::export-files
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [features (get state :features)
|
||||||
team-id (:current-team-id state)
|
team-id (:current-team-id state)
|
||||||
evname (if (= format :legacy-zip)
|
evname (if (= format :legacy-zip)
|
||||||
"export-standard-files"
|
"export-standard-files"
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
(def ^:private schema:notification
|
(def ^:private schema:notification
|
||||||
[:map {:title "Notification"}
|
[:map {:title "Notification"}
|
||||||
[:level [::sm/one-of #{:success :error :info :warning}]]
|
[:level {:optional true} [::sm/one-of #{:success :error :info :warning}]]
|
||||||
[:status {:optional true}
|
[:status {:optional true}
|
||||||
[::sm/one-of #{:visible :hide}]]
|
[::sm/one-of #{:visible :hide}]]
|
||||||
[:position {:optional true}
|
[:position {:optional true}
|
||||||
@ -129,15 +129,11 @@
|
|||||||
:timeout timeout})))
|
:timeout timeout})))
|
||||||
|
|
||||||
(defn dialog
|
(defn dialog
|
||||||
[& {:keys [content controls actions accept cancel position tag level links]
|
[& {:keys [content accept cancel tag links]}]
|
||||||
:or {controls :none position :floating level :info}}]
|
|
||||||
(show (d/without-nils
|
(show (d/without-nils
|
||||||
{:content content
|
{:content content
|
||||||
:level level
|
:type :inline
|
||||||
:links links
|
|
||||||
:position position
|
|
||||||
:controls controls
|
|
||||||
:actions actions
|
|
||||||
:accept accept
|
:accept accept
|
||||||
:cancel cancel
|
:cancel cancel
|
||||||
|
:links links
|
||||||
:tag tag})))
|
:tag tag})))
|
||||||
|
|||||||
@ -101,7 +101,7 @@
|
|||||||
(let [permissions (get team :permissions)
|
(let [permissions (get team :permissions)
|
||||||
features (get team :features)]
|
features (get team :features)]
|
||||||
(rx/of #(assoc % :permissions permissions)
|
(rx/of #(assoc % :permissions permissions)
|
||||||
(features/initialize (or features #{}))
|
(features/initialize features)
|
||||||
(fetch-members team-id))))))
|
(fetch-members team-id))))))
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
@ -255,12 +255,12 @@
|
|||||||
(dm/assert! (string? name))
|
(dm/assert! (string? name))
|
||||||
(ptk/reify ::create-team
|
(ptk/reify ::create-team
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it _ _]
|
||||||
(let [{:keys [on-success on-error]
|
(let [{:keys [on-success on-error]
|
||||||
:or {on-success identity
|
:or {on-success identity
|
||||||
on-error rx/throw}} (meta params)
|
on-error rx/throw}} (meta params)
|
||||||
features (features/get-enabled-features state)
|
features features/global-enabled-features
|
||||||
params {:name name :features features}]
|
params {:name name :features features}]
|
||||||
(->> (rp/cmd! :create-team (with-meta params (meta it)))
|
(->> (rp/cmd! :create-team (with-meta params (meta it)))
|
||||||
(rx/tap on-success)
|
(rx/tap on-success)
|
||||||
(rx/map team-created)
|
(rx/map team-created)
|
||||||
@ -272,11 +272,11 @@
|
|||||||
[{:keys [name emails role] :as params}]
|
[{:keys [name emails role] :as params}]
|
||||||
(ptk/reify ::create-team-with-invitations
|
(ptk/reify ::create-team-with-invitations
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it _ _]
|
||||||
(let [{:keys [on-success on-error]
|
(let [{:keys [on-success on-error]
|
||||||
:or {on-success identity
|
:or {on-success identity
|
||||||
on-error rx/throw}} (meta params)
|
on-error rx/throw}} (meta params)
|
||||||
features (features/get-enabled-features state)
|
features features/global-enabled-features
|
||||||
params {:name name
|
params {:name name
|
||||||
:emails emails
|
:emails emails
|
||||||
:role role
|
:role role
|
||||||
|
|||||||
@ -184,7 +184,7 @@
|
|||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [team-id (:id team)
|
(let [team-id (:id team)
|
||||||
team {:members users}]
|
team (assoc team :members users)]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc :share-links share-links)
|
(assoc :share-links share-links)
|
||||||
(assoc :current-team-id team-id)
|
(assoc :current-team-id team-id)
|
||||||
|
|||||||
@ -205,30 +205,29 @@
|
|||||||
(d/index-by :id))))))
|
(d/index-by :id))))))
|
||||||
|
|
||||||
(defn- fetch-libraries
|
(defn- fetch-libraries
|
||||||
[file-id]
|
[file-id features]
|
||||||
(ptk/reify ::fetch-libries
|
(ptk/reify ::fetch-libries
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ _ _]
|
||||||
(let [features (features/get-team-enabled-features state)]
|
(->> (rp/cmd! :get-file-libraries {:file-id file-id})
|
||||||
(->> (rp/cmd! :get-file-libraries {:file-id file-id})
|
(rx/mapcat
|
||||||
(rx/mapcat
|
(fn [libraries]
|
||||||
(fn [libraries]
|
(rx/concat
|
||||||
(rx/concat
|
(rx/of (libraries-fetched file-id libraries))
|
||||||
(rx/of (libraries-fetched file-id libraries))
|
(rx/merge
|
||||||
(rx/merge
|
(->> (rx/from libraries)
|
||||||
(->> (rx/from libraries)
|
(rx/merge-map
|
||||||
(rx/merge-map
|
(fn [{:keys [id synced-at]}]
|
||||||
(fn [{:keys [id synced-at]}]
|
(->> (rp/cmd! :get-file {:id id :features features})
|
||||||
(->> (rp/cmd! :get-file {:id id :features features})
|
(rx/map #(assoc % :synced-at synced-at :library-of file-id)))))
|
||||||
(rx/map #(assoc % :synced-at synced-at :library-of file-id)))))
|
(rx/mapcat resolve-file)
|
||||||
(rx/mapcat resolve-file)
|
(rx/map library-resolved))
|
||||||
(rx/map library-resolved))
|
(->> (rx/from libraries)
|
||||||
(->> (rx/from libraries)
|
(rx/map :id)
|
||||||
(rx/map :id)
|
(rx/mapcat (fn [file-id]
|
||||||
(rx/mapcat (fn [file-id]
|
(rp/cmd! :get-file-object-thumbnails {:file-id file-id :tag "component"})))
|
||||||
(rp/cmd! :get-file-object-thumbnails {:file-id file-id :tag "component"})))
|
(rx/map dwl/library-thumbnails-fetched)))
|
||||||
(rx/map dwl/library-thumbnails-fetched)))
|
(rx/of (check-libraries-synchronozation file-id libraries)))))))))
|
||||||
(rx/of (check-libraries-synchronozation file-id libraries))))))))))
|
|
||||||
|
|
||||||
(defn- workspace-initialized
|
(defn- workspace-initialized
|
||||||
[file-id]
|
[file-id]
|
||||||
@ -246,28 +245,16 @@
|
|||||||
(fbs/fix-broken-shapes)))))
|
(fbs/fix-broken-shapes)))))
|
||||||
|
|
||||||
(defn- bundle-fetched
|
(defn- bundle-fetched
|
||||||
[{:keys [features file thumbnails]}]
|
[{:keys [file file-id thumbnails] :as bundle}]
|
||||||
(ptk/reify ::bundle-fetched
|
(ptk/reify ::bundle-fetched
|
||||||
IDeref
|
IDeref
|
||||||
(-deref [_]
|
(-deref [_] bundle)
|
||||||
{:features features
|
|
||||||
:file file
|
|
||||||
:thumbnails thumbnails})
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [file-id (:id file)]
|
(-> state
|
||||||
(-> state
|
(assoc :thumbnails thumbnails)
|
||||||
(assoc :thumbnails thumbnails)
|
(update :files assoc file-id file)))))
|
||||||
(update :files assoc file-id file))))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [team-id (:current-team-id state)
|
|
||||||
file-id (:id file)]
|
|
||||||
(rx/of (dwn/initialize team-id file-id)
|
|
||||||
(dwsl/initialize-shape-layout)
|
|
||||||
(fetch-libraries file-id))))))
|
|
||||||
|
|
||||||
(defn zoom-to-frame
|
(defn zoom-to-frame
|
||||||
[]
|
[]
|
||||||
@ -296,46 +283,30 @@
|
|||||||
|
|
||||||
(defn- fetch-bundle
|
(defn- fetch-bundle
|
||||||
"Multi-stage file bundle fetch coordinator"
|
"Multi-stage file bundle fetch coordinator"
|
||||||
[file-id]
|
[file-id features]
|
||||||
(ptk/reify ::fetch-bundle
|
(ptk/reify ::fetch-bundle
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ _ stream]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)]
|
||||||
render-wasm? (contains? features "render-wasm/v1")
|
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features})
|
||||||
stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
(get-file-object-thumbnails file-id))
|
||||||
team-id (:current-team-id state)]
|
(rx/take 1)
|
||||||
|
(rx/mapcat
|
||||||
(->> (rx/concat
|
(fn [[file thumbnails]]
|
||||||
;; Firstly load wasm module if it is enabled and fonts
|
(->> (resolve-file file)
|
||||||
(rx/merge
|
(rx/map (fn [file]
|
||||||
(if ^boolean render-wasm?
|
{:file file
|
||||||
(->> (rx/from @wasm/module)
|
:file-id file-id
|
||||||
(rx/ignore))
|
:features features
|
||||||
(rx/empty))
|
:thumbnails thumbnails})))))
|
||||||
|
(rx/map bundle-fetched)
|
||||||
(->> stream
|
|
||||||
(rx/filter (ptk/type? ::df/fonts-loaded))
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/ignore))
|
|
||||||
(rx/of (df/fetch-fonts team-id)))
|
|
||||||
|
|
||||||
;; Then fetch file and thumbnails
|
|
||||||
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features})
|
|
||||||
(get-file-object-thumbnails file-id))
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/mapcat
|
|
||||||
(fn [[file thumbnails]]
|
|
||||||
(->> (resolve-file file)
|
|
||||||
(rx/map (fn [file]
|
|
||||||
{:file file
|
|
||||||
:features features
|
|
||||||
:thumbnails thumbnails})))))
|
|
||||||
(rx/map bundle-fetched)))
|
|
||||||
(rx/take-until stopper-s))))))
|
(rx/take-until stopper-s))))))
|
||||||
|
|
||||||
(defn initialize-workspace
|
(defn initialize-workspace
|
||||||
[file-id]
|
[team-id file-id]
|
||||||
|
(assert (uuid? team-id) "expected valud uuid for `team-id`")
|
||||||
(assert (uuid? file-id) "expected valud uuid for `file-id`")
|
(assert (uuid? file-id) "expected valud uuid for `file-id`")
|
||||||
|
|
||||||
(ptk/reify ::initialize-workspace
|
(ptk/reify ::initialize-workspace
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
@ -347,24 +318,51 @@
|
|||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(log/debug :hint "initialize-workspace" :file-id (dm/str file-id))
|
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
rparams (rt/get-params state)
|
||||||
rparams (rt/get-params state)]
|
features (features/get-enabled-features state team-id)
|
||||||
|
render-wasm? (contains? features "render-wasm/v1")]
|
||||||
|
|
||||||
|
(log/debug :hint "initialize-workspace"
|
||||||
|
:team-id (dm/str team-id)
|
||||||
|
:file-id (dm/str file-id))
|
||||||
|
|
||||||
(->> (rx/merge
|
(->> (rx/merge
|
||||||
(rx/of (ntf/hide)
|
(rx/concat
|
||||||
(dcmt/retrieve-comment-threads file-id)
|
;; Fetch all essential data that should be loaded before the file
|
||||||
(dcmt/fetch-profiles)
|
(rx/merge
|
||||||
(fetch-bundle file-id))
|
(if ^boolean render-wasm?
|
||||||
|
(->> (rx/from @wasm/module)
|
||||||
|
(rx/ignore))
|
||||||
|
(rx/empty))
|
||||||
|
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? ::df/fonts-loaded))
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/ignore))
|
||||||
|
|
||||||
|
(rx/of (ntf/hide)
|
||||||
|
(dcmt/retrieve-comment-threads file-id)
|
||||||
|
(dcmt/fetch-profiles)
|
||||||
|
(df/fetch-fonts team-id)))
|
||||||
|
|
||||||
|
;; Once the essential data is fetched, lets proceed to
|
||||||
|
;; fetch teh file bunldle
|
||||||
|
(rx/of (fetch-bundle file-id features)))
|
||||||
|
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? ::bundle-fetched))
|
(rx/filter (ptk/type? ::bundle-fetched))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/mapcat (fn [{:keys [file]}]
|
(rx/mapcat
|
||||||
(rx/of (dpj/initialize-project (:project-id file))
|
(fn [{:keys [file]}]
|
||||||
(-> (workspace-initialized file-id)
|
(rx/of (dpj/initialize-project (:project-id file))
|
||||||
(with-meta {:file-id file-id}))))))
|
(dwn/initialize team-id file-id)
|
||||||
|
(dwsl/initialize-shape-layout)
|
||||||
|
(fetch-libraries file-id features)
|
||||||
|
(-> (workspace-initialized file-id)
|
||||||
|
(with-meta {:team-id team-id
|
||||||
|
:file-id file-id}))))))
|
||||||
|
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? ::dps/persistence-notification))
|
(rx/filter (ptk/type? ::dps/persistence-notification))
|
||||||
@ -410,7 +408,7 @@
|
|||||||
(unchecked-set ug/global "name" name)))))
|
(unchecked-set ug/global "name" name)))))
|
||||||
|
|
||||||
(defn finalize-workspace
|
(defn finalize-workspace
|
||||||
[file-id]
|
[_team-id file-id]
|
||||||
(ptk/reify ::finalize-workspace
|
(ptk/reify ::finalize-workspace
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
@ -430,7 +428,6 @@
|
|||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [project-id (:current-project-id state)]
|
(let [project-id (:current-project-id state)]
|
||||||
|
|
||||||
(rx/of (dwn/finalize file-id)
|
(rx/of (dwn/finalize file-id)
|
||||||
(dpj/finalize-project project-id)
|
(dpj/finalize-project project-id)
|
||||||
(dwsl/finalize-shape-layout)
|
(dwsl/finalize-shape-layout)
|
||||||
@ -444,14 +441,13 @@
|
|||||||
(ptk/reify ::reload-current-file
|
(ptk/reify ::reload-current-file
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [file-id (:current-file-id state)]
|
(let [file-id (:current-file-id state)
|
||||||
(rx/of (initialize-workspace file-id))))))
|
team-id (:current-team-id state)]
|
||||||
|
(rx/of (initialize-workspace team-id file-id))))))
|
||||||
|
|
||||||
;; Make this event callable through dynamic resolution
|
;; Make this event callable through dynamic resolution
|
||||||
(defmethod ptk/resolve ::reload-current-file [_ _] (reload-current-file))
|
(defmethod ptk/resolve ::reload-current-file [_ _] (reload-current-file))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(def ^:private xf:collect-file-media
|
(def ^:private xf:collect-file-media
|
||||||
"Resolve and collect all file media on page objects"
|
"Resolve and collect all file media on page objects"
|
||||||
(comp (map second)
|
(comp (map second)
|
||||||
@ -488,18 +484,25 @@
|
|||||||
(defn initialize-page
|
(defn initialize-page
|
||||||
[file-id page-id]
|
[file-id page-id]
|
||||||
(assert (uuid? file-id) "expected valid uuid for `file-id`")
|
(assert (uuid? file-id) "expected valid uuid for `file-id`")
|
||||||
|
(assert (uuid? page-id) "expected valid uuid for `page-id`")
|
||||||
|
|
||||||
(ptk/reify ::initialize-page
|
(ptk/reify ::initialize-page
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(if-let [page (dsh/lookup-page state file-id page-id)]
|
(if-let [page (dsh/lookup-page state file-id page-id)]
|
||||||
(rx/concat (rx/of (initialize-page* file-id page-id page)
|
(rx/concat
|
||||||
(dwth/watch-state-changes file-id page-id)
|
(rx/of (initialize-page* file-id page-id page)
|
||||||
(dwl/watch-component-changes))
|
(dwth/watch-state-changes file-id page-id)
|
||||||
(let [profile (:profile state)
|
(dwl/watch-component-changes))
|
||||||
props (get profile :props)]
|
(let [profile (:profile state)
|
||||||
(when (not (:workspace-visited props))
|
props (get profile :props)]
|
||||||
(rx/of (select-frame-tool file-id page-id)))))
|
(when (not (:workspace-visited props))
|
||||||
|
(rx/of (select-frame-tool file-id page-id)))))
|
||||||
|
|
||||||
|
;; NOTE: this redirect is necessary for cases where user
|
||||||
|
;; explicitly passes an non-existing page-id on the url
|
||||||
|
;; params, so on check it we can detect that there are no data
|
||||||
|
;; for the page and redirect user to an existing page
|
||||||
(rx/of (dcm/go-to-workspace :file-id file-id ::rt/replace true))))))
|
(rx/of (dcm/go-to-workspace :file-id file-id ::rt/replace true))))))
|
||||||
|
|
||||||
(defn finalize-page
|
(defn finalize-page
|
||||||
@ -1410,7 +1413,7 @@
|
|||||||
(let [objects (dsh/lookup-page-objects state)
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
selected (->> (dsh/lookup-selected state)
|
selected (->> (dsh/lookup-selected state)
|
||||||
(cfh/clean-loops objects))
|
(cfh/clean-loops objects))
|
||||||
features (-> (features/get-team-enabled-features state)
|
features (-> (get state :features)
|
||||||
(set/difference cfeat/frontend-only-features))
|
(set/difference cfeat/frontend-only-features))
|
||||||
|
|
||||||
file-id (:current-file-id state)
|
file-id (:current-file-id state)
|
||||||
@ -1648,9 +1651,10 @@
|
|||||||
objects (dsh/lookup-page-objects state)]
|
objects (dsh/lookup-page-objects state)]
|
||||||
(when-let [shape (get objects selected)]
|
(when-let [shape (get objects selected)]
|
||||||
(let [props (cts/extract-props shape)
|
(let [props (cts/extract-props shape)
|
||||||
features (-> (features/get-team-enabled-features state)
|
features (-> (get state :features)
|
||||||
(set/difference cfeat/frontend-only-features))
|
(set/difference cfeat/frontend-only-features))
|
||||||
version (-> (dsh/lookup-file state) :version)
|
version (-> (dsh/lookup-file state)
|
||||||
|
(get :version))
|
||||||
|
|
||||||
copy-data {:type :copied-props
|
copy-data {:type :copied-props
|
||||||
:features features
|
:features features
|
||||||
@ -1784,8 +1788,8 @@
|
|||||||
(ptk/reify ::paste-transit-shapes
|
(ptk/reify ::paste-transit-shapes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [file-id (:current-file-id state)
|
(let [file-id (:current-file-id state)
|
||||||
features (features/get-team-enabled-features state)]
|
features (get state :features)]
|
||||||
|
|
||||||
(when-not (paste-data-valid? pdata)
|
(when-not (paste-data-valid? pdata)
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
@ -1856,7 +1860,7 @@
|
|||||||
(ptk/reify ::paste-transit-props
|
(ptk/reify ::paste-transit-props
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [features (get state :features)
|
||||||
selected (dsh/lookup-selected state)]
|
selected (dsh/lookup-selected state)]
|
||||||
|
|
||||||
(when (paste-data-valid? pdata)
|
(when (paste-data-valid? pdata)
|
||||||
|
|||||||
@ -1398,7 +1398,7 @@
|
|||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)]
|
(let [features (get state :features)]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
||||||
|
|||||||
@ -65,7 +65,6 @@
|
|||||||
(->> (rx/from initmsg)
|
(->> (rx/from initmsg)
|
||||||
(rx/map dws/send))
|
(rx/map dws/send))
|
||||||
|
|
||||||
|
|
||||||
;; Subscribe to notifications of the subscription
|
;; Subscribe to notifications of the subscription
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? ::dws/message))
|
(rx/filter (ptk/type? ::dws/message))
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.data.persistence :as dwp]
|
[app.main.data.persistence :as dwp]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.thumbnails :as th]
|
[app.main.data.workspace.thumbnails :as th]
|
||||||
@ -97,7 +98,8 @@
|
|||||||
(ptk/reify ::restore-version
|
(ptk/reify ::restore-version
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [file-id (:current-file-id state)]
|
(let [file-id (:current-file-id state)
|
||||||
|
team-id (:current-team-id state)]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of ::dwp/force-persist
|
(rx/of ::dwp/force-persist
|
||||||
(dw/remove-layout-flag :document-history))
|
(dw/remove-layout-flag :document-history))
|
||||||
@ -106,7 +108,7 @@
|
|||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||||
(rx/tap #(th/clear-queue!))
|
(rx/tap #(th/clear-queue!))
|
||||||
(rx/map #(dw/initialize-workspace file-id)))
|
(rx/map #(dw/initialize-workspace team-id file-id)))
|
||||||
(case origin
|
(case origin
|
||||||
:version
|
:version
|
||||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))
|
(rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))
|
||||||
@ -200,21 +202,23 @@
|
|||||||
|
|
||||||
(ptk/reify ::restore-version-from-plugins
|
(ptk/reify ::restore-version-from-plugins
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ state _]
|
||||||
(rx/concat
|
(let [file (dsh/lookup-file state file-id)
|
||||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"})
|
team-id (or (:team-id file) (:current-file-id state))]
|
||||||
::dwp/force-persist)
|
(rx/concat
|
||||||
|
(rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"})
|
||||||
|
::dwp/force-persist)
|
||||||
|
|
||||||
;; FIXME: we should abstract this
|
;; FIXME: we should abstract this
|
||||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||||
(rx/filter #(or (nil? %) (= :saved %)))
|
(rx/filter #(or (nil? %) (= :saved %)))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||||
(rx/map #(dw/initialize-workspace file-id)))
|
(rx/map #(dw/initialize-workspace team-id file-id)))
|
||||||
|
|
||||||
(->> (rx/of 1)
|
(->> (rx/of 1)
|
||||||
(rx/tap resolve)
|
(rx/tap resolve)
|
||||||
(rx/ignore))))))
|
(rx/ignore)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
"A thin, frontend centric abstraction layer and collection of
|
"A thin, frontend centric abstraction layer and collection of
|
||||||
helpers for `app.common.features` namespace."
|
helpers for `app.common.features` namespace."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.render-wasm :as wasm]
|
[app.render-wasm :as wasm]
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
@ -26,38 +26,32 @@
|
|||||||
(cfeat/get-enabled-features cf/flags))
|
(cfeat/get-enabled-features cf/flags))
|
||||||
|
|
||||||
(defn get-enabled-features
|
(defn get-enabled-features
|
||||||
[state]
|
"An explicit lookup of enabled features for the current team"
|
||||||
(-> (get state :features-runtime #{})
|
[state team-id]
|
||||||
(set/intersection cfeat/no-migration-features)
|
(let [team (dm/get-in state [:teams team-id])]
|
||||||
(set/union global-enabled-features)))
|
|
||||||
|
|
||||||
(defn get-team-enabled-features
|
|
||||||
[state]
|
|
||||||
(let [runtime-features (:features-runtime state #{})
|
|
||||||
team-features (->> (:features-team state #{})
|
|
||||||
(into #{} cfeat/xf-remove-ephimeral))]
|
|
||||||
(-> global-enabled-features
|
(-> global-enabled-features
|
||||||
(set/union runtime-features)
|
(set/union (get state :features-runtime #{}))
|
||||||
(set/intersection cfeat/no-migration-features)
|
(set/intersection cfeat/no-migration-features)
|
||||||
(set/union team-features))))
|
(set/union (get team :features)))))
|
||||||
|
|
||||||
(def features-ref
|
|
||||||
(l/derived get-team-enabled-features st/state =))
|
|
||||||
|
|
||||||
(defn active-feature?
|
(defn active-feature?
|
||||||
"Given a state and feature, check if feature is enabled"
|
"Given a state and feature, check if feature is enabled."
|
||||||
[state feature]
|
[state feature]
|
||||||
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
(assert (contains? cfeat/supported-features feature) "feature not supported")
|
||||||
(or (contains? (get state :features-runtime) feature)
|
(let [runtime-features (get state :features-runtime)
|
||||||
(if (contains? cfeat/no-migration-features feature)
|
enabled-features (get state :features)]
|
||||||
(or (contains? global-enabled-features feature)
|
(or (contains? runtime-features feature)
|
||||||
(contains? (get state :features-team) feature))
|
(if (contains? cfeat/no-migration-features feature)
|
||||||
(contains? (get state :features-team state) feature))))
|
(or (contains? global-enabled-features feature)
|
||||||
|
(contains? enabled-features feature))
|
||||||
|
(contains? enabled-features feature)))))
|
||||||
|
|
||||||
|
(def ^:private features-ref
|
||||||
|
(l/derived (l/key :features) st/state))
|
||||||
|
|
||||||
(defn use-feature
|
(defn use-feature
|
||||||
"A react hook that checks if feature is currently enabled"
|
"A react hook that checks if feature is currently enabled"
|
||||||
[feature]
|
[feature]
|
||||||
(assert (contains? cfeat/supported-features feature) "Not supported feature")
|
|
||||||
(let [enabled-features (mf/deref features-ref)]
|
(let [enabled-features (mf/deref features-ref)]
|
||||||
(contains? enabled-features feature)))
|
(contains? enabled-features feature)))
|
||||||
|
|
||||||
@ -71,14 +65,16 @@
|
|||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
(assert (contains? cfeat/supported-features feature) "not supported feature")
|
||||||
(update state :features-runtime (fn [features]
|
(-> state
|
||||||
(if (contains? features feature)
|
(update :features-runtime (fn [features]
|
||||||
(do
|
(if (contains? features feature)
|
||||||
(log/trc :hint "feature disabled" :feature feature)
|
(do
|
||||||
(disj features feature))
|
(log/trc :hint "feature disabled" :feature feature)
|
||||||
(do
|
(disj features feature))
|
||||||
(log/trc :hint "feature enabled" :feature feature)
|
(do
|
||||||
(conj features feature))))))))
|
(log/trc :hint "feature enabled" :feature feature)
|
||||||
|
(conj features feature)))))
|
||||||
|
(update :features-runtime set/intersection cfeat/no-migration-features)))))
|
||||||
|
|
||||||
(defn enable-feature
|
(defn enable-feature
|
||||||
[feature]
|
[feature]
|
||||||
@ -90,46 +86,28 @@
|
|||||||
state
|
state
|
||||||
(do
|
(do
|
||||||
(log/trc :hint "feature enabled" :feature feature)
|
(log/trc :hint "feature enabled" :feature feature)
|
||||||
(update state :features-runtime (fnil conj #{}) feature))))))
|
(-> state
|
||||||
|
(update :features-runtime (fnil conj #{}) feature)
|
||||||
|
(update :features-runtime set/intersection cfeat/no-migration-features)))))))
|
||||||
|
|
||||||
(defn initialize
|
(defn initialize
|
||||||
([] (initialize #{}))
|
[features]
|
||||||
([team-features]
|
(ptk/reify ::initialize
|
||||||
(assert (set? team-features) "expected a set of features")
|
ptk/UpdateEvent
|
||||||
(assert (every? string? team-features) "expected a set of strings")
|
(update [_ state]
|
||||||
|
(let [features (-> global-enabled-features
|
||||||
|
(set/union (get state :features-runtime #{}))
|
||||||
|
(set/union features))]
|
||||||
|
(assoc state :features features)))
|
||||||
|
|
||||||
(ptk/reify ::initialize
|
ptk/EffectEvent
|
||||||
ptk/UpdateEvent
|
(effect [_ state _]
|
||||||
(update [_ state]
|
(let [features (get state :features)]
|
||||||
(let [runtime-features (get state :features/runtime #{})
|
(if (contains? features "render-wasm/v1")
|
||||||
team-features (into #{}
|
(wasm/initialize true)
|
||||||
cfeat/xf-supported-features
|
(wasm/initialize false))
|
||||||
team-features)]
|
|
||||||
(-> state
|
|
||||||
(assoc :features-runtime runtime-features)
|
|
||||||
(assoc :features-team team-features))))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
(log/inf :hint "initialized"
|
||||||
(watch [_ _ _]
|
:enabled (str/join "," features)
|
||||||
(when *assert*
|
:runtime (str/join "," (:features-runtime state)))))))
|
||||||
(->> (rx/from cfeat/no-migration-features)
|
|
||||||
;; text editor v2 isn't enabled by default even in devenv
|
|
||||||
;; wasm render v1 isn't enabled by default even in devenv
|
|
||||||
(rx/filter #(not (or (contains? cfeat/backend-only-features %)
|
|
||||||
(= "text-editor/v2" %)
|
|
||||||
(= "render-wasm/v1" %)
|
|
||||||
(= "design-tokens/v1" %))))
|
|
||||||
(rx/observe-on :async)
|
|
||||||
(rx/map enable-feature))))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
|
||||||
(effect [_ state _]
|
|
||||||
(let [features (get-team-enabled-features state)]
|
|
||||||
(if (contains? features "render-wasm/v1")
|
|
||||||
(wasm/initialize true)
|
|
||||||
(wasm/initialize false))
|
|
||||||
|
|
||||||
(log/inf :hint "initialized"
|
|
||||||
:enabled (str/join "," features)
|
|
||||||
:runtime (str/join "," (:features-runtime state))))))))
|
|
||||||
|
|
||||||
|
|||||||
@ -370,6 +370,6 @@
|
|||||||
(if edata
|
(if edata
|
||||||
[:> static/exception-page* {:data edata :route route}]
|
[:> static/exception-page* {:data edata :route route}]
|
||||||
[:> error-boundary* {:fallback static/internal-error*}
|
[:> error-boundary* {:fallback static/internal-error*}
|
||||||
[:& notifications/current-notification]
|
[:> notifications/current-notification*]
|
||||||
(when route
|
(when route
|
||||||
[:> page* {:route route :profile profile}])])]]))
|
[:> page* {:route route :profile profile}])])]]))
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
[app.main.data.notifications :as ntf]
|
[app.main.data.notifications :as ntf]
|
||||||
[app.main.data.project :as dpj]
|
[app.main.data.project :as dpj]
|
||||||
[app.main.data.team :as dtm]
|
[app.main.data.team :as dtm]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[app.main.rasterizer :as thr]
|
[app.main.rasterizer :as thr]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
@ -60,7 +59,7 @@
|
|||||||
(->> (wrk/ask! {:cmd :thumbnails/generate-for-file
|
(->> (wrk/ask! {:cmd :thumbnails/generate-for-file
|
||||||
:revn revn
|
:revn revn
|
||||||
:file-id file-id
|
:file-id file-id
|
||||||
:features (features/get-team-enabled-features @st/state)})
|
:features (get @st/state :features)})
|
||||||
(rx/mapcat (fn [{:keys [fonts] :as result}]
|
(rx/mapcat (fn [{:keys [fonts] :as result}]
|
||||||
(->> (fonts/render-font-styles fonts)
|
(->> (fonts/render-font-styles fonts)
|
||||||
(rx/map (fn [styles]
|
(rx/map (fn [styles]
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.notifications :as ntf]
|
[app.main.data.notifications :as ntf]
|
||||||
[app.main.errors :as errors]
|
[app.main.errors :as errors]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||||
@ -162,29 +161,32 @@
|
|||||||
|
|
||||||
(defn- analyze-entries
|
(defn- analyze-entries
|
||||||
[state entries]
|
[state entries]
|
||||||
(->> (uw/ask-many!
|
(let [features (get @st/state :features)]
|
||||||
{:cmd :analyze-import
|
(->> (uw/ask-many!
|
||||||
:files entries
|
{:cmd :analyze-import
|
||||||
:features @features/features-ref})
|
:files entries
|
||||||
(rx/mapcat #(rx/delay emit-delay (rx/of %)))
|
:features features})
|
||||||
(rx/filter some?)
|
(rx/mapcat #(rx/delay emit-delay (rx/of %)))
|
||||||
(rx/subs!
|
(rx/filter some?)
|
||||||
(fn [message]
|
(rx/subs!
|
||||||
(swap! state update-with-analyze-result message)))))
|
(fn [message]
|
||||||
|
(swap! state update-with-analyze-result message))))))
|
||||||
|
|
||||||
(defn- import-files
|
(defn- import-files
|
||||||
[state project-id entries]
|
[state project-id entries]
|
||||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-files"
|
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-files"
|
||||||
:num-files (count entries)}))
|
:num-files (count entries)}))
|
||||||
(->> (uw/ask-many!
|
|
||||||
{:cmd :import-files
|
(let [features (get @st/state :features)]
|
||||||
:project-id project-id
|
(->> (uw/ask-many!
|
||||||
:files entries
|
{:cmd :import-files
|
||||||
:features @features/features-ref})
|
:project-id project-id
|
||||||
(rx/filter (comp uuid? :file-id))
|
:files entries
|
||||||
(rx/subs!
|
:features features})
|
||||||
(fn [message]
|
(rx/filter (comp uuid? :file-id))
|
||||||
(swap! state update-entry-status message)))))
|
(rx/subs!
|
||||||
|
(fn [message]
|
||||||
|
(swap! state update-entry-status message))))))
|
||||||
|
|
||||||
(mf/defc import-entry*
|
(mf/defc import-entry*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
|
|||||||
@ -7,8 +7,8 @@
|
|||||||
(ns app.main.ui.dashboard.placeholder
|
(ns app.main.ui.dashboard.placeholder
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.config :as cf]
|
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.dashboard.import :as udi]
|
[app.main.ui.dashboard.import :as udi]
|
||||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||||
@ -55,9 +55,10 @@
|
|||||||
(mf/deps create-fn)
|
(mf/deps create-fn)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(create-fn "dashboard:empty-folder-placeholder")))
|
(create-fn "dashboard:empty-folder-placeholder")))
|
||||||
show-text (mf/use-state nil)
|
show-text (mf/use-state nil)
|
||||||
on-mouse-enter (mf/use-fn #(reset! show-text true))
|
on-mouse-enter (mf/use-fn #(reset! show-text true))
|
||||||
on-mouse-leave (mf/use-fn #(reset! show-text nil))]
|
on-mouse-leave (mf/use-fn #(reset! show-text nil))
|
||||||
|
files (mf/deref refs/files)]
|
||||||
(cond
|
(cond
|
||||||
(true? dragging?)
|
(true? dragging?)
|
||||||
[:ul
|
[:ul
|
||||||
@ -79,18 +80,14 @@
|
|||||||
:tag-name "span"}])]
|
:tag-name "span"}])]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(if (cf/external-feature-flag "add-file-02" "test")
|
(if (= (count files) 0)
|
||||||
[:> empty-placeholder-projects* {:on-create on-click :on-finish-import on-finish-import :project-id project-id}]
|
[:> empty-placeholder-projects* {:on-create on-click :on-finish-import on-finish-import :project-id project-id}]
|
||||||
[:div {:class (stl/css :grid-empty-placeholder)}
|
[:div {:class (stl/css :grid-empty-placeholder)}
|
||||||
(if (cf/external-feature-flag "add-file-01" "test")
|
[:button {:class (stl/css :create-new)
|
||||||
[:button {:class (stl/css :create-new)
|
:on-click on-click
|
||||||
:on-click on-click
|
:on-mouse-enter on-mouse-enter
|
||||||
:on-mouse-enter on-mouse-enter
|
:on-mouse-leave on-mouse-leave}
|
||||||
:on-mouse-leave on-mouse-leave}
|
(if @show-text (tr "dashboard.empty-project.create") i/add)]]))))
|
||||||
(if @show-text (tr "dashboard.empty-project.create") i/add)]
|
|
||||||
[:button {:class (stl/css :create-new)
|
|
||||||
:on-click on-click}
|
|
||||||
i/add])]))))
|
|
||||||
|
|
||||||
(mf/defc loading-placeholder
|
(mf/defc loading-placeholder
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import * as IconStories from "./icon.stories"
|
|||||||
|
|
||||||
# Iconography
|
# Iconography
|
||||||
|
|
||||||
See the [list of all available icons](?path=/story/foundations-icons--all-icons).
|
See the [list of all available icons](?path=/story/foundations-assets-icon--all).
|
||||||
|
|
||||||
## Variants
|
## Variants
|
||||||
|
|
||||||
|
|||||||
@ -17,10 +17,10 @@
|
|||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
[:variant {:optional true}
|
[:variant {:optional true}
|
||||||
[:maybe [:enum "default" "error"]]]
|
[:maybe [:enum "default" "error"]]]
|
||||||
[:accept-label {:optional true} :string]
|
[:accept-label {:optional true} [:maybe :string]]
|
||||||
[:cancel-label {:optional true} :string]
|
[:cancel-label {:optional true} [:maybe :string]]
|
||||||
[:on-accept {:optional true} [:fn fn?]]
|
[:on-accept {:optional true} [:maybe [:fn fn?]]]
|
||||||
[:on-cancel {:optional true} [:fn fn?]]])
|
[:on-cancel {:optional true} [:maybe [:fn fn?]]]])
|
||||||
|
|
||||||
(mf/defc actionable*
|
(mf/defc actionable*
|
||||||
{::mf/schema schema:actionable}
|
{::mf/schema schema:actionable}
|
||||||
@ -45,9 +45,13 @@
|
|||||||
|
|
||||||
[:> :aside props
|
[:> :aside props
|
||||||
[:div {:class (stl/css :notification-message)} children]
|
[:div {:class (stl/css :notification-message)} children]
|
||||||
[:> button* {:variant "secondary"
|
|
||||||
:on-click on-cancel}
|
(when cancel-label
|
||||||
cancel-label]
|
[:> button* {:variant "secondary"
|
||||||
[:> button* {:variant (if (= variant "default") "primary" "destructive")
|
:on-click on-cancel}
|
||||||
:on-click on-accept}
|
cancel-label])
|
||||||
accept-label]]))
|
|
||||||
|
(when accept-label
|
||||||
|
[:> button* {:variant (if (= variant "default") "primary" "destructive")
|
||||||
|
:on-click on-accept}
|
||||||
|
accept-label])]))
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(def ref:notification
|
(def ^:private ref:notification
|
||||||
(l/derived :notification st/state))
|
(l/derived :notification st/state))
|
||||||
|
|
||||||
(mf/defc current-notification
|
(mf/defc current-notification*
|
||||||
[]
|
[]
|
||||||
(let [notification (mf/deref ref:notification)
|
(let [notification (mf/deref ref:notification)
|
||||||
on-close (mf/use-fn #(st/emit! (ntf/hide)))
|
on-close (mf/use-fn #(st/emit! (ntf/hide)))
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.common :as dcm]
|
[app.main.data.common :as dcm]
|
||||||
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.data.persistence :as dps]
|
[app.main.data.persistence :as dps]
|
||||||
[app.main.data.plugins :as dpl]
|
[app.main.data.plugins :as dpl]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
@ -45,9 +46,10 @@
|
|||||||
(mf/defc workspace-content*
|
(mf/defc workspace-content*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
[{:keys [file layout page wglobal]}]
|
[{:keys [file layout page wglobal]}]
|
||||||
|
|
||||||
(let [palete-size (mf/use-state nil)
|
(let [palete-size (mf/use-state nil)
|
||||||
selected (mf/deref refs/selected-shapes)
|
selected (mf/deref refs/selected-shapes)
|
||||||
page-id (:id page)
|
page-id (get page :id)
|
||||||
|
|
||||||
{:keys [vport] :as wlocal} (mf/deref refs/workspace-local)
|
{:keys [vport] :as wlocal} (mf/deref refs/workspace-local)
|
||||||
{:keys [options-mode]} wglobal
|
{:keys [options-mode]} wglobal
|
||||||
@ -120,10 +122,46 @@
|
|||||||
:overlay true
|
:overlay true
|
||||||
:file-loading true}])
|
:file-loading true}])
|
||||||
|
|
||||||
|
(defn- make-team-ref
|
||||||
|
[team-id]
|
||||||
|
(l/derived (fn [state]
|
||||||
|
(let [teams (get state :teams)]
|
||||||
|
(get teams team-id)))
|
||||||
|
st/state))
|
||||||
|
|
||||||
|
(defn- make-file-ref
|
||||||
|
[file-id]
|
||||||
|
(l/derived (fn [state]
|
||||||
|
;; NOTE: for ensure ordering of execution, we need to
|
||||||
|
;; wait the file initialization completly success until
|
||||||
|
;; mark this file availablea and unlock the rendering
|
||||||
|
;; of the following components
|
||||||
|
(when (= (get state :current-file-id) file-id)
|
||||||
|
(let [files (get state :files)
|
||||||
|
file (get files file-id)]
|
||||||
|
(-> file
|
||||||
|
(dissoc :data)
|
||||||
|
(assoc ::has-data (contains? file :data))))))
|
||||||
|
st/state))
|
||||||
|
|
||||||
|
(defn- make-page-ref
|
||||||
|
[file-id page-id]
|
||||||
|
(l/derived (fn [state]
|
||||||
|
(let [current-page-id (get state :current-page-id)]
|
||||||
|
;; NOTE: for ensure ordering of execution, we need to
|
||||||
|
;; wait the page initialization completly success until
|
||||||
|
;; mark this file availablea and unlock the rendering
|
||||||
|
;; of the following components
|
||||||
|
(when (= current-page-id page-id)
|
||||||
|
(dsh/lookup-page state file-id page-id))))
|
||||||
|
st/state))
|
||||||
|
|
||||||
(mf/defc workspace-page*
|
(mf/defc workspace-page*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
[{:keys [page-id file-id file layout wglobal]}]
|
[{:keys [page-id file-id file layout wglobal]}]
|
||||||
(let [page (mf/deref refs/workspace-page)]
|
(let [page-ref (mf/with-memo [file-id page-id]
|
||||||
|
(make-page-ref file-id page-id))
|
||||||
|
page (mf/deref page-ref)]
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(let [focus-out #(st/emit! (dw/workspace-focus-lost))
|
(let [focus-out #(st/emit! (dw/workspace-focus-lost))
|
||||||
@ -133,8 +171,7 @@
|
|||||||
(mf/with-effect [file-id page-id]
|
(mf/with-effect [file-id page-id]
|
||||||
(st/emit! (dw/initialize-page file-id page-id))
|
(st/emit! (dw/initialize-page file-id page-id))
|
||||||
(fn []
|
(fn []
|
||||||
(when page-id
|
(st/emit! (dw/finalize-page file-id page-id))))
|
||||||
(st/emit! (dw/finalize-page file-id page-id)))))
|
|
||||||
|
|
||||||
(if (some? page)
|
(if (some? page)
|
||||||
[:> workspace-content* {:file file
|
[:> workspace-content* {:file file
|
||||||
@ -143,18 +180,9 @@
|
|||||||
:layout layout}]
|
:layout layout}]
|
||||||
[:> workspace-loader*])))
|
[:> workspace-loader*])))
|
||||||
|
|
||||||
(def ^:private ref:file-without-data
|
|
||||||
(l/derived (fn [file]
|
|
||||||
(-> file
|
|
||||||
(dissoc :data)
|
|
||||||
(assoc ::has-data (contains? file :data))))
|
|
||||||
refs/file
|
|
||||||
=))
|
|
||||||
|
|
||||||
(mf/defc workspace*
|
(mf/defc workspace*
|
||||||
{::mf/props :obj
|
{::mf/wrap [mf/memo]}
|
||||||
::mf/wrap [mf/memo]}
|
[{:keys [team-id project-id file-id page-id layout-name]}]
|
||||||
[{:keys [project-id file-id page-id layout-name]}]
|
|
||||||
|
|
||||||
(let [file-id (hooks/use-equal-memo file-id)
|
(let [file-id (hooks/use-equal-memo file-id)
|
||||||
page-id (hooks/use-equal-memo page-id)
|
page-id (hooks/use-equal-memo page-id)
|
||||||
@ -162,8 +190,15 @@
|
|||||||
layout (mf/deref refs/workspace-layout)
|
layout (mf/deref refs/workspace-layout)
|
||||||
wglobal (mf/deref refs/workspace-global)
|
wglobal (mf/deref refs/workspace-global)
|
||||||
|
|
||||||
team (mf/deref refs/team)
|
team-ref (mf/with-memo [team-id]
|
||||||
file (mf/deref ref:file-without-data)
|
(make-team-ref team-id))
|
||||||
|
file-ref (mf/with-memo [file-id]
|
||||||
|
(make-file-ref file-id))
|
||||||
|
|
||||||
|
team (mf/deref team-ref)
|
||||||
|
file (mf/deref file-ref)
|
||||||
|
|
||||||
|
file-loaded? (get file ::has-data)
|
||||||
|
|
||||||
file-name (:name file)
|
file-name (:name file)
|
||||||
permissions (:permissions team)
|
permissions (:permissions team)
|
||||||
@ -187,14 +222,14 @@
|
|||||||
(when file-name
|
(when file-name
|
||||||
(dom/set-html-title (tr "title.workspace" file-name))))
|
(dom/set-html-title (tr "title.workspace" file-name))))
|
||||||
|
|
||||||
(mf/with-effect [file-id]
|
(mf/with-effect [team-id file-id]
|
||||||
(st/emit! (dw/initialize-workspace file-id))
|
(st/emit! (dw/initialize-workspace team-id file-id))
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! ::dps/force-persist
|
(st/emit! ::dps/force-persist
|
||||||
(dw/finalize-workspace file-id))))
|
(dw/finalize-workspace team-id file-id))))
|
||||||
|
|
||||||
(mf/with-effect [file page-id]
|
(mf/with-effect [file-id page-id file-loaded?]
|
||||||
(when-not page-id
|
(when (and file-loaded? (not page-id))
|
||||||
(st/emit! (dcm/go-to-workspace :file-id file-id ::rt/replace true))))
|
(st/emit! (dcm/go-to-workspace :file-id file-id ::rt/replace true))))
|
||||||
|
|
||||||
[:> (mf/provider ctx/current-project-id) {:value project-id}
|
[:> (mf/provider ctx/current-project-id) {:value project-id}
|
||||||
@ -208,8 +243,7 @@
|
|||||||
:style {:background-color background-color
|
:style {:background-color background-color
|
||||||
:touch-action "none"}}
|
:touch-action "none"}}
|
||||||
[:> context-menu*]
|
[:> context-menu*]
|
||||||
|
(if (and file-loaded? page-id)
|
||||||
(if (::has-data file)
|
|
||||||
[:> workspace-page*
|
[:> workspace-page*
|
||||||
{:page-id page-id
|
{:page-id page-id
|
||||||
:file-id file-id
|
:file-id file-id
|
||||||
|
|||||||
@ -17,8 +17,10 @@
|
|||||||
[]
|
[]
|
||||||
(let [worker (uw/init cf/worker-uri err/on-error)]
|
(let [worker (uw/init cf/worker-uri err/on-error)]
|
||||||
(uw/ask! worker {:cmd :configure
|
(uw/ask! worker {:cmd :configure
|
||||||
:key :public-uri
|
:config {:public-uri cf/public-uri
|
||||||
:val cf/public-uri})
|
:build-data cf/build-date
|
||||||
|
:version cf/version}})
|
||||||
|
|
||||||
(set! instance worker)))
|
(set! instance worker)))
|
||||||
|
|
||||||
(defn ask!
|
(defn ask!
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
[app.main.data.exports.files :as exports.files]
|
[app.main.data.exports.files :as exports.files]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.versions :as dwv]
|
[app.main.data.workspace.versions :as dwv]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
@ -237,7 +236,7 @@
|
|||||||
|
|
||||||
:else
|
:else
|
||||||
(let [file (u/locate-file id)
|
(let [file (u/locate-file id)
|
||||||
features (features/get-team-enabled-features @st/state)
|
features (:features @st/state)
|
||||||
team-id (:current-team-id @st/state)
|
team-id (:current-team-id @st/state)
|
||||||
format (case format
|
format (case format
|
||||||
"zip" :legacy-zip
|
"zip" :legacy-zip
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (features/initialize (or features #{}))))))
|
(rx/of (features/initialize features)))))
|
||||||
|
|
||||||
(defn- fetch-team
|
(defn- fetch-team
|
||||||
[& {:keys [file-id]}]
|
[& {:keys [file-id]}]
|
||||||
@ -98,7 +98,7 @@
|
|||||||
(ptk/reify ::fetch-objects-bundle
|
(ptk/reify ::fetch-objects-bundle
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)]
|
(let [features (get state :features)]
|
||||||
(->> (rx/zip
|
(->> (rx/zip
|
||||||
(repo/cmd! :get-font-variants {:file-id file-id :share-id share-id})
|
(repo/cmd! :get-font-variants {:file-id file-id :share-id share-id})
|
||||||
(repo/cmd! :get-page {:file-id file-id
|
(repo/cmd! :get-page {:file-id file-id
|
||||||
@ -237,7 +237,7 @@
|
|||||||
(ptk/reify ::fetch-components-bundle
|
(ptk/reify ::fetch-components-bundle
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)]
|
(let [features (get state :features)]
|
||||||
(->> (repo/cmd! :get-file {:id file-id :features features})
|
(->> (repo/cmd! :get-file {:id file-id :features features})
|
||||||
(rx/map (fn [file] #(assoc % :file file))))))))
|
(rx/map (fn [file] #(assoc % :file file))))))))
|
||||||
|
|
||||||
@ -309,7 +309,6 @@
|
|||||||
|
|
||||||
(defn ^:export init
|
(defn ^:export init
|
||||||
[]
|
[]
|
||||||
(st/emit! (features/initialize))
|
|
||||||
(init-ui))
|
(init-ui))
|
||||||
|
|
||||||
(defn reinit
|
(defn reinit
|
||||||
|
|||||||
@ -104,7 +104,9 @@
|
|||||||
|
|
||||||
(defn send!
|
(defn send!
|
||||||
[ws msg]
|
[ws msg]
|
||||||
(-send ws (t/encode-str msg)))
|
(if *assert*
|
||||||
|
(-send ws (t/encode-str msg {:type :json-verbose}))
|
||||||
|
(-send ws (t/encode-str msg))))
|
||||||
|
|
||||||
(defn close!
|
(defn close!
|
||||||
[ws]
|
[ws]
|
||||||
|
|||||||
@ -135,15 +135,15 @@
|
|||||||
(rx/debounce 1)
|
(rx/debounce 1)
|
||||||
|
|
||||||
(rx/subs! (fn [[messages dropped last]]
|
(rx/subs! (fn [[messages dropped last]]
|
||||||
;; Send back the dropped messages replies
|
;; Send back the dropped messages replies
|
||||||
(doseq [msg dropped]
|
(doseq [msg dropped]
|
||||||
(drop-message msg))
|
(drop-message msg))
|
||||||
|
|
||||||
;; Process the message
|
;; Process the message
|
||||||
(doseq [msg (vals messages)]
|
(doseq [msg (vals messages)]
|
||||||
(handle-message msg))
|
(handle-message msg))
|
||||||
|
|
||||||
;; After process the buffer we send a clear
|
;; After process the buffer we send a clear
|
||||||
(when-not (= last ::clear)
|
(when-not (= last ::clear)
|
||||||
(rx/push! buffer ::clear)))))))
|
(rx/push! buffer ::clear)))))))
|
||||||
|
|
||||||
|
|||||||
@ -50,8 +50,16 @@
|
|||||||
(handler (assoc message :cmd :snaps/update-page-index))))
|
(handler (assoc message :cmd :snaps/update-page-index))))
|
||||||
|
|
||||||
(defmethod handler :configure
|
(defmethod handler :configure
|
||||||
[{:keys [key val]}]
|
[{:keys [config]}]
|
||||||
(log/info :hint "configure worker" :key key :val (dm/str val))
|
(log/info :hint "configure worker" :keys (keys config))
|
||||||
(case key
|
|
||||||
:public-uri
|
(when-let [public-uri (get config :public-uri)]
|
||||||
(set! cf/public-uri val)))
|
(set! cf/public-uri public-uri))
|
||||||
|
|
||||||
|
(when-let [version (get config :version)]
|
||||||
|
(set! cf/version version))
|
||||||
|
|
||||||
|
(when-let [build-date (get config :build-data)]
|
||||||
|
(set! cf/build-date build-date))
|
||||||
|
|
||||||
|
nil)
|
||||||
|
|||||||
@ -27,7 +27,6 @@
|
|||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.shortcuts]
|
[app.main.data.workspace.shortcuts]
|
||||||
[app.main.errors :as errors]
|
[app.main.errors :as errors]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.util.debug :as dbg]
|
[app.util.debug :as dbg]
|
||||||
@ -393,7 +392,7 @@
|
|||||||
(ptk/reify ::repair-current-file
|
(ptk/reify ::repair-current-file
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ state _]
|
(effect [_ state _]
|
||||||
(let [features (features/get-team-enabled-features state)
|
(let [features (:features state)
|
||||||
sid (:session-id state)
|
sid (:session-id state)
|
||||||
|
|
||||||
file (dsh/lookup-file state)
|
file (dsh/lookup-file state)
|
||||||
@ -430,7 +429,3 @@
|
|||||||
(defn ^:export set-shape-ref
|
(defn ^:export set-shape-ref
|
||||||
[id shape-ref]
|
[id shape-ref]
|
||||||
(st/emit! (dw/set-shape-ref id shape-ref)))
|
(st/emit! (dw/set-shape-ref id shape-ref)))
|
||||||
|
|
||||||
(defn ^:export enable-text-v2
|
|
||||||
[]
|
|
||||||
(st/emit! (features/enable-feature "text-editor/v2")))
|
|
||||||
|
|||||||
@ -20,13 +20,12 @@
|
|||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defn ^:export get-enabled []
|
(defn ^:export get-enabled []
|
||||||
(clj->js (features/get-enabled-features @st/state)))
|
(clj->js features/global-enabled-features))
|
||||||
|
|
||||||
(defn ^:export get-team-enabled []
|
(defn ^:export get-team-enabled []
|
||||||
(clj->js (features/get-team-enabled-features @st/state)))
|
(clj->js (get @st/state :features)))
|
||||||
|
|
||||||
(defn ^:export plugins []
|
(defn ^:export plugins []
|
||||||
(st/emit! (features/enable-feature "plugins/runtime"))
|
(st/emit! (features/enable-feature "plugins/runtime"))
|
||||||
(plugins/init-plugins-runtime!)
|
(plugins/init-plugins-runtime!)
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"author": "Kaleidos INC",
|
"author": "Kaleidos INC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "yarn@4.2.2",
|
"packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/penpot/penpot"
|
"url": "https://github.com/penpot/penpot"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user