mirror of
https://github.com/penpot/penpot.git
synced 2025-04-13 15:31:26 -05:00
♻️ Refactor application routing
Mainly removes an inconsistent use of path params and normalize all routes to use query params for make it extensible without breaking urls.
This commit is contained in:
parent
b2f02de5c1
commit
3e090b126e
90 changed files with 1617 additions and 1548 deletions
|
@ -77,7 +77,7 @@
|
|||
:share-links links
|
||||
:libraries libs
|
||||
:file file
|
||||
:team team
|
||||
:team (assoc team :permissions perms)
|
||||
:permissions perms}))
|
||||
|
||||
(def schema:get-view-only-bundle
|
||||
|
|
|
@ -1010,6 +1010,9 @@
|
|||
(def valid-safe-number?
|
||||
(lazy-validator ::safe-number))
|
||||
|
||||
(def valid-text?
|
||||
(validator ::text))
|
||||
|
||||
(def check-safe-int!
|
||||
(check-fn ::safe-int))
|
||||
|
||||
|
|
|
@ -412,7 +412,6 @@
|
|||
(recur (when continue? (rest styles)) taking? to result))
|
||||
result))))
|
||||
|
||||
|
||||
(defn content->text
|
||||
"Given a root node of a text content extracts the texts with its associated styles"
|
||||
[content]
|
||||
|
|
|
@ -18,11 +18,18 @@
|
|||
java.nio.ByteBuffer)))
|
||||
|
||||
(defn uuid
|
||||
"Parse string uuid representation into proper UUID instance."
|
||||
"Creates an UUID instance from string, expectes valid uuid strings,
|
||||
the existense of validation is implementation detail"
|
||||
[s]
|
||||
#?(:clj (UUID/fromString s)
|
||||
:cljs (c/uuid s)))
|
||||
|
||||
(defn parse
|
||||
"Parse string uuid representation into proper UUID instance, validates input"
|
||||
[s]
|
||||
#?(:clj (UUID/fromString s)
|
||||
:cljs (c/parse-uuid s)))
|
||||
|
||||
(defn next
|
||||
[]
|
||||
#?(:clj (UUIDv8/create)
|
||||
|
|
23
frontend/playwright/data/get-teams-role-viewer.json
Normal file
23
frontend/playwright/data/get-teams-role-viewer.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
[{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:permissions": {
|
||||
"~:type": "~:membership",
|
||||
"~:is-owner": false,
|
||||
"~:is-admin": false,
|
||||
"~:can-edit": false
|
||||
},
|
||||
"~:name": "Default",
|
||||
"~:modified-at": "~m1713533116375",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920a",
|
||||
"~:created-at": "~m1713533116375",
|
||||
"~:is-default": true
|
||||
}]
|
23
frontend/playwright/data/get-teams.json
Normal file
23
frontend/playwright/data/get-teams.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
[{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:permissions": {
|
||||
"~:type": "~:membership",
|
||||
"~:is-owner": true,
|
||||
"~:is-admin": true,
|
||||
"~:can-edit": true
|
||||
},
|
||||
"~:name": "Default",
|
||||
"~:modified-at": "~m1713533116375",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920a",
|
||||
"~:created-at": "~m1713533116375",
|
||||
"~:is-default": true
|
||||
}]
|
|
@ -211,60 +211,64 @@ export class DashboardPage extends BaseWebSocketPage {
|
|||
|
||||
async goToDashboard() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.anyTeamId}/projects`,
|
||||
`#/dashboard/recent?team-id=${DashboardPage.anyTeamId}`,
|
||||
);
|
||||
await expect(this.mainHeading).toBeVisible();
|
||||
}
|
||||
|
||||
async goToSecondTeamDashboard() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/projects`,
|
||||
`#/dashboard/recent?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSecondTeamMembersSection() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/members`,
|
||||
`#/dashboard/members?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSecondTeamInvitationsSection() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/invitations`,
|
||||
`#/dashboard/invitations?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSecondTeamWebhooksSection() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/webhooks`,
|
||||
`#/dashboard/webhooks?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSecondTeamWebhooksSection() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/webhooks`,
|
||||
`#/dashboard/webhooks?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSecondTeamSettingsSection() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.secondTeamId}/settings`,
|
||||
`#/dashboard/settings?team-id=${DashboardPage.secondTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToSearch() {
|
||||
await this.page.goto(`#/dashboard/team/${DashboardPage.anyTeamId}/search`);
|
||||
await this.page.goto(
|
||||
`#/dashboard/search?team-id=${DashboardPage.anyTeamId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async goToDrafts() {
|
||||
await this.page.goto(
|
||||
`#/dashboard/team/${DashboardPage.anyTeamId}/projects/${DashboardPage.draftProjectId}`,
|
||||
`#/dashboard/files?team-id=${DashboardPage.anyTeamId}&project-id=${DashboardPage.draftProjectId}`,
|
||||
);
|
||||
await expect(this.mainHeading).toHaveText("Drafts");
|
||||
}
|
||||
|
||||
async goToFonts() {
|
||||
await this.page.goto(`#/dashboard/team/${DashboardPage.anyTeamId}/fonts`);
|
||||
await this.page.goto(
|
||||
`#/dashboard/fonts?team-id=${DashboardPage.anyTeamId}`,
|
||||
);
|
||||
await expect(this.mainHeading).toHaveText("Fonts");
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ export class ViewerPage extends BaseWebSocketPage {
|
|||
pageId = ViewerPage.anyPageId,
|
||||
} = {}) {
|
||||
await this.page.goto(
|
||||
`/#/view/${fileId}?page-id=${pageId}§ion=interactions&index=0`,
|
||||
`/#/view?file-id=${fileId}&page-id=${pageId}§ion=interactions&index=0`,
|
||||
);
|
||||
|
||||
this.#ws = await this.waitForNotificationsWebSocket();
|
||||
|
|
|
@ -36,6 +36,14 @@ export class WorkspacePage extends BaseWebSocketPage {
|
|||
"get-team?id=*",
|
||||
"workspace/get-team-default.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams.json");
|
||||
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"logged-in-user/get-team-members-your-penpot.json",
|
||||
);
|
||||
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
page,
|
||||
"get-profiles-for-file-comments?file-id=*",
|
||||
|
@ -43,6 +51,7 @@ export class WorkspacePage extends BaseWebSocketPage {
|
|||
);
|
||||
}
|
||||
|
||||
static anyTeamId = "c7ce0794-0992-8105-8004-38e630f7920a";
|
||||
static anyProjectId = "c7ce0794-0992-8105-8004-38e630f7920b";
|
||||
static anyFileId = "c7ce0794-0992-8105-8004-38f280443849";
|
||||
static anyPageId = "c7ce0794-0992-8105-8004-38f28044384a";
|
||||
|
@ -83,7 +92,7 @@ export class WorkspacePage extends BaseWebSocketPage {
|
|||
pageId = WorkspacePage.anyPageId,
|
||||
} = {}) {
|
||||
await this.page.goto(
|
||||
`/#/workspace/${WorkspacePage.anyProjectId}/${fileId}?page-id=${pageId}`,
|
||||
`/#/workspace?team-id=${WorkspacePage.anyTeamId}&file-id=${fileId}&page-id=${pageId}`,
|
||||
);
|
||||
|
||||
this.#ws = await this.waitForNotificationsWebSocket();
|
||||
|
|
|
@ -7,11 +7,7 @@ test.beforeEach(async ({ page }) => {
|
|||
|
||||
const workspacePage = new WorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile(page);
|
||||
await WorkspacePage.mockRPC(
|
||||
page,
|
||||
"get-team?id=*",
|
||||
"workspace/get-team-role-viewer.json",
|
||||
);
|
||||
await WorkspacePage.mockRPC(page, "get-teams", "get-teams-role-viewer.json");
|
||||
|
||||
await workspacePage.goToWorkspace();
|
||||
});
|
||||
|
|
|
@ -12,14 +12,15 @@
|
|||
[app.common.exceptions :as ex]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.profile :as dp]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.data.websocket :as ws]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -45,8 +46,9 @@
|
|||
(rx/of (rt/reload true))
|
||||
(rx/of (rt/nav-raw :href redirect-href))))
|
||||
(if-let [file-id (get props :welcome-file-id)]
|
||||
(rx/of (rt/nav' :workspace {:project-id (:default-project-id profile)
|
||||
:file-id file-id})
|
||||
(rx/of (dcm/go-to-workspace
|
||||
:file-id file-id
|
||||
:team-id (:default-team-id profile))
|
||||
(dp/update-profile-props {:welcome-file-id nil}))
|
||||
|
||||
(let [teams (into #{} (map :id) teams)
|
||||
|
@ -54,7 +56,7 @@
|
|||
team-id (if (and team-id (contains? teams team-id))
|
||||
team-id
|
||||
(:default-team-id profile))]
|
||||
(rx/of (rt/nav' :dashboard-projects {:team-id team-id}))))))]
|
||||
(rx/of (dcm/go-to-dashboard-recent {:team-id team-id}))))))]
|
||||
|
||||
(ptk/reify ::logged-in
|
||||
ev/Event
|
||||
|
|
|
@ -603,3 +603,18 @@
|
|||
(filter (fn [comment] (some #(= % (:frame-id comment)) frame-ids?)))
|
||||
(map update-comment-thread-frame)
|
||||
(rx/from))))))
|
||||
|
||||
(defn fetch-profiles
|
||||
"Fetch or refresh all profile data for comments of the current file"
|
||||
[]
|
||||
(ptk/reify ::fetch-comments-profiles
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)
|
||||
share-id (or (-> state :viewer-local :share-id)
|
||||
(:current-share-id state))]
|
||||
(->> (rp/cmd! :get-profiles-for-file-comments {:file-id file-id :share-id share-id})
|
||||
(rx/map (fn [profiles]
|
||||
#(update % :profiles merge (d/index-by :id profiles)))))))))
|
||||
|
||||
|
||||
|
|
|
@ -14,14 +14,18 @@
|
|||
[app.common.types.team :as ctt]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.persistence :as-alias dps]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.util.dom :as-alias dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(declare go-to-dashboard-recent)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SHARE LINK
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -233,12 +237,165 @@
|
|||
(watch [_ state _]
|
||||
(when (= :removed change)
|
||||
(let [message (tr "dashboard.removed-from-team" team-name)
|
||||
profile (:profile state)]
|
||||
team-id (-> state :profile :default-team-id)]
|
||||
(rx/concat
|
||||
(rx/of (rt/nav :dashboard-projects {:team-id (:default-team-id profile)}))
|
||||
(rx/of (go-to-dashboard-recent :team-id team-id))
|
||||
(->> (rx/of (ntf/info message))
|
||||
;; Delay so the navigation can finish
|
||||
(rx/delay 250))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NAVEGATION EVENTS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn go-to-feedback
|
||||
[]
|
||||
(ptk/reify ::go-to-feedback
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (rt/nav :settings-feedback {}
|
||||
::rt/new-window true
|
||||
::rt/window-name "penpot-feedback")))))
|
||||
|
||||
(defn go-to-dashboard-files
|
||||
[& {:keys [project-id team-id] :as options}]
|
||||
(ptk/reify ::go-to-dashboard-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [profile (get state :profile)
|
||||
team-id (or team-id (:current-team-id state))
|
||||
project-id (if (= project-id :default)
|
||||
(:default-project-id profile)
|
||||
project-id)
|
||||
|
||||
params {:team-id team-id
|
||||
:project-id project-id}]
|
||||
(rx/of (rt/nav :dashboard-files params options))))))
|
||||
|
||||
(defn go-to-dashboard-search
|
||||
[& {:keys [term] :as options}]
|
||||
(ptk/reify ::go-to-dashboard-search
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/merge
|
||||
(->> (rx/of (rt/nav :dashboard-search
|
||||
{:team-id team-id
|
||||
:search-term term})
|
||||
(modal/hide))
|
||||
(rx/observe-on :async))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::rt/navigated))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [_]
|
||||
(ptk/event ::dom/focus-element
|
||||
{:name "search-input"})))))))))
|
||||
|
||||
(defn go-to-dashboard-libraries
|
||||
[& {:keys [team-id] :as options}]
|
||||
(ptk/reify ::go-to-dashboard-libraries
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or team-id (:current-team-id state))]
|
||||
(rx/of (rt/nav :dashboard-libraries {:team-id team-id}))))))
|
||||
|
||||
|
||||
(defn go-to-dashboard-fonts
|
||||
[& {:keys [team-id] :as options}]
|
||||
(ptk/reify ::go-to-dashboard-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or team-id (:current-team-id state))]
|
||||
(rx/of (rt/nav :dashboard-libraries {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-dashboard-recent
|
||||
[& {:keys [team-id] :as options}]
|
||||
(ptk/reify ::go-to-dashboard-recent
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [profile (get state :profile)
|
||||
team-id (cond
|
||||
(= :default team-id)
|
||||
(:default-team-id profile)
|
||||
|
||||
(uuid? team-id)
|
||||
team-id
|
||||
|
||||
:else
|
||||
(:current-team-id state))
|
||||
params {:team-id team-id}]
|
||||
(rx/of (modal/hide)
|
||||
(rt/nav :dashboard-recent params options))))))
|
||||
|
||||
(defn go-to-dashboard-members
|
||||
[& {:as options}]
|
||||
(ptk/reify ::go-to-dashboard-members
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-members {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-dashboard-invitations
|
||||
[& {:as options}]
|
||||
(ptk/reify ::go-to-dashboard-invitations
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-invitations {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-dashboard-webhooks
|
||||
[& {:as options}]
|
||||
(ptk/reify ::go-to-dashboard-webhooks
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-webhooks {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-dashboard-settings
|
||||
[& {:as options}]
|
||||
(ptk/reify ::go-to-dashboard-settings
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-settings {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-workspace
|
||||
[& {:keys [team-id file-id page-id layout] :as options}]
|
||||
(ptk/reify ::go-to-workspace
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or team-id (:current-team-id state))
|
||||
file-id (or file-id (:current-file-id state))
|
||||
;: FIXME: why not :current-page-id
|
||||
page-id (or page-id
|
||||
(dm/get-in state [:workspace-data :pages 0]))
|
||||
params (-> (rt/get-params state)
|
||||
(assoc :team-id team-id)
|
||||
(assoc :file-id file-id)
|
||||
(assoc :page-id page-id)
|
||||
(assoc :layout layout)
|
||||
(d/without-nils))]
|
||||
(rx/of (rt/nav :workspace params options))))))
|
||||
|
||||
(defn go-to-viewer
|
||||
[& {:keys [file-id page-id section frame-id index] :as options}]
|
||||
(ptk/reify ::go-to-viewer
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (or page-id (:current-page-id state))
|
||||
file-id (or file-id (:current-file-id state))
|
||||
section (or section :interactions)
|
||||
params {:file-id file-id
|
||||
:page-id page-id
|
||||
:section section
|
||||
:frame-id frame-id
|
||||
:index index}
|
||||
params (d/without-nils params)
|
||||
name (dm/str "viewer-" file-id)
|
||||
options (merge {::rt/new-window true
|
||||
::rt/window-name name}
|
||||
options)]
|
||||
(rx/of ::dps/force-persist
|
||||
(rt/nav :viewer params options))))))
|
||||
|
||||
|
|
|
@ -13,18 +13,15 @@
|
|||
[app.common.logging :as log]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.common :as dc]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.websocket :as dws]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.sse :as sse]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.time :as dt]
|
||||
[beicon.v2.core :as rx]
|
||||
[clojure.set :as set]
|
||||
|
@ -115,55 +112,6 @@
|
|||
(rx/map (fn [result]
|
||||
#(assoc % :search-result result)))))))))
|
||||
|
||||
;; --- EVENT: files
|
||||
|
||||
(defn files-fetched
|
||||
[project-id files]
|
||||
(letfn [(remove-project-files [files]
|
||||
(reduce-kv (fn [result id file]
|
||||
(cond-> result
|
||||
(= (:project-id file) project-id) (dissoc id)))
|
||||
files
|
||||
files))]
|
||||
(ptk/reify ::files-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :files
|
||||
(fn [files']
|
||||
(reduce #(assoc %1 (:id %2) %2)
|
||||
(remove-project-files files')
|
||||
files)))
|
||||
(assoc-in [:projects project-id :count] (count files)))))))
|
||||
|
||||
(defn fetch-files
|
||||
[{:keys [project-id] :as params}]
|
||||
(dm/assert! (uuid? project-id))
|
||||
(ptk/reify ::fetch-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-project-files {:project-id project-id})
|
||||
(rx/map #(files-fetched project-id %))))))
|
||||
|
||||
;; --- EVENT: shared-files
|
||||
|
||||
(defn shared-files-fetched
|
||||
[files]
|
||||
(ptk/reify ::shared-files-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [files (d/index-by :id files)]
|
||||
(assoc state :shared-files files)))))
|
||||
|
||||
(defn fetch-shared-files
|
||||
[]
|
||||
(ptk/reify ::fetch-shared-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-shared-files {:team-id team-id})
|
||||
(rx/map shared-files-fetched))))))
|
||||
|
||||
;; --- EVENT: recent-files
|
||||
|
||||
(defn recent-files-fetched
|
||||
|
@ -630,133 +578,6 @@
|
|||
(rx/tap on-success)
|
||||
(rx/catch on-error))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Navigation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn go-to-workspace
|
||||
[{:keys [id project-id] :as file}]
|
||||
(ptk/reify ::go-to-workspace
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [pparams {:project-id project-id :file-id id}]
|
||||
(rx/of (rt/nav :workspace pparams))))))
|
||||
|
||||
|
||||
(defn go-to-files
|
||||
([project-id] (go-to-files project-id nil))
|
||||
([project-id team-id]
|
||||
(ptk/reify ::go-to-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or team-id (:current-team-id state))]
|
||||
(rx/of (rt/nav :dashboard-files {:team-id team-id
|
||||
:project-id project-id})))))))
|
||||
|
||||
(defn go-to-search
|
||||
([] (go-to-search nil))
|
||||
([term]
|
||||
(ptk/reify ::go-to-search
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(if (empty? term)
|
||||
(do
|
||||
(dom/focus! (dom/get-element "search-input"))
|
||||
(rx/of (rt/nav :dashboard-search
|
||||
{:team-id team-id})))
|
||||
(rx/of (rt/nav :dashboard-search
|
||||
{:team-id team-id}
|
||||
{:search-term term})))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(dom/focus! (dom/get-element "search-input"))))))
|
||||
|
||||
(defn go-to-projects
|
||||
[team-id]
|
||||
(ptk/reify ::go-to-projects
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or team-id (:current-team-id state))]
|
||||
(rx/of (rt/nav :dashboard-projects {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-default-team
|
||||
"High-level component for redirect to the current profile default
|
||||
team and hide all modals"
|
||||
[]
|
||||
(ptk/reify ::go-to-default-team
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (dm/get-in state [:profile :default-team-id])]
|
||||
(rx/of (go-to-projects team-id)
|
||||
(modal/hide))))))
|
||||
|
||||
|
||||
(defn go-to-current-team
|
||||
"High-level component for redirect to the current profile default
|
||||
team and hide all modals"
|
||||
[]
|
||||
(ptk/reify ::go-to-current-team
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (or (::current-team-id storage/user)
|
||||
(dm/get-in state [:profile :default-team-id]))]
|
||||
(rx/of (go-to-projects team-id)
|
||||
(modal/hide))))))
|
||||
|
||||
(defn go-to-team-members
|
||||
[]
|
||||
(ptk/reify ::go-to-team-members
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-team-members {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-team-invitations
|
||||
[]
|
||||
(ptk/reify ::go-to-team-invitations
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-team-invitations {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-team-webhooks
|
||||
[]
|
||||
(ptk/reify ::go-to-team-webhooks
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-team-webhooks {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-team-settings
|
||||
[]
|
||||
(ptk/reify ::go-to-team-settings
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-team-settings {:team-id team-id}))))))
|
||||
|
||||
(defn go-to-drafts
|
||||
[]
|
||||
(ptk/reify ::go-to-drafts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)
|
||||
projects (:projects state)
|
||||
default-project (d/seek :is-default (vals projects))]
|
||||
(when default-project
|
||||
(rx/of (rt/nav :dashboard-files {:team-id team-id
|
||||
:project-id (:id default-project)})))))))
|
||||
|
||||
(defn go-to-libs
|
||||
[]
|
||||
(ptk/reify ::go-to-libs
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (rt/nav :dashboard-libraries {:team-id team-id}))))))
|
||||
|
||||
(defn create-element
|
||||
[]
|
||||
(ptk/reify ::create-element
|
||||
|
@ -793,8 +614,7 @@
|
|||
(watch [_ state _]
|
||||
(let [[file-id :as files] (get state :selected-files)]
|
||||
(if (= 1 (count files))
|
||||
(let [file (dm/get-in state [files file-id])]
|
||||
(rx/of (go-to-workspace file)))
|
||||
(rx/of (dcm/go-to-workspace :file-id file-id))
|
||||
(rx/empty))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -806,13 +626,13 @@
|
|||
(ptk/reify ::handle-change-team-role
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (dc/change-team-role params)
|
||||
(rx/of (dcm/change-team-role params)
|
||||
(modal/hide)))))
|
||||
|
||||
(defn- process-message
|
||||
[{:keys [type] :as msg}]
|
||||
(case type
|
||||
:notification (dc/handle-notification msg)
|
||||
:notification (dcm/handle-notification msg)
|
||||
:team-role-change (handle-change-team-role msg)
|
||||
:team-membership-change (dc/team-membership-change msg)
|
||||
:team-membership-change (dcm/team-membership-change msg)
|
||||
nil))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.data.dashboard.shortcuts
|
||||
(:require
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.profile :as du]
|
||||
|
@ -16,17 +17,17 @@
|
|||
{:go-to-search {:tooltip (ds/meta "F")
|
||||
:command (ds/c-mod "f")
|
||||
:subsections [:navigation-dashboard]
|
||||
:fn #(st/emit! (dd/go-to-search))}
|
||||
:fn #(st/emit! (dcm/go-to-dashboard-search))}
|
||||
|
||||
:go-to-drafts {:tooltip "G D"
|
||||
:command "g d"
|
||||
:subsections [:navigation-dashboard]
|
||||
:fn #(st/emit! (dd/go-to-drafts))}
|
||||
:fn #(st/emit! (dcm/go-to-dashboard-files :project-id :default))}
|
||||
|
||||
:go-to-libs {:tooltip "G L"
|
||||
:command "g l"
|
||||
:subsections [:navigation-dashboard]
|
||||
:fn #(st/emit! (dd/go-to-libs))}
|
||||
:fn #(st/emit! (dcm/go-to-dashboard-libraries))}
|
||||
|
||||
:create-new-project {:tooltip "+"
|
||||
:command "+"
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
(rx/merge
|
||||
(let [stopper (rx/filter (ptk/type? ::hide) stream)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? :app.util.router/navigate))
|
||||
(rx/filter (ptk/type? :app.main.router/navigate))
|
||||
(rx/map (fn [_] (hide)))
|
||||
(rx/take-until stopper)))
|
||||
(when (:timeout data)
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
[app.main.data.media :as di]
|
||||
[app.main.data.team :as-alias dtm]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.plugins.register :as plugins.register]
|
||||
[app.util.i18n :as i18n]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
|
80
frontend/src/app/main/data/project.cljs
Normal file
80
frontend/src/app/main/data/project.cljs
Normal file
|
@ -0,0 +1,80 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.data.project
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.logging :as log]
|
||||
[app.main.repo :as rp]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(log/set-level! :warn)
|
||||
|
||||
(defn- project-fetched
|
||||
[{:keys [id] :as project}]
|
||||
(ptk/reify ::project-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:projects id] merge project))))
|
||||
|
||||
(defn fetch-project
|
||||
"Fetch or refresh a single project"
|
||||
([] (fetch-project))
|
||||
([project-id]
|
||||
(assert (uuid? project-id) "expected a valid uuid for `project-id`")
|
||||
|
||||
(ptk/reify ::fetch-project
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (or project-id (:current-project-id state))]
|
||||
(->> (rp/cmd! :get-project {:id project-id})
|
||||
(rx/map project-fetched)))))))
|
||||
|
||||
(defn initialize-project
|
||||
[project-id]
|
||||
(ptk/reify ::initialize-project
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :current-project-id project-id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (fetch-project project-id)))))
|
||||
|
||||
(defn finalize-project
|
||||
[project-id]
|
||||
(ptk/reify ::finalize-project
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [project-id' (get state :current-project-id)]
|
||||
(if (= project-id' project-id)
|
||||
(dissoc state :current-project-id)
|
||||
state)))))
|
||||
|
||||
|
||||
(defn- files-fetched
|
||||
[project-id files]
|
||||
(ptk/reify ::files-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :files merge (d/index-by :id files))
|
||||
(d/update-in-when [:projects project-id] (fn [project]
|
||||
(assoc project :count (count files))))))))
|
||||
|
||||
(defn fetch-files
|
||||
[project-id]
|
||||
(assert (uuid? project-id) "expected valid uuid for `project-id`")
|
||||
(ptk/reify ::fetch-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-project-files {:project-id project-id})
|
||||
(rx/map (partial files-fetched project-id))))))
|
||||
|
||||
|
||||
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.data.team
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.logging :as log]
|
||||
[app.common.schema :as sm]
|
||||
|
@ -16,7 +17,7 @@
|
|||
[app.main.data.media :as di]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.router :as rt]
|
||||
[app.main.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -57,7 +58,9 @@
|
|||
(ptk/reify ::members-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:teams team-id] assoc :members members))))
|
||||
(-> state
|
||||
(update-in [:teams team-id] assoc :members members)
|
||||
(update :profiles merge (d/index-by :id members))))))
|
||||
|
||||
(defn fetch-members
|
||||
[]
|
||||
|
@ -145,6 +148,7 @@
|
|||
(if (= team-id' team-id)
|
||||
(-> state
|
||||
(dissoc :current-team-id)
|
||||
(dissoc :shared-files)
|
||||
(dissoc :fonts))
|
||||
state)))))
|
||||
|
||||
|
@ -220,6 +224,26 @@
|
|||
(->> (rp/cmd! :get-webhooks {:team-id team-id})
|
||||
(rx/map (partial webhooks-fetched team-id)))))))
|
||||
|
||||
(defn- shared-files-fetched
|
||||
[files]
|
||||
(ptk/reify ::shared-files-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [files (d/index-by :id files)]
|
||||
(assoc state :shared-files files)))))
|
||||
|
||||
(defn fetch-shared-files
|
||||
"Event mainly used for fetch a list of shared libraries for a team,
|
||||
this list does not includes the content of the library per se. It
|
||||
is used mainly for show available libraries and a summary of it."
|
||||
[]
|
||||
(ptk/reify ::fetch-shared-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-shared-files {:team-id team-id})
|
||||
(rx/map shared-files-fetched))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Data Modification
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -334,7 +358,7 @@
|
|||
(when reassign-to
|
||||
(assert (uuid? reassign-to) "expect a valid uuid for `reassign-to`"))
|
||||
|
||||
(ptk/reify ::leave-team
|
||||
(ptk/reify ::leave-current-team
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (get state :current-team-id)
|
||||
|
@ -405,7 +429,7 @@
|
|||
|
||||
(->> (rp/cmd! :get-team-invitation-token params)
|
||||
(rx/map (fn [params]
|
||||
(rt/resolve router :auth-verify-token {} params)))
|
||||
(rt/resolve router :auth-verify-token params)))
|
||||
(rx/map (fn [fragment]
|
||||
(assoc cf/public-uri :fragment fragment)))
|
||||
(rx/tap (fn [uri]
|
||||
|
@ -532,3 +556,4 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
[app.common.transit :as t]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.comments :as dcmt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.util.globals :as ug]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
|
@ -32,7 +34,7 @@
|
|||
{:zoom 1
|
||||
:fullscreen? false
|
||||
:interactions-mode :show-on-click
|
||||
:interactions-show? false
|
||||
:show-interactions false
|
||||
:comments-mode :all
|
||||
:comments-show :unresolved
|
||||
:selected #{}
|
||||
|
@ -55,7 +57,7 @@
|
|||
[:page-id {:optional true} ::sm/uuid]])
|
||||
|
||||
(defn initialize
|
||||
[{:keys [file-id share-id interactions-show?] :as params}]
|
||||
[{:keys [file-id share-id] :as params}]
|
||||
(dm/assert!
|
||||
"expected valid params"
|
||||
(sm/check schema:initialize params))
|
||||
|
@ -65,13 +67,13 @@
|
|||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :current-file-id file-id)
|
||||
(assoc :current-share-id share-id)
|
||||
(update :viewer-local
|
||||
(fn [lstate]
|
||||
(if (nil? lstate)
|
||||
default-local-state
|
||||
lstate)))
|
||||
(assoc-in [:viewer-local :share-id] share-id)
|
||||
(assoc-in [:viewer-local :interactions-show?] interactions-show?)))
|
||||
(assoc-in [:viewer-local :share-id] share-id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -256,12 +258,9 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [zoom-type (get-in state [:viewer-local :zoom-type])
|
||||
route (:route state)
|
||||
screen (-> route :data :name keyword)
|
||||
qparams (:query-params route)
|
||||
pparams (:path-params route)]
|
||||
params (rt/get-params state)]
|
||||
|
||||
(rx/of (rt/nav screen pparams (assoc qparams :zoom zoom-type)))))))
|
||||
(rx/of (rt/nav :viewer (assoc params :zoom zoom-type)))))))
|
||||
|
||||
(def increase-zoom
|
||||
(ptk/reify ::increase-zoom
|
||||
|
@ -293,14 +292,17 @@
|
|||
(ptk/reify ::zoom-to-fit
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [srect (as-> (get-in state [:route :query-params :page-id]) %
|
||||
(get-in state [:viewer :pages % :frames])
|
||||
(nth % (get-in state [:route :query-params :index]))
|
||||
(get % :selrect))
|
||||
orig-size (get-in state [:viewer-local :viewport-size])
|
||||
wdiff (/ (:width orig-size) (:width srect))
|
||||
hdiff (/ (:height orig-size) (:height srect))
|
||||
minzoom (min wdiff hdiff)]
|
||||
(let [params (rt/get-params state)
|
||||
page-id (some-> (:page-id params) uuid/parse)
|
||||
index (some-> (:index params) parse-long)
|
||||
|
||||
frames (dm/get-in state [:viewer :pages page-id :frames])
|
||||
srect (-> (nth frames index)
|
||||
(get :selrect))
|
||||
osize (dm/get-in state [:viewer-local :viewport-size])
|
||||
wdiff (/ (:width osize) (:width srect))
|
||||
hdiff (/ (:height osize) (:height srect))
|
||||
minzoom (min wdiff hdiff)]
|
||||
(-> state
|
||||
(assoc-in [:viewer-local :zoom] minzoom)
|
||||
(assoc-in [:viewer-local :zoom-type] :fit))))
|
||||
|
@ -312,17 +314,25 @@
|
|||
(ptk/reify ::zoom-to-fill
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [srect (as-> (get-in state [:route :query-params :page-id]) %
|
||||
(get-in state [:viewer :pages % :frames])
|
||||
(nth % (get-in state [:route :query-params :index]))
|
||||
(get % :selrect))
|
||||
orig-size (get-in state [:viewer-local :viewport-size])
|
||||
wdiff (/ (:width orig-size) (:width srect))
|
||||
hdiff (/ (:height orig-size) (:height srect))
|
||||
maxzoom (max wdiff hdiff)]
|
||||
|
||||
(let [params (rt/get-params state)
|
||||
page-id (some-> (:page-id params) uuid/parse)
|
||||
index (some-> (:index params) parse-long)
|
||||
|
||||
frames (dm/get-in state [:viewer :pages page-id :frames])
|
||||
srect (-> (nth frames index)
|
||||
(get :selrect))
|
||||
|
||||
osize (dm/get-in state [:viewer-local :viewport-size])
|
||||
|
||||
wdiff (/ (:width osize) (:width srect))
|
||||
hdiff (/ (:height osize) (:height srect))
|
||||
|
||||
maxzoom (max wdiff hdiff)]
|
||||
(-> state
|
||||
(assoc-in [:viewer-local :zoom] maxzoom)
|
||||
(assoc-in [:viewer-local :zoom-type] :fill))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _] (rx/of update-zoom-querystring))))
|
||||
|
||||
|
@ -376,16 +386,15 @@
|
|||
(-> state
|
||||
(dissoc :viewer-animations)
|
||||
(assoc :viewer-overlays [])))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
qparams (:query-params route)
|
||||
pparams (:path-params route)
|
||||
index (:index qparams)]
|
||||
(let [params (rt/get-params state)
|
||||
index (some-> params :index parse-long)]
|
||||
(when (pos? index)
|
||||
(rx/of
|
||||
(dcm/close-thread)
|
||||
(rt/nav :viewer pparams (assoc qparams :index (dec index)))))))))
|
||||
(dcmt/close-thread)
|
||||
(rt/nav :viewer (assoc params :index (dec index)))))))))
|
||||
|
||||
(def select-next-frame
|
||||
(ptk/reify ::select-next-frame
|
||||
|
@ -396,30 +405,25 @@
|
|||
(assoc :viewer-overlays [])))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
pparams (:path-params route)
|
||||
qparams (:query-params route)
|
||||
|
||||
page-id (:page-id qparams)
|
||||
index (:index qparams)
|
||||
(let [params (rt/get-params state)
|
||||
index (some-> params :index parse-long)
|
||||
page-id (some-> params :page-id parse-uuid)
|
||||
|
||||
total (count (get-in state [:viewer :pages page-id :frames]))]
|
||||
|
||||
(when (< index (dec total))
|
||||
(rx/of
|
||||
(dcm/close-thread)
|
||||
(rt/nav :viewer pparams (assoc qparams :index (inc index)))))))))
|
||||
(dcmt/close-thread)
|
||||
(rt/nav :viewer params (assoc params :index (inc index)))))))))
|
||||
|
||||
(def select-first-frame
|
||||
(ptk/reify ::select-first-frame
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
qparams (:query-params route)
|
||||
pparams (:path-params route)]
|
||||
(let [params (rt/get-params state)]
|
||||
(rx/of
|
||||
(dcm/close-thread)
|
||||
(rt/nav :viewer pparams (assoc qparams :index 0)))))))
|
||||
(dcmt/close-thread)
|
||||
(rt/nav :viewer (assoc params :index 0)))))))
|
||||
|
||||
(def valid-interaction-modes
|
||||
#{:hide :show :show-on-click})
|
||||
|
@ -434,17 +438,14 @@
|
|||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:viewer-local :interactions-mode] mode)
|
||||
(assoc-in [:viewer-local :interactions-show?] (case mode
|
||||
:hide false
|
||||
:show true
|
||||
:show-on-click false))))
|
||||
(assoc-in [:viewer-local :show-interactions] (case mode
|
||||
:hide false
|
||||
:show true
|
||||
:show-on-click false))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
screen (-> route :data :name keyword)
|
||||
qparams (:query-params route)
|
||||
pparams (:path-params route)]
|
||||
(rx/of (rt/nav screen pparams (assoc qparams :interactions-mode mode)))))))
|
||||
(let [params (rt/get-params state)]
|
||||
(rx/of (rt/nav :viewer (assoc params :interactions-mode mode)))))))
|
||||
|
||||
(declare flash-done)
|
||||
|
||||
|
@ -453,7 +454,7 @@
|
|||
(ptk/reify ::flash-interactions
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :interactions-show?] true))
|
||||
(assoc-in state [:viewer-local :show-interactions] true))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
|
@ -466,7 +467,7 @@
|
|||
(ptk/reify ::flash-done
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :interactions-show?] false))))
|
||||
(assoc-in state [:viewer-local :show-interactions] false))))
|
||||
|
||||
(defn set-nav-scroll
|
||||
[scroll]
|
||||
|
@ -500,11 +501,8 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
screen (-> route :data :name keyword)
|
||||
qparams (:query-params route)
|
||||
pparams (:path-params route)]
|
||||
(rx/of (rt/nav screen pparams (assoc qparams :index index)))))))
|
||||
(let [params (rt/get-params state)]
|
||||
(rx/of (rt/nav :viewer (assoc params :index index)))))))
|
||||
|
||||
(defn go-to-frame
|
||||
([frame-id]
|
||||
|
@ -573,10 +571,8 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
pparams (:path-params route)
|
||||
qparams (:query-params route)]
|
||||
(rx/of (rt/nav :viewer pparams (assoc qparams :section section)))))))
|
||||
(let [params (rt/get-params state)]
|
||||
(rx/of (rt/nav :viewer (assoc params :section section)))))))
|
||||
|
||||
;; --- Overlays
|
||||
|
||||
|
@ -771,9 +767,8 @@
|
|||
(ptk/reify ::go-to-dashboard
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (get-in state [:viewer :project :team-id])
|
||||
params {:team-id team-id}]
|
||||
(rx/of (rt/nav :dashboard-projects params))))))
|
||||
(let [team-id (get-in state [:viewer :project :team-id])]
|
||||
(rx/of (dcm/go-to-dashboard-recent :team-id team-id))))))
|
||||
|
||||
(defn go-to-page
|
||||
[page-id]
|
||||
|
@ -784,13 +779,10 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
pparams (:path-params route)
|
||||
qparams (-> (:query-params route)
|
||||
(assoc :index 0)
|
||||
(assoc :page-id page-id))
|
||||
rname (get-in route [:data :name])]
|
||||
(rx/of (rt/nav rname pparams qparams))))))
|
||||
(let [params (-> (rt/get-params state)
|
||||
(assoc :index 0)
|
||||
(assoc :page-id page-id))]
|
||||
(rx/of (rt/nav :viewer params))))))
|
||||
|
||||
(defn go-to-workspace
|
||||
([] (go-to-workspace nil))
|
||||
|
@ -798,14 +790,16 @@
|
|||
(ptk/reify ::go-to-workspace
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
project-id (get-in state [:viewer :project :id])
|
||||
file-id (get-in state [:viewer :file :id])
|
||||
saved-page-id (get-in route [:query-params :page-id])
|
||||
pparams {:project-id project-id :file-id file-id}
|
||||
qparams {:page-id (or page-id saved-page-id)}]
|
||||
(rx/of (rt/nav-new-window*
|
||||
{:rname :workspace
|
||||
:path-params pparams
|
||||
:query-params qparams
|
||||
:name (str "workspace-" file-id)})))))))
|
||||
(let [params (rt/get-params state)
|
||||
file-id (get-in state [:viewer :file :id])
|
||||
team-id (get-in state [:viewer :project :team-id])
|
||||
page-id (or page-id
|
||||
(some-> (:page-id params) uuid/parse))
|
||||
params {:page-id page-id
|
||||
:file-id file-id
|
||||
:team-id team-id}
|
||||
name (dm/str "workspace-" file-id)]
|
||||
|
||||
(rx/of (rt/nav :workspace params
|
||||
::rt/new-window true
|
||||
::rt/window-name name)))))))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.data.viewer.shortcuts
|
||||
(:require
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.shortcuts :as ds]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.store :as st]))
|
||||
|
@ -69,7 +70,7 @@
|
|||
:open-workspace {:tooltip "G W"
|
||||
:command "g w"
|
||||
:subsections [:navigation-viewer]
|
||||
:fn #(st/emit! (dv/go-to-workspace))}})
|
||||
:fn #(st/emit! (dcm/go-to-workspace))}})
|
||||
|
||||
(defn get-tooltip [shortcut]
|
||||
(assert (contains? shortcuts shortcut) (str shortcut))
|
||||
|
|
|
@ -36,17 +36,18 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.comments :as dcmt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.persistence :as dps]
|
||||
[app.main.data.plugins :as dp]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.data.project :as dpj]
|
||||
[app.main.data.workspace.bool :as dwb]
|
||||
[app.main.data.workspace.collapse :as dwco]
|
||||
[app.main.data.workspace.colors :as dwcl]
|
||||
[app.main.data.workspace.drawing :as dwd]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.fix-broken-shapes :as fbs]
|
||||
|
@ -75,6 +76,7 @@
|
|||
[app.main.features :as features]
|
||||
[app.main.features.pointer-map :as fpmap]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.worker :as uw]
|
||||
[app.render-wasm :as wasm]
|
||||
|
@ -82,7 +84,6 @@
|
|||
[app.util.globals :as ug]
|
||||
[app.util.http :as http]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.timers :as tm]
|
||||
[app.util.webapi :as wapi]
|
||||
|
@ -101,12 +102,15 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(declare ^:private workspace-initialized)
|
||||
(declare ^:private fetch-libraries)
|
||||
(declare ^:private libraries-fetched)
|
||||
(declare go-to-layout)
|
||||
(declare ^:private preload-data-uris)
|
||||
|
||||
;; (declare go-to-layout)
|
||||
|
||||
;; --- Initialize Workspace
|
||||
|
||||
(defn initialize-layout
|
||||
(defn initialize-workspace-layout
|
||||
[lname]
|
||||
(ptk/reify ::initialize-layout
|
||||
ptk/UpdateEvent
|
||||
|
@ -121,105 +125,45 @@
|
|||
(rx/of (layout/ensure-layout lname))
|
||||
(rx/of (layout/ensure-layout :layers))))))
|
||||
|
||||
(defn- workspace-initialized
|
||||
[]
|
||||
(ptk/reify ::workspace-initialized
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :workspace-undo {})
|
||||
(assoc :workspace-ready? true)))
|
||||
(defn- datauri->blob-uri
|
||||
[uri]
|
||||
(->> (http/send! {:uri uri
|
||||
:response-type :blob
|
||||
:method :get})
|
||||
(rx/map :body)
|
||||
(rx/map (fn [blob] (wapi/create-uri blob)))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(rx/of
|
||||
(when (and (not (boolean (-> state :profile :props :v2-info-shown)))
|
||||
(features/active-feature? state "components/v2"))
|
||||
(modal/show :v2-info {}))
|
||||
(dp/check-open-plugin)
|
||||
(fdf/fix-deleted-fonts)
|
||||
(fbs/fix-broken-shapes)))))
|
||||
(defn- get-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 (str/starts-with? v "data:")
|
||||
(->> (datauri->blob-uri v)
|
||||
(rx/map (fn [uri] [k uri])))
|
||||
(rx/of [k v])))))))
|
||||
(rx/reduce conj {})))
|
||||
|
||||
(defn- workspace-data-loaded
|
||||
[data]
|
||||
(ptk/reify ::workspace-data-loaded
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [data (d/removem (comp t/pointer? val) data)]
|
||||
(assoc state :workspace-data data)))))
|
||||
|
||||
(defn- bundle-fetched
|
||||
[{: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-file-comments-users (d/index-by :id comments-users))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [team-id (:id team)
|
||||
file-id (:id file)
|
||||
stopper (rx/filter (ptk/type? ::bundle-fetched) stream)]
|
||||
|
||||
(->> (rx/concat
|
||||
;; Initialize notifications
|
||||
;; FIXME: this should not be initialized here looks like
|
||||
(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? ::df/fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
|
||||
(rx/of (df/fetch-fonts))
|
||||
|
||||
;; FIXME: move to bundle fetch stages
|
||||
|
||||
;; Load main file
|
||||
(->> (fpmap/resolve-file file)
|
||||
(rx/map :data)
|
||||
(rx/mapcat (fn [{:keys [pages-index] :as data}]
|
||||
(->> (rx/from (seq pages-index))
|
||||
(rx/mapcat
|
||||
(fn [[id page]]
|
||||
(let [page (update page :objects ctst/start-page-index)]
|
||||
(->> (uw/ask! {:cmd :initialize-page-index :page page})
|
||||
(rx/map (fn [_] [id page]))))))
|
||||
(rx/reduce conj {})
|
||||
(rx/map (fn [pages-index]
|
||||
(assoc data :pages-index pages-index))))))
|
||||
(rx/map workspace-data-loaded))
|
||||
|
||||
;; Load libraries
|
||||
(->> (rp/cmd! :get-file-libraries {:file-id file-id})
|
||||
(rx/mapcat (fn [libraries]
|
||||
(rx/merge
|
||||
(->> (rx/from libraries)
|
||||
(rx/merge-map
|
||||
(fn [{:keys [id synced-at]}]
|
||||
(->> (rp/cmd! :get-file {:id id :features features})
|
||||
(rx/map #(assoc % :synced-at synced-at)))))
|
||||
(rx/merge-map fpmap/resolve-file)
|
||||
(rx/reduce conj [])
|
||||
(rx/map libraries-fetched))
|
||||
(->> (rx/from libraries)
|
||||
(rx/map :id)
|
||||
(rx/mapcat (fn [file-id]
|
||||
(rp/cmd! :get-file-object-thumbnails {:file-id file-id :tag "component"})))
|
||||
(rx/map dwl/library-thumbnails-fetched)))))))
|
||||
|
||||
(rx/of (with-meta (workspace-initialized)
|
||||
{:file-id file-id})))
|
||||
(rx/take-until stopper))))))
|
||||
(defn- resolve-file
|
||||
[file]
|
||||
(->> (fpmap/resolve-file file)
|
||||
(rx/map :data)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [pages-index] :as data}]
|
||||
(->> (rx/from (seq pages-index))
|
||||
(rx/mapcat
|
||||
(fn [[id page]]
|
||||
(let [page (update page :objects ctst/start-page-index)]
|
||||
(->> (uw/ask! {:cmd :initialize-page-index :page page})
|
||||
(rx/map (fn [_] [id page]))))))
|
||||
(rx/reduce conj {})
|
||||
(rx/map (fn [pages-index]
|
||||
(let [data (assoc data :pages-index pages-index)]
|
||||
(assoc file :data (d/removem (comp t/pointer? val) data))))))))))
|
||||
|
||||
(defn- libraries-fetched
|
||||
[libraries]
|
||||
|
@ -240,193 +184,180 @@
|
|||
(rx/concat (rx/timer 1000)
|
||||
(rx/of (dwl/notify-sync-file file-id))))))))
|
||||
|
||||
(defn- datauri->blob-uri
|
||||
[uri]
|
||||
(->> (http/send! {:uri uri
|
||||
:response-type :blob
|
||||
:method :get})
|
||||
(rx/map :body)
|
||||
(rx/map (fn [blob] (wapi/create-uri blob)))))
|
||||
|
||||
(defn- fetch-file-object-thumbnails
|
||||
(defn- fetch-libraries
|
||||
[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 (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-stage-1
|
||||
[project-id file-id]
|
||||
(ptk/reify ::fetch-bundle-stage-1
|
||||
(ptk/reify ::fetch-libries
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [render-wasm? (features/active-feature? state "render-wasm/v1")]
|
||||
(->> (rp/cmd! :get-project {:id project-id})
|
||||
(rx/mapcat (fn [project]
|
||||
(rx/concat
|
||||
;; Wait the wasm module to be loaded or failed to
|
||||
;; load. We need to wait the promise to be resolved
|
||||
;; before continue with the next workspace loading
|
||||
;; steps
|
||||
(watch [_ state _]
|
||||
(let [features (features/get-team-enabled-features state)]
|
||||
(->> (rp/cmd! :get-file-libraries {:file-id file-id})
|
||||
(rx/mapcat
|
||||
(fn [libraries]
|
||||
(rx/merge
|
||||
(->> (rx/from libraries)
|
||||
(rx/merge-map
|
||||
(fn [{:keys [id synced-at]}]
|
||||
(->> (rp/cmd! :get-file {:id id :features features})
|
||||
(rx/map #(assoc % :synced-at synced-at)))))
|
||||
(rx/merge-map resolve-file)
|
||||
(rx/reduce conj [])
|
||||
(rx/map libraries-fetched))
|
||||
(->> (rx/from libraries)
|
||||
(rx/map :id)
|
||||
(rx/mapcat (fn [file-id]
|
||||
(rp/cmd! :get-file-object-thumbnails {:file-id file-id :tag "component"})))
|
||||
(rx/map dwl/library-thumbnails-fetched))))))))))
|
||||
|
||||
(if ^boolean render-wasm?
|
||||
(->> (rx/from @wasm/module)
|
||||
(rx/ignore))
|
||||
(rx/empty))
|
||||
|
||||
(->> (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}]
|
||||
;; FIXME: this should not be handled here, pending
|
||||
;; refactor of urls and team initialization
|
||||
;; normalization
|
||||
(rx/of (dtm/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 project] :as bundle}]
|
||||
(ptk/reify ::fetch-bundle-stage-2
|
||||
(defn- workspace-initialized
|
||||
[]
|
||||
(ptk/reify ::workspace-initialized
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :projects assoc project-id project)))
|
||||
(assoc :workspace-undo {})
|
||||
(assoc :workspace-ready true)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
(watch [_ state _]
|
||||
(rx/of
|
||||
(when (and (not (boolean (-> state :profile :props :v2-info-shown)))
|
||||
(features/active-feature? state "components/v2"))
|
||||
(modal/show :v2-info {}))
|
||||
(dp/check-open-plugin)
|
||||
(fdf/fix-deleted-fonts)
|
||||
(fbs/fix-broken-shapes)))))
|
||||
|
||||
;; WTF is this?
|
||||
share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features :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 (fn [[file thumbnails team-users comments-users]]
|
||||
(let [bundle (-> bundle
|
||||
(assoc :file file)
|
||||
(assoc :features features)
|
||||
(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- bundle-fetched
|
||||
[{:keys [features file thumbnails]}]
|
||||
(ptk/reify ::bundle-fetched
|
||||
IDeref
|
||||
(-deref [_]
|
||||
{:features features
|
||||
:file file
|
||||
:thumbnails thumbnails})
|
||||
|
||||
(declare go-to-component)
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :thumbnails thumbnails)
|
||||
(assoc :workspace-file (dissoc file :data))
|
||||
(assoc :workspace-data (:data 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- fetch-bundle
|
||||
"Multi-stage file bundle fetch coordinator"
|
||||
[project-id file-id]
|
||||
[file-id]
|
||||
(ptk/reify ::fetch-bundle
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rx/merge
|
||||
(rx/of (fetch-bundle-stage-1 project-id file-id))
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
render-wasm? (contains? features "render-wasm/v1")
|
||||
stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)]
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-stage-1))
|
||||
(rx/observe-on :async)
|
||||
(rx/map deref)
|
||||
(rx/map fetch-bundle-stage-2))
|
||||
(->> (rx/concat
|
||||
;; Firstly load wasm module if it is enabled and fonts
|
||||
(rx/merge
|
||||
(if ^boolean render-wasm?
|
||||
(->> (rx/from @wasm/module)
|
||||
(rx/ignore))
|
||||
(rx/empty))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-stage-2))
|
||||
(rx/observe-on :async)
|
||||
(rx/map deref)
|
||||
(rx/map bundle-fetched))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::df/fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
(rx/of (df/fetch-fonts)))
|
||||
|
||||
(when-let [component-id (get-in state [:route :query-params :component-id])]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
;; 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/map #(go-to-component (uuid/uuid component-id))))))
|
||||
(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
|
||||
(rx/filter (ptk/type? ::fetch-bundle) stream))))))
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
(defn initialize-file
|
||||
[project-id file-id]
|
||||
(dm/assert! (uuid? project-id))
|
||||
(dm/assert! (uuid? file-id))
|
||||
(defn initialize-workspace
|
||||
[file-id]
|
||||
(assert (uuid? file-id) "expected valud uuid for `file-id`")
|
||||
|
||||
(ptk/reify ::initialize-file
|
||||
(ptk/reify ::initialize-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state
|
||||
:recent-colors (:recent-colors storage/user)
|
||||
:workspace-ready? false
|
||||
:workspace-ready false
|
||||
:current-file-id file-id
|
||||
:current-project-id project-id
|
||||
:workspace-presence {}))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(log/debug :hint "initialize-file" :file-id file-id)
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-file) stream)]
|
||||
(rx/merge
|
||||
(rx/of (ntf/hide)
|
||||
;; We initialize the features without knowning the
|
||||
;; team specific features in this step.
|
||||
(features/initialize)
|
||||
(dcm/retrieve-comment-threads file-id)
|
||||
(fetch-bundle project-id file-id))
|
||||
(watch [_ state stream]
|
||||
(log/debug :hint "initialize-workspace" :file-id file-id)
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||
rparams (rt/get-params state)]
|
||||
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||
(if (and save-undo? (seq undo-changes))
|
||||
(let [entry {:undo-changes undo-changes
|
||||
:redo-changes redo-changes
|
||||
:undo-group undo-group
|
||||
:tags tags}]
|
||||
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||
(rx/empty))))
|
||||
(->> (rx/merge
|
||||
(rx/of (ntf/hide)
|
||||
(dcmt/retrieve-comment-threads file-id)
|
||||
(dcmt/fetch-profiles)
|
||||
(fetch-bundle file-id))
|
||||
|
||||
(rx/take-until stoper-s)))))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-fetched))
|
||||
(rx/take 1)
|
||||
(rx/map deref)
|
||||
(rx/mapcat (fn [{:keys [file]}]
|
||||
(rx/of (dpj/initialize-project (:project-id file))
|
||||
(-> (workspace-initialized)
|
||||
(with-meta {:file-id file-id}))))))
|
||||
|
||||
(when-let [component-id (some-> rparams :component-id parse-uuid)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
(rx/take 1)
|
||||
(rx/map #(dwl/go-to-local-component :id component-id))))
|
||||
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||
(if (and save-undo? (seq undo-changes))
|
||||
(let [entry {:undo-changes undo-changes
|
||||
:redo-changes redo-changes
|
||||
:undo-group undo-group
|
||||
:tags tags}]
|
||||
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||
(rx/empty))))))
|
||||
(rx/take-until stoper-s))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(let [name (dm/str "workspace-" file-id)]
|
||||
(unchecked-set ug/global "name" name)))))
|
||||
|
||||
(defn reload-file
|
||||
[]
|
||||
(ptk/reify ::reload-file
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)
|
||||
project-id (:current-project-id state)]
|
||||
(rx/of (initialize-file project-id file-id))))))
|
||||
|
||||
;; We need to inject this so there are no cycles
|
||||
(set! app.main.data.workspace.notifications/reload-file reload-file)
|
||||
(set! app.main.errors/reload-file reload-file)
|
||||
|
||||
(defn finalize-file
|
||||
[_project-id file-id]
|
||||
(defn finalize-workspace
|
||||
[file-id]
|
||||
(ptk/reify ::finalize-file
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(dissoc
|
||||
:current-file-id
|
||||
:current-project-id
|
||||
:workspace-data
|
||||
:workspace-editor-state
|
||||
:workspace-file
|
||||
|
@ -434,22 +365,37 @@
|
|||
:workspace-media-objects
|
||||
:workspace-persistence
|
||||
:workspace-presence
|
||||
:workspace-ready?
|
||||
:workspace-ready
|
||||
:workspace-undo)
|
||||
(update :workspace-global dissoc :read-only?)
|
||||
(assoc-in [:workspace-global :options-mode] :design)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (dwn/finalize file-id)
|
||||
(dwsl/finalize)))))
|
||||
(watch [_ state _]
|
||||
(let [project-id (:current-project-id state)]
|
||||
|
||||
(declare go-to-page)
|
||||
(declare ^:private preload-data-uris)
|
||||
(rx/of (dwn/finalize file-id)
|
||||
(dpj/finalize-project project-id)
|
||||
(dwsl/finalize-shape-layout)
|
||||
(dwcl/stop-picker)
|
||||
(modal/hide)
|
||||
(ntf/hide))))))
|
||||
|
||||
(defn- reload-current-file
|
||||
[]
|
||||
(ptk/reify ::reload-current-file
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/of (initialize-workspace file-id))))))
|
||||
|
||||
;; Make this event callable through dynamic resolution
|
||||
(defmethod ptk/resolve ::reload-current-file [_ _] (reload-current-file))
|
||||
|
||||
(defn initialize-page
|
||||
[page-id]
|
||||
(dm/assert! (uuid? page-id))
|
||||
(assert (uuid? page-id) "expected valid uuid for `page-id`")
|
||||
|
||||
(ptk/reify ::initialize-page
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -464,30 +410,20 @@
|
|||
|
||||
;; FIXME: this should be done on `initialize-layout` (?)
|
||||
(update :workspace-layout layout/load-layout-flags)
|
||||
(update :workspace-global layout/load-layout-state)
|
||||
|
||||
(update :workspace-global assoc :background-color (-> page :options :background))
|
||||
(update-in [:route :params :query] assoc :page-id (dm/str id))))
|
||||
(update :workspace-global layout/load-layout-state)))
|
||||
|
||||
state))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
;; NOTE: there are cases between files navigation when this
|
||||
;; event is emmited but the page-index is still not loaded, so
|
||||
;; we only need to proceed when page-index is properly loaded
|
||||
(when-let [pindex (-> state :workspace-data :pages-index)]
|
||||
(if (contains? pindex page-id)
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/of (preload-data-uris page-id)
|
||||
(dwth/watch-state-changes file-id page-id)
|
||||
(dwl/watch-component-changes)))
|
||||
(let [page-id (dm/get-in state [:workspace-data :pages 0])]
|
||||
(rx/of (go-to-page page-id))))))))
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/of (preload-data-uris page-id)
|
||||
(dwth/watch-state-changes file-id page-id)
|
||||
(dwl/watch-component-changes))))))
|
||||
|
||||
(defn finalize-page
|
||||
[page-id]
|
||||
(dm/assert! (uuid? page-id))
|
||||
(assert (uuid? page-id) "expected valid uuid for `page-id`")
|
||||
(ptk/reify ::finalize-page
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -683,7 +619,7 @@
|
|||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(when (= id (:current-page-id state))
|
||||
go-to-file))))))
|
||||
(go-to-file)))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; WORKSPACE File Actions
|
||||
|
@ -847,7 +783,7 @@
|
|||
(let [selected (wsh/lookup-selected state)
|
||||
id (first selected)]
|
||||
(when (= (count selected) 1)
|
||||
(rx/of (go-to-layout :layers)
|
||||
(rx/of (dcm/go-to-workspace :layout :layers)
|
||||
(start-rename-shape id)))))))
|
||||
|
||||
;; --- Shape Vertical Ordering
|
||||
|
@ -1111,76 +1047,17 @@
|
|||
(rx/of (dwsh/update-shapes selected #(assoc % :proportion-lock true)))
|
||||
(rx/of (dwsh/update-shapes selected #(update % :proportion-lock not))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Navigation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn workspace-focus-lost
|
||||
[]
|
||||
(ptk/reify ::workspace-focus-lost
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
;; FIXME: remove the `?` from show-distances?
|
||||
(assoc-in state [:workspace-global :show-distances?] false))))
|
||||
|
||||
(defn navigate-to-project
|
||||
[project-id]
|
||||
(ptk/reify ::navigate-to-project
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-ids (get-in state [:projects project-id :pages])
|
||||
params {:project project-id :page (first page-ids)}]
|
||||
(rx/of (rt/nav :workspace/page params))))))
|
||||
|
||||
(defn go-to-page
|
||||
([]
|
||||
(ptk/reify ::go-to-page
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (:current-project-id state)
|
||||
file-id (:current-file-id state)
|
||||
page-id (get-in state [:workspace-data :pages 0])
|
||||
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id page-id}]
|
||||
(rx/of (rt/nav' :workspace pparams qparams))))))
|
||||
([page-id]
|
||||
(dm/assert! (uuid? page-id))
|
||||
(ptk/reify ::go-to-page-2
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (:current-project-id state)
|
||||
file-id (:current-file-id state)
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id page-id}]
|
||||
(rx/of (rt/nav :workspace pparams qparams)))))))
|
||||
|
||||
(defn go-to-layout
|
||||
[layout]
|
||||
(ptk/reify ::go-to-layout
|
||||
IDeref
|
||||
(-deref [_] {:layout layout})
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (:current-project-id state)
|
||||
file-id (:current-file-id state)
|
||||
page-id (:current-page-id state)
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id page-id :layout (name layout)}]
|
||||
(rx/of (rt/nav :workspace pparams qparams))))))
|
||||
|
||||
(defn navigate-to-library
|
||||
"Open a new tab, and navigate to the workspace with the provided file"
|
||||
[library-id]
|
||||
(ptk/reify ::navigate-to-file
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [file (dm/get-in state [:workspace-libraries library-id])]
|
||||
(let [params {:rname :workspace
|
||||
:path-params {:project-id (:project-id file)
|
||||
:file-id (:id file)}
|
||||
:query-params {:page-id (dm/get-in file [:data :pages 0])}}]
|
||||
(rx/of (rt/nav-new-window* params)))))))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Navigation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn set-assets-section-open
|
||||
[file-id section open?]
|
||||
|
@ -1242,111 +1119,18 @@
|
|||
(update-in state [:workspace-assets :selected] dissoc file-id)
|
||||
(update state :workspace-assets dissoc :selected))))))
|
||||
|
||||
(defn go-to-main-instance
|
||||
[file-id component-id]
|
||||
(dm/assert!
|
||||
"expected uuid type for `file-id` parameter (nilable)"
|
||||
(or (nil? file-id)
|
||||
(uuid? file-id)))
|
||||
|
||||
(dm/assert!
|
||||
"expected uuid type for `component-id` parameter"
|
||||
(uuid? component-id))
|
||||
|
||||
(ptk/reify ::go-to-main-instance
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [current-file-id (:current-file-id state)
|
||||
current-page-id (:current-page-id state)
|
||||
current-project-id (:current-project-id state)
|
||||
file-id (or file-id current-file-id)
|
||||
|
||||
select-and-zoom
|
||||
(fn [shape-id]
|
||||
(rx/of (dws/select-shapes (d/ordered-set shape-id))
|
||||
dwz/zoom-to-selected-shape))
|
||||
|
||||
redirect-to-page
|
||||
(fn [page-id shape-id]
|
||||
(rx/concat
|
||||
(rx/of (go-to-page page-id))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::initialize-page))
|
||||
(rx/take 1)
|
||||
(rx/observe-on :async))
|
||||
(select-and-zoom shape-id)))
|
||||
|
||||
redirect-to-file
|
||||
(fn [file-id page-id]
|
||||
(let [pparams {:file-id file-id :project-id current-project-id}
|
||||
qparams {:page-id page-id}]
|
||||
(rx/merge
|
||||
(rx/of (rt/nav :workspace pparams qparams))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/map meta)
|
||||
(rx/filter #(= file-id (:file-id %)))
|
||||
(rx/take 1)
|
||||
(rx/observe-on :async)
|
||||
(rx/map #(go-to-main-instance file-id component-id))))))]
|
||||
|
||||
(if (= file-id current-file-id)
|
||||
(let [component (dm/get-in state [:workspace-data :components component-id])
|
||||
page-id (:main-instance-page component)
|
||||
shape-id (:main-instance-id component)]
|
||||
(when (some? page-id)
|
||||
(if (= page-id current-page-id)
|
||||
(select-and-zoom shape-id)
|
||||
(redirect-to-page page-id shape-id))))
|
||||
|
||||
(let [component (dm/get-in state [:workspace-libraries file-id :data :components component-id])]
|
||||
(some->> (:main-instance-page component)
|
||||
(redirect-to-file file-id))))))))
|
||||
|
||||
(defn go-to-component
|
||||
[component-id]
|
||||
(ptk/reify ::go-to-component
|
||||
IDeref
|
||||
(-deref [_] {:layout :assets})
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [components-v2 (features/active-feature? state "components/v2")]
|
||||
(if components-v2
|
||||
(rx/of (go-to-main-instance nil component-id))
|
||||
(let [file-id (:current-file-id state)
|
||||
project-id (:current-project-id state)
|
||||
page-id (:current-page-id state)
|
||||
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id page-id :layout :assets}]
|
||||
(rx/of (rt/nav :workspace pparams qparams)
|
||||
(set-assets-section-open file-id :library true)
|
||||
(set-assets-section-open file-id :components true)
|
||||
(select-single-asset file-id component-id :components))))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(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))))))))
|
||||
|
||||
(defn show-component-in-assets
|
||||
[component-id]
|
||||
|
||||
(ptk/reify ::show-component-in-assets
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (:current-project-id state)
|
||||
file-id (:current-file-id state)
|
||||
page-id (:current-page-id state)
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id page-id :layout :assets}
|
||||
component-path (cfh/split-path (get-in state [:workspace-data :components component-id :path]))
|
||||
paths (map (fn [i] (cfh/join-path (take (inc i) component-path))) (range (count component-path)))]
|
||||
(let [component-path (cfh/split-path (get-in state [:workspace-data :components component-id :path]))
|
||||
paths (map (fn [i] (cfh/join-path (take (inc i) component-path))) (range (count component-path)))
|
||||
file-id (:current-file-id state)]
|
||||
(rx/concat
|
||||
(rx/from (map #(set-assets-group-open file-id :components % true) paths))
|
||||
(rx/of (rt/nav :workspace pparams qparams)
|
||||
(rx/of (dcm/go-to-workspace :layout :assets)
|
||||
(set-assets-section-open file-id :library true)
|
||||
(set-assets-section-open file-id :components true)
|
||||
(select-single-asset file-id component-id :components)))))
|
||||
|
@ -1356,55 +1140,6 @@
|
|||
(let [wrapper-id (str "component-shape-id-" component-id)]
|
||||
(tm/schedule-on-idle #(dom/scroll-into-view-if-needed! (dom/get-element wrapper-id)))))))
|
||||
|
||||
(def go-to-file
|
||||
(ptk/reify ::go-to-file
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [{:keys [id project-id data] :as file} (:workspace-file state)
|
||||
page-id (get-in data [:pages 0])
|
||||
pparams {:project-id project-id :file-id id}
|
||||
qparams {:page-id page-id}]
|
||||
(rx/of (rt/nav :workspace pparams qparams))))))
|
||||
|
||||
(defn go-to-viewer
|
||||
([] (go-to-viewer {}))
|
||||
([{:keys [file-id page-id section frame-id]}]
|
||||
(ptk/reify ::go-to-viewer
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [{:keys [current-file-id current-page-id]} state
|
||||
pparams {:file-id (or file-id current-file-id)}
|
||||
qparams (cond-> {:page-id (or page-id current-page-id)}
|
||||
(some? section)
|
||||
(assoc :section section)
|
||||
(some? frame-id)
|
||||
(assoc :frame-id frame-id))]
|
||||
(rx/of ::dps/force-persist
|
||||
(rt/nav-new-window* {:rname :viewer
|
||||
:path-params pparams
|
||||
:query-params qparams
|
||||
:name (str "viewer-" (:file-id pparams))})))))))
|
||||
|
||||
(defn go-to-dashboard
|
||||
([] (go-to-dashboard nil))
|
||||
([{:keys [team-id]}]
|
||||
(ptk/reify ::go-to-dashboard
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [team-id (or team-id (:current-team-id state))]
|
||||
(rx/of ::dps/force-persist
|
||||
(rt/nav :dashboard-projects {:team-id team-id})))))))
|
||||
|
||||
(defn go-to-dashboard-fonts
|
||||
[]
|
||||
(ptk/reify ::go-to-dashboard-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of ::dps/force-persist
|
||||
(rt/nav :dashboard-fonts {:team-id team-id}))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Context Menu
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1640,8 +1375,8 @@
|
|||
(rx/catch on-copy-error)
|
||||
(rx/ignore)))
|
||||
|
||||
;; FIXME: this is to support Firefox versions below 116 that don't support `ClipboardItem`
|
||||
;; after the version 116 is less common we could remove this.
|
||||
;; FIXME: this is to support Firefox versions below 116 that don't support
|
||||
;; `ClipboardItem` after the version 116 is less common we could remove this.
|
||||
;; https://caniuse.com/?search=ClipboardItem
|
||||
(->> (rx/from shapes)
|
||||
(rx/merge-map (partial prepare-object objects frame-id))
|
||||
|
@ -1924,7 +1659,8 @@
|
|||
;; the pasted object doesn't fit we try to:
|
||||
;;
|
||||
;; - Align it to the limits on the x and y axis
|
||||
;; - Respect the distance of the object to the right and bottom in the original frame
|
||||
;; - Respect the distance of the object to the right
|
||||
;; and bottom in the original frame
|
||||
(gpt/point paste-x paste-y))]
|
||||
[frame-id delta (dec (count (:shapes selected-frame-obj)))]))
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
[app.common.schema :as sm]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.comments :as dcmt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwco]
|
||||
|
@ -23,7 +24,6 @@
|
|||
[app.main.repo :as rp]
|
||||
[app.main.streams :as ms]
|
||||
[app.util.mouse :as mse]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
|||
(watch [_ _ stream]
|
||||
(let [stopper (rx/filter #(= ::finalize %) stream)]
|
||||
(rx/merge
|
||||
(rx/of (dcm/retrieve-comment-threads file-id))
|
||||
(rx/of (dcmt/retrieve-comment-threads file-id))
|
||||
(->> stream
|
||||
(rx/filter mse/mouse-event?)
|
||||
(rx/filter mse/mouse-click-event?)
|
||||
|
@ -60,8 +60,8 @@
|
|||
(watch [_ state _]
|
||||
(let [local (:comments-local state)]
|
||||
(cond
|
||||
(:draft local) (rx/of (dcm/close-thread))
|
||||
(:open local) (rx/of (dcm/close-thread))
|
||||
(:draft local) (rx/of (dcmt/close-thread))
|
||||
(:open local) (rx/of (dcmt/close-thread))
|
||||
|
||||
:else
|
||||
(rx/of (dw/clear-edition-mode)
|
||||
|
@ -78,19 +78,19 @@
|
|||
(watch [_ state _]
|
||||
(let [local (:comments-local state)]
|
||||
(if (some? (:open local))
|
||||
(rx/of (dcm/close-thread))
|
||||
(rx/of (dcmt/close-thread))
|
||||
(let [page-id (:current-page-id state)
|
||||
file-id (:current-file-id state)
|
||||
params {:position position
|
||||
:page-id page-id
|
||||
:file-id file-id}]
|
||||
(rx/of (dcm/create-draft params))))))))
|
||||
(rx/of (dcmt/create-draft params))))))))
|
||||
|
||||
(defn center-to-comment-thread
|
||||
[{:keys [position] :as thread}]
|
||||
(dm/assert!
|
||||
"expected valid comment thread"
|
||||
(dcm/check-comment-thread! thread))
|
||||
(dcmt/check-comment-thread! thread))
|
||||
|
||||
(ptk/reify ::center-to-comment-thread
|
||||
ptk/UpdateEvent
|
||||
|
@ -109,22 +109,21 @@
|
|||
[thread]
|
||||
(dm/assert!
|
||||
"expected valid comment thread"
|
||||
(dcm/check-comment-thread! thread))
|
||||
(dcmt/check-comment-thread! thread))
|
||||
(ptk/reify ::open-comment-thread
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [pparams {:project-id (:project-id thread)
|
||||
:file-id (:file-id thread)}
|
||||
qparams {:page-id (:page-id thread)}]
|
||||
(rx/merge
|
||||
(rx/of (rt/nav :workspace pparams qparams))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dwv/initialize-viewport))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rx/of (center-to-comment-thread thread)
|
||||
(dwd/select-for-drawing :comments)
|
||||
(with-meta (dcm/open-thread thread)
|
||||
{::ev/origin "workspace"})))))))))
|
||||
(rx/merge
|
||||
(rx/of (dcm/go-to-workspace :file-id (:file-id thread)
|
||||
:page-id (:page-id thread)))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dwv/initialize-viewport))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rx/of (center-to-comment-thread thread)
|
||||
(dwd/select-for-drawing :comments)
|
||||
(with-meta (dcmt/open-thread thread)
|
||||
{::ev/origin "workspace"}))))))))
|
||||
|
||||
(defn update-comment-thread-position
|
||||
([thread [new-x new-y]]
|
||||
|
@ -133,7 +132,7 @@
|
|||
([thread [new-x new-y] frame-id]
|
||||
(dm/assert!
|
||||
"expected valid comment thread"
|
||||
(dcm/check-comment-thread! thread))
|
||||
(dcmt/check-comment-thread! thread))
|
||||
(ptk/reify ::update-comment-thread-position
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
[app.config :as cf]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.comments :as dc]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
|
@ -40,14 +41,15 @@
|
|||
[app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.data.workspace.transforms :as dwtr]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.features :as features]
|
||||
[app.main.features.pointer-map :as fpmap]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.util.color :as uc]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.time :as dt]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -684,21 +686,49 @@
|
|||
(rx/of (when can-detach?
|
||||
(dch/commit-changes changes)))))))
|
||||
|
||||
(defn nav-to-component-file
|
||||
(defn go-to-component-file
|
||||
[file-id component]
|
||||
(dm/assert! (uuid? file-id))
|
||||
(dm/assert! (some? component))
|
||||
(ptk/reify ::nav-to-component-file
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [project-id (get-in state [:workspace-libraries file-id :project-id])
|
||||
path-params {:project-id project-id
|
||||
:file-id file-id}
|
||||
query-params {:page-id (:main-instance-page component)
|
||||
:component-id (:id component)}]
|
||||
(rx/of (rt/nav-new-window* {:rname :workspace
|
||||
:path-params path-params
|
||||
:query-params query-params}))))))
|
||||
(let [params (-> (rt/get-params state)
|
||||
(assoc :file-id file-id)
|
||||
(assoc :page-id (:main-instance-page component))
|
||||
(assoc :component-id (:id component)))]
|
||||
(rx/of (rt/nav :workspace params :new-window? true))))))
|
||||
|
||||
|
||||
(defn go-to-local-component
|
||||
[& {:keys [id] :as options}]
|
||||
(ptk/reify ::go-to-local-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [current-page-id (:current-page-id state)
|
||||
|
||||
select-and-zoom
|
||||
(fn [shape-id]
|
||||
(rx/of (dws/select-shapes (d/ordered-set shape-id))
|
||||
dwz/zoom-to-selected-shape))
|
||||
|
||||
redirect-to-page
|
||||
(fn [page-id shape-id]
|
||||
(rx/merge
|
||||
(rx/of (dcm/go-to-workspace :page-id page-id))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::initialize-page))
|
||||
(rx/take 1)
|
||||
(rx/observe-on :async)
|
||||
(rx/mapcat (fn [_] (select-and-zoom shape-id))))))]
|
||||
|
||||
(when-let [component (dm/get-in state [:workspace-data :components id])]
|
||||
(let [page-id (:main-instance-page component)
|
||||
shape-id (:main-instance-id component)]
|
||||
(when (some? page-id)
|
||||
(if (= page-id current-page-id)
|
||||
(select-and-zoom shape-id)
|
||||
(redirect-to-page page-id shape-id)))))))))
|
||||
|
||||
(defn library-thumbnails-fetched
|
||||
[thumbnails]
|
||||
|
@ -1117,9 +1147,11 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(rp/cmd! :ignore-file-library-sync-status
|
||||
{:file-id (get-in state [:workspace-file :id])
|
||||
:date (dt/now)}))))
|
||||
(let [file-id (:current-file-id state)]
|
||||
(->> (rp/cmd! :ignore-file-library-sync-status
|
||||
{:file-id file-id
|
||||
:date (dt/now)})
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn assets-need-sync
|
||||
"Get a lazy sequence of all the assets of each type in the library that have
|
||||
|
@ -1309,23 +1341,6 @@
|
|||
(->> (rp/cmd! :set-file-shared params)
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn- shared-files-fetched
|
||||
[files]
|
||||
(ptk/reify ::shared-files-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [state (dissoc state :files)]
|
||||
(assoc state :workspace-shared-files files)))))
|
||||
|
||||
(defn fetch-shared-files
|
||||
[{:keys [team-id] :as params}]
|
||||
(dm/assert! (uuid? team-id))
|
||||
(ptk/reify ::fetch-shared-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-team-shared-files {:team-id team-id})
|
||||
(rx/map shared-files-fetched)))))
|
||||
|
||||
;; --- Link and unlink Files
|
||||
|
||||
(defn link-file-to-library
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.main.data.modal :as modal]
|
||||
[app.main.data.plugins :as dpl]
|
||||
[app.main.data.websocket :as dws]
|
||||
[app.main.data.workspace :as-alias dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.layout :as dwly]
|
||||
|
@ -30,9 +31,6 @@
|
|||
[clojure.set :as set]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; From app.main.data.workspace we can use directly because it causes a circular dependency
|
||||
(def reload-file nil)
|
||||
|
||||
;; FIXME: this ns should be renamed to something different
|
||||
|
||||
(declare process-message)
|
||||
|
@ -292,7 +290,7 @@
|
|||
curr-vern (dm/get-in state [:workspace-file :vern])
|
||||
reload? (and (= file-id curr-file-id) (not= vern curr-vern))]
|
||||
(when reload?
|
||||
(rx/of (reload-file)))))))
|
||||
(rx/of (ptk/event ::dw/reload-current-file)))))))
|
||||
|
||||
(def ^:private schema:handle-library-change
|
||||
[:map {:title "handle-library-change"}
|
||||
|
|
|
@ -110,13 +110,15 @@
|
|||
:undo-group undo-group})))
|
||||
(rx/empty))))))
|
||||
|
||||
(defn initialize
|
||||
(defn initialize-shape-layout
|
||||
[]
|
||||
(ptk/reify ::initialize
|
||||
(ptk/reify ::initialize-shape-layout
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [stopper (rx/filter (ptk/type? ::finalize) stream)]
|
||||
(let [stopper (rx/filter (ptk/type? ::finalize-shape-layout) stream)]
|
||||
(->> stream
|
||||
;; FIXME: we don't need use types for simple signaling,
|
||||
;; we can just use a keyword for it
|
||||
(rx/filter (ptk/type? :layout/update))
|
||||
(rx/map deref)
|
||||
;; We buffer the updates to the layout so if there are many changes at the same time
|
||||
|
@ -129,9 +131,9 @@
|
|||
(update-layout-positions {:ids ids}))))
|
||||
(rx/take-until stopper))))))
|
||||
|
||||
(defn finalize
|
||||
(defn finalize-shape-layout
|
||||
[]
|
||||
(ptk/reify ::finalize))
|
||||
(ptk/data-event ::finalize-shape-layout))
|
||||
|
||||
(defn create-layout-from-id
|
||||
[id type & {:keys [from-frame? calculate-params?] :or {from-frame? false calculate-params? true}}]
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns app.main.data.workspace.shortcuts
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.exports.assets :as de]
|
||||
[app.main.data.modal :as modal]
|
||||
|
@ -440,17 +441,18 @@
|
|||
:toggle-layers {:tooltip (ds/alt "L")
|
||||
:command (ds/a-mod "l")
|
||||
:subsections [:panels]
|
||||
:fn #(st/emit! (dw/go-to-layout :layers))}
|
||||
:fn #(st/emit! (dcm/go-to-workspace :layout :layers))}
|
||||
|
||||
:toggle-assets {:tooltip (ds/alt "I")
|
||||
:command (ds/a-mod "i")
|
||||
:subsections [:panels]
|
||||
:fn #(st/emit! (dw/go-to-layout :assets))}
|
||||
:fn #(st/emit! (dcm/go-to-workspace :layout :assets))}
|
||||
|
||||
:toggle-history {:tooltip (ds/alt "H")
|
||||
:command (ds/a-mod "h")
|
||||
:subsections [:panels]
|
||||
:fn #(emit-when-no-readonly (dw/go-to-layout :document-history))}
|
||||
:fn #(emit-when-no-readonly
|
||||
(dcm/go-to-workspace :layout :document-history))}
|
||||
|
||||
:toggle-colorpalette {:tooltip (ds/alt "P")
|
||||
:command (ds/a-mod "p")
|
||||
|
@ -516,22 +518,22 @@
|
|||
:open-viewer {:tooltip "G V"
|
||||
:command "g v"
|
||||
:subsections [:navigation-workspace]
|
||||
:fn #(st/emit! (dw/go-to-viewer))}
|
||||
:fn #(st/emit! (dcm/go-to-viewer))}
|
||||
|
||||
:open-inspect {:tooltip "G I"
|
||||
:command "g i"
|
||||
:subsections [:navigation-workspace]
|
||||
:fn #(st/emit! (dw/go-to-viewer {:section :inspect}))}
|
||||
:fn #(st/emit! (dcm/go-to-viewer :section :inspect))}
|
||||
|
||||
:open-comments {:tooltip "G C"
|
||||
:command "g c"
|
||||
:subsections [:navigation-workspace]
|
||||
:fn #(st/emit! (dw/go-to-viewer {:section :comments}))}
|
||||
:fn #(st/emit! (dcm/go-to-viewer :section :comments))}
|
||||
|
||||
:open-dashboard {:tooltip "G D"
|
||||
:command "g d"
|
||||
:subsections [:navigation-workspace]
|
||||
:fn #(st/emit! (dw/go-to-dashboard))}
|
||||
:fn #(st/emit! (dcm/go-to-dashboard-recent))}
|
||||
|
||||
:select-prev {:tooltip (ds/shift "tab")
|
||||
:command "shift+tab"
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
(-> (lookup-page state page-id)
|
||||
(get :objects))))
|
||||
|
||||
(defn lookup-viewer-objects
|
||||
([state page-id]
|
||||
(dm/get-in state [:viewer :pages page-id :objects])))
|
||||
|
||||
(defn lookup-library-objects
|
||||
[state file-id page-id]
|
||||
(dm/get-in state [:workspace-libraries file-id :data :pages-index page-id :objects]))
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.features :as features]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.util.router :as rt]
|
||||
[app.main.router :as rt]
|
||||
[app.util.text-editor :as ted]
|
||||
[app.util.text.content.styles :as styles]
|
||||
[app.util.timers :as ts]
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
[app.common.schema :as sm]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.util.router :as rt]
|
||||
[app.util.time :as dt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -290,14 +290,8 @@
|
|||
(ptk/reify ::assure-valid-current-page
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [current_page (:current-page-id state)
|
||||
pages (get-in state [:workspace-data :pages])
|
||||
exists? (some #(= current_page %) pages)
|
||||
|
||||
project-id (:current-project-id state)
|
||||
file-id (:current-file-id state)
|
||||
pparams {:file-id file-id :project-id project-id}
|
||||
qparams {:page-id (first pages)}]
|
||||
(if exists?
|
||||
(let [page-id (:current-page-id state)
|
||||
pages (dm/get-in state [:workspace-data :pages])]
|
||||
(if (contains? pages page-id)
|
||||
(rx/empty)
|
||||
(rx/of (rt/nav :workspace pparams qparams)))))))
|
||||
(rx/of (dcm/go-to-workspace :page-id (first pages))))))))
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.persistence :as dwp]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -25,7 +26,7 @@
|
|||
(declare fetch-versions)
|
||||
|
||||
(defn init-version-state
|
||||
[file-id]
|
||||
[]
|
||||
(ptk/reify ::init-version-state
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -33,7 +34,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (fetch-versions file-id)))))
|
||||
(rx/of (fetch-versions)))))
|
||||
|
||||
(defn update-version-state
|
||||
[version-state]
|
||||
|
@ -43,123 +44,90 @@
|
|||
(update state :workspace-versions merge version-state))))
|
||||
|
||||
(defn fetch-versions
|
||||
[file-id]
|
||||
(dm/assert! (uuid? file-id))
|
||||
[]
|
||||
(ptk/reify ::fetch-versions
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-file-snapshots {:file-id file-id})
|
||||
(rx/map #(update-version-state {:status :loaded :data %}))))))
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(->> (rp/cmd! :get-file-snapshots {:file-id file-id})
|
||||
(rx/map #(update-version-state {:status :loaded :data %})))))))
|
||||
|
||||
(defn create-version
|
||||
[file-id]
|
||||
(dm/assert! (uuid? file-id))
|
||||
[]
|
||||
(ptk/reify ::create-version
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [label (dt/format (dt/now) :date-full)]
|
||||
(watch [_ state _]
|
||||
(let [label (dt/format (dt/now) :date-full)
|
||||
file-id (:current-file-id state)]
|
||||
|
||||
;; Force persist before creating snapshot, otherwise we could loss changes
|
||||
(rx/concat
|
||||
(rx/of ::dwp/force-persist)
|
||||
(rx/of ::dwp/force-persist
|
||||
(ptk/event ::ev/event {::ev/name "create-version"}))
|
||||
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :create-file-snapshot {:file-id file-id :label label}))
|
||||
(rx/mapcat
|
||||
(fn [{:keys [id]}]
|
||||
(rx/of
|
||||
(update-version-state {:editing id})
|
||||
(fetch-versions file-id)))))
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "create-version"})))))))
|
||||
|
||||
(defn create-version-from-plugins
|
||||
[file-id label resolve reject]
|
||||
(dm/assert! (uuid? file-id))
|
||||
(ptk/reify ::create-version-plugins
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
;; Force persist before creating snapshot, otherwise we could loss changes
|
||||
(->> (rx/concat
|
||||
(rx/of ::dwp/force-persist)
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :create-file-snapshot {:file-id file-id :label label}))
|
||||
|
||||
(rx/mapcat
|
||||
(fn [{:keys [id]}]
|
||||
(->> (rp/cmd! :get-file-snapshots {:file-id file-id})
|
||||
(rx/take 1)
|
||||
(rx/map (fn [versions] (d/seek #(= id (:id %)) versions))))))
|
||||
(rx/tap resolve)
|
||||
(rx/ignore))
|
||||
(rx/of (ptk/event ::ev/event {::ev/origin "plugins"
|
||||
::ev/name "create-version"})))
|
||||
|
||||
;; On error reject the promise and empty the stream
|
||||
(rx/catch (fn [error]
|
||||
(reject error)
|
||||
(rx/empty)))))))
|
||||
(rx/of (update-version-state {:editing id})
|
||||
(fetch-versions))))))))))
|
||||
|
||||
(defn rename-version
|
||||
[file-id id label]
|
||||
(dm/assert! (uuid? file-id))
|
||||
(dm/assert! (uuid? id))
|
||||
(dm/assert! (and (string? label) (d/not-empty? label)))
|
||||
[id label]
|
||||
(assert (uuid? id) "expected valid uuid for `id`")
|
||||
(assert (sm/valid-text? label) "expected not empty string for `label`")
|
||||
|
||||
(ptk/reify ::rename-version
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/merge
|
||||
(rx/of (update-version-state {:editing false}))
|
||||
(->> (rp/cmd! :update-file-snapshot {:id id :label label})
|
||||
(rx/map #(fetch-versions file-id)))
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "rename-version"}))))))
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/merge
|
||||
(rx/of (update-version-state {:editing false})
|
||||
(ptk/event ::ev/event {::ev/name "rename-version"
|
||||
:file-id file-id}))
|
||||
(->> (rp/cmd! :update-file-snapshot {:id id :label label})
|
||||
(rx/map fetch-versions)))))))
|
||||
|
||||
(defn restore-version
|
||||
[project-id file-id id origin]
|
||||
(dm/assert! (uuid? project-id))
|
||||
(dm/assert! (uuid? file-id))
|
||||
(dm/assert! (uuid? id))
|
||||
[id origin]
|
||||
(assert (uuid? id) "expected valid uuid for `id`")
|
||||
|
||||
(ptk/reify ::restore-version
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/concat
|
||||
(rx/of ::dwp/force-persist)
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||
(rx/map #(dw/initialize-file project-id file-id)))
|
||||
(case origin
|
||||
:version
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/concat
|
||||
(rx/of ::dwp/force-persist)
|
||||
|
||||
:snapshot
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-autosave"}))
|
||||
;; FIXME: we should abstract this
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||
(rx/map #(dw/initialize-workspace file-id)))
|
||||
|
||||
:plugin
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"}))
|
||||
|
||||
(rx/empty))))))
|
||||
(when-let [name (case origin
|
||||
:version "restore-pin-version"
|
||||
:snapshot "restore-autosave"
|
||||
:plugin "restore-version-plugin"
|
||||
nil)]
|
||||
(rx/of (ptk/event ::ev/event {::ev/name name}))))))))
|
||||
|
||||
(defn delete-version
|
||||
[file-id id]
|
||||
(dm/assert! (uuid? file-id))
|
||||
(dm/assert! (uuid? id))
|
||||
[id]
|
||||
(assert (uuid? id) "expected valid uuid for `id`")
|
||||
|
||||
(ptk/reify ::delete-version
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :delete-file-snapshot {:id id})
|
||||
(rx/map #(fetch-versions file-id))))))
|
||||
(rx/map fetch-versions)))))
|
||||
|
||||
(defn pin-version
|
||||
[file-id id]
|
||||
(dm/assert! (uuid? file-id))
|
||||
(dm/assert! (uuid? id))
|
||||
|
||||
[id]
|
||||
(assert (uuid? id) "expected valid uuid for `id`")
|
||||
(ptk/reify ::pin-version
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -168,8 +136,82 @@
|
|||
params {:id id
|
||||
:label (dt/format (:created-at version) :date-full)}]
|
||||
|
||||
(rx/concat
|
||||
(->> (rp/cmd! :update-file-snapshot params)
|
||||
(rx/mapcat #(rx/of (update-version-state {:editing id})
|
||||
(fetch-versions file-id))))
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "pin-version"})))))))
|
||||
(->> (rp/cmd! :update-file-snapshot params)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (update-version-state {:editing id})
|
||||
(fetch-versions)
|
||||
(ptk/event ::ev/event {::ev/name "pin-version"})))))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; PLUGINS SPECIFIC EVENTS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- wait-persisted-status
|
||||
[]
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)))
|
||||
|
||||
(defn create-version-from-plugins
|
||||
[file-id label resolve reject]
|
||||
|
||||
(assert (uuid? file-id) "expected valid uuid for `file-id`")
|
||||
(assert (sm/valid-text? label) "expected not empty string for `label`")
|
||||
|
||||
(ptk/reify ::create-version-from-plugins
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [current-file-id (:current-file-id state)]
|
||||
;; Force persist before creating snapshot, otherwise we could loss changes
|
||||
(->> (rx/concat
|
||||
(rx/of (ptk/event ::ev/event {::ev/origin "plugins"
|
||||
::ev/name "create-version"}))
|
||||
|
||||
(when (= file-id current-file-id)
|
||||
(rx/of ::dwp/force-persist))
|
||||
|
||||
(->> (if (= file-id current-file-id)
|
||||
(wait-persisted-status)
|
||||
(rx/of :nothing))
|
||||
(rx/mapcat
|
||||
(fn [_]
|
||||
(rp/cmd! :create-file-snapshot {:file-id file-id :label label})))
|
||||
(rx/mapcat
|
||||
(fn [{:keys [id]}]
|
||||
(->> (rp/cmd! :get-file-snapshots {:file-id file-id})
|
||||
(rx/take 1)
|
||||
(rx/map (fn [versions] (d/seek #(= id (:id %)) versions))))))
|
||||
(rx/tap resolve)
|
||||
(rx/ignore)))
|
||||
|
||||
;; On error reject the promise and empty the stream
|
||||
(rx/catch (fn [error]
|
||||
(reject error)
|
||||
(rx/empty))))))))
|
||||
|
||||
(defn restore-version-from-plugin
|
||||
[file-id id resolve _reject]
|
||||
(assert (uuid? id) "expected valid uuid for `id`")
|
||||
|
||||
(ptk/reify ::restore-version-from-plugins
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/concat
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"})
|
||||
::dwp/force-persist)
|
||||
|
||||
;; FIXME: we should abstract this
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||
(rx/map #(dw/initialize-workspace file-id)))
|
||||
|
||||
(->> (rx/of 1)
|
||||
(rx/tap resolve)
|
||||
(rx/ignore))))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
[app.main.data.auth :as da]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.workspace :as-alias dw]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.util.globals :as glob]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.timers :as ts]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -141,7 +142,7 @@
|
|||
:timeout 3000})))
|
||||
|
||||
(= code :vern-conflict)
|
||||
(st/emit! (reload-file))
|
||||
(st/emit! (ptk/event ::dw/reload-current-file))
|
||||
|
||||
:else
|
||||
(st/async-emit! (rt/assign-exception error))))
|
||||
|
@ -212,7 +213,6 @@
|
|||
(ts/schedule
|
||||
#(st/emit! (rt/assign-exception error))))
|
||||
|
||||
|
||||
(defn- redirect-to-dashboard
|
||||
[]
|
||||
(let [team-id (:current-team-id @st/state)
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
;; ---- Global refs
|
||||
|
||||
(def route
|
||||
(l/derived :route st/state))
|
||||
(l/derived (l/key :route) st/state))
|
||||
|
||||
(def router
|
||||
(l/derived :router st/state))
|
||||
(l/derived (l/key :router) st/state))
|
||||
|
||||
(def profile
|
||||
(l/derived :profile st/state))
|
||||
(l/derived (l/key :profile) st/state))
|
||||
|
||||
(def team
|
||||
(l/derived (fn [state]
|
||||
|
@ -37,11 +37,18 @@
|
|||
(get teams team-id)))
|
||||
st/state))
|
||||
|
||||
(def project
|
||||
(l/derived (fn [state]
|
||||
(let [project-id (:current-project-id state)
|
||||
projects (:projects state)]
|
||||
(get projects project-id)))
|
||||
st/state))
|
||||
|
||||
(def permissions
|
||||
(l/derived :permissions team))
|
||||
(l/derived (l/key :permissions) team))
|
||||
|
||||
(def teams
|
||||
(l/derived :teams st/state))
|
||||
(l/derived (l/key :teams) st/state))
|
||||
|
||||
(def exception
|
||||
(l/derived :exception st/state))
|
||||
|
@ -65,8 +72,13 @@
|
|||
(l/derived :files st/state))
|
||||
|
||||
(def shared-files
|
||||
"A derived state that points to the current list of shared
|
||||
files (without the content, only summary)"
|
||||
(l/derived :shared-files st/state))
|
||||
|
||||
(def libraries
|
||||
(l/derived :libraries st/state))
|
||||
|
||||
(defn extract-selected-files
|
||||
[files selected]
|
||||
(let [get-file #(get files %)
|
||||
|
@ -86,7 +98,6 @@
|
|||
(def selected-project
|
||||
(l/derived :selected-project st/state))
|
||||
|
||||
|
||||
(def dashboard-local
|
||||
(l/derived :dashboard-local st/state))
|
||||
|
||||
|
@ -243,12 +254,6 @@
|
|||
(def workspace-file-typography
|
||||
(l/derived :typographies workspace-data))
|
||||
|
||||
(def workspace-project
|
||||
(l/derived :workspace-project st/state))
|
||||
|
||||
(def workspace-shared-files
|
||||
(l/derived :workspace-shared-files st/state))
|
||||
|
||||
(def workspace-local-library
|
||||
(l/derived (fn [state]
|
||||
(select-keys (:workspace-data state)
|
||||
|
@ -505,12 +510,16 @@
|
|||
|
||||
;; ---- Viewer refs
|
||||
|
||||
(defn get-viewer-objects
|
||||
[state page-id]
|
||||
(dm/get-in state [:viewer :pages page-id :objects]))
|
||||
|
||||
(defn lookup-viewer-objects-by-id
|
||||
[page-id]
|
||||
(l/derived #(wsh/lookup-viewer-objects % page-id) st/state =))
|
||||
(l/derived #(get-viewer-objects % page-id) st/state =))
|
||||
|
||||
(def viewer-data
|
||||
(l/derived :viewer st/state))
|
||||
(l/derived (l/key :viewer) st/state))
|
||||
|
||||
(def viewer-file
|
||||
(l/derived :file viewer-data))
|
||||
|
@ -536,14 +545,8 @@
|
|||
(def comments-local
|
||||
(l/derived :comments-local st/state))
|
||||
|
||||
(def users
|
||||
(l/derived :users st/state))
|
||||
|
||||
(def current-file-comments-users
|
||||
(l/derived :current-file-comments-users st/state))
|
||||
|
||||
(def current-team-comments-users
|
||||
(l/derived :current-team-comments-users st/state))
|
||||
(def profiles
|
||||
(l/derived :profiles st/state))
|
||||
|
||||
(def viewer-fullscreen?
|
||||
(l/derived (fn [state]
|
||||
|
@ -555,14 +558,11 @@
|
|||
(dm/get-in state [:viewer-local :zoom-type]))
|
||||
st/state))
|
||||
|
||||
(def workspace-thumbnails
|
||||
(l/derived :workspace-thumbnails st/state))
|
||||
|
||||
(defn workspace-thumbnail-by-id
|
||||
[object-id]
|
||||
(l/derived
|
||||
(fn [state]
|
||||
(some-> (dm/get-in state [:workspace-thumbnails object-id])
|
||||
(some-> (dm/get-in state [:thumbnails object-id])
|
||||
(cf/resolve-media)))
|
||||
st/state))
|
||||
|
||||
|
@ -608,35 +608,9 @@
|
|||
(every? (partial ctl/grid-layout-immediate-child? objects))))
|
||||
workspace-page-objects =))
|
||||
|
||||
;; FIXME: move to viewer.inspect.code
|
||||
(defn get-flex-child-viewer
|
||||
[ids page-id]
|
||||
(l/derived
|
||||
(fn [state]
|
||||
(let [objects (wsh/lookup-viewer-objects state page-id)]
|
||||
(into []
|
||||
(comp (map (d/getf objects))
|
||||
(filter (partial ctl/flex-layout-immediate-child? objects)))
|
||||
ids)))
|
||||
st/state =))
|
||||
|
||||
;; FIXME: move to viewer.inspect.code
|
||||
(defn get-viewer-objects
|
||||
([]
|
||||
(let [route (deref route)
|
||||
page-id (:page-id (:query-params route))]
|
||||
(get-viewer-objects page-id)))
|
||||
([page-id]
|
||||
(l/derived
|
||||
(fn [state]
|
||||
(let [objects (wsh/lookup-viewer-objects state page-id)]
|
||||
objects))
|
||||
st/state =)))
|
||||
|
||||
(def colorpicker
|
||||
(l/derived :colorpicker st/state))
|
||||
|
||||
|
||||
(def workspace-grid-edition
|
||||
(l/derived :workspace-grid-edition st/state))
|
||||
|
||||
|
@ -644,6 +618,7 @@
|
|||
[id]
|
||||
(l/derived #(get % id) workspace-grid-edition))
|
||||
|
||||
;; FIXME: remove
|
||||
(def current-file-id
|
||||
(l/derived :current-file-id st/state))
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.util.router
|
||||
(ns app.main.router
|
||||
(:refer-clojure :exclude [resolve])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
|
@ -28,11 +28,10 @@
|
|||
(r/map->Match data))
|
||||
|
||||
(defn resolve
|
||||
([router id] (resolve router id {} {}))
|
||||
([router id path-params] (resolve router id path-params {}))
|
||||
([router id path-params query-params]
|
||||
(when-let [match (r/match-by-name router id path-params)]
|
||||
(r/match->path match query-params))))
|
||||
([router id] (resolve router id {}))
|
||||
([router id params]
|
||||
(when-let [match (r/match-by-name router id)]
|
||||
(r/match->path match params))))
|
||||
|
||||
(defn create
|
||||
[routes]
|
||||
|
@ -63,6 +62,9 @@
|
|||
(defn navigated
|
||||
[match]
|
||||
(ptk/reify ::navigated
|
||||
IDeref
|
||||
(-deref [_] match)
|
||||
|
||||
ev/Event
|
||||
(-data [_]
|
||||
(let [route (dm/get-in match [:data :name])
|
||||
|
@ -77,25 +79,29 @@
|
|||
(assoc :route match)
|
||||
(dissoc :exception)))))
|
||||
|
||||
(defn navigate*
|
||||
[id path-params query-params replace]
|
||||
(defn navigate
|
||||
[id params & {:keys [::replace ::new-window] :as options}]
|
||||
(ptk/reify ::navigate
|
||||
IDeref
|
||||
(-deref [_]
|
||||
{:id id
|
||||
:path-params path-params
|
||||
:query-params query-params
|
||||
:replace replace})
|
||||
:params params
|
||||
:options options})
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [router (:router state)
|
||||
history (:history state)
|
||||
path (resolve router id path-params query-params)]
|
||||
(ts/asap
|
||||
#(if ^boolean replace
|
||||
(bhistory/replace-token! history path)
|
||||
(bhistory/set-token! history path)))))))
|
||||
path (resolve router id params)]
|
||||
|
||||
(if ^boolean new-window
|
||||
(let [name (or (::window-name options) "_blank")
|
||||
uri (assoc cf/public-uri :fragment path)]
|
||||
(dom/open-new-window uri name nil))
|
||||
(ts/asap
|
||||
#(if ^boolean replace
|
||||
(bhistory/replace-token! history path)
|
||||
(bhistory/set-token! history path))))))))
|
||||
|
||||
(defn assign-exception
|
||||
[error]
|
||||
|
@ -107,27 +113,14 @@
|
|||
(assoc state :exception error)))))
|
||||
|
||||
(defn nav
|
||||
([id] (nav id nil nil))
|
||||
([id path-params] (nav id path-params nil))
|
||||
([id path-params query-params] (navigate* id path-params query-params false)))
|
||||
([id] (navigate id nil))
|
||||
([id params] (navigate id params))
|
||||
([id params & {:as options}]
|
||||
(navigate id params options)))
|
||||
|
||||
(defn nav'
|
||||
([id] (nav id nil nil))
|
||||
([id path-params] (nav id path-params nil))
|
||||
([id path-params query-params] (navigate* id path-params query-params true)))
|
||||
|
||||
(def navigate nav)
|
||||
|
||||
(defn nav-new-window*
|
||||
[{:keys [rname path-params query-params name]}]
|
||||
(ptk/reify ::nav-new-window
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [router (:router state)
|
||||
path (resolve router rname path-params query-params)
|
||||
name (or name "_blank")
|
||||
uri (assoc cf/public-uri :fragment path)]
|
||||
(dom/open-new-window uri name nil)))))
|
||||
(defn get-params
|
||||
[state]
|
||||
(dm/get-in state [:route :params :query]))
|
||||
|
||||
(defn nav-back
|
||||
[]
|
|
@ -60,7 +60,7 @@
|
|||
:app.main.data.workspace.persistence/update-persistence-status
|
||||
:app.main.data.websocket/send-message
|
||||
:app.main.data.workspace.notifications/handle-pointer-send
|
||||
:app.util.router/assign-exception}]
|
||||
:app.main.router/assign-exception}]
|
||||
(->> (rx/merge
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? :app.main.data.changes/commit))
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
(mf/lazy-component app.main.ui.auth.verify-token/verify-token))
|
||||
|
||||
(def viewer-page
|
||||
(mf/lazy-component app.main.ui.viewer/viewer))
|
||||
(mf/lazy-component app.main.ui.viewer/viewer*))
|
||||
|
||||
(def dashboard-page
|
||||
(mf/lazy-component app.main.ui.dashboard/dashboard*))
|
||||
|
@ -42,7 +42,7 @@
|
|||
(mf/lazy-component app.main.ui.settings/settings))
|
||||
|
||||
(def workspace-page
|
||||
(mf/lazy-component app.main.ui.workspace/workspace))
|
||||
(mf/lazy-component app.main.ui.workspace/workspace*))
|
||||
|
||||
(mf/defc team-container*
|
||||
{::mf/props :obj
|
||||
|
@ -62,13 +62,13 @@
|
|||
;; all dom tree instead of simple rerender.
|
||||
[:* {:key (str team-id)} children]]])))
|
||||
|
||||
(mf/defc page-container*
|
||||
(mf/defc page*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [route profile]}]
|
||||
(let [{:keys [data params]} route
|
||||
props (get profile :props)
|
||||
route-name (get data :name)
|
||||
props (get profile :props)
|
||||
section (get data :name)
|
||||
|
||||
|
||||
show-question-modal?
|
||||
|
@ -95,7 +95,7 @@
|
|||
(not= "0.0" (:main cf/version)))]
|
||||
|
||||
[:& (mf/provider ctx/current-route) {:value route}
|
||||
(case route-name
|
||||
(case section
|
||||
(:auth-login
|
||||
:auth-register
|
||||
:auth-register-validate
|
||||
|
@ -119,20 +119,20 @@
|
|||
[:& icons-preview])
|
||||
|
||||
(:dashboard-search
|
||||
:dashboard-projects
|
||||
:dashboard-recent
|
||||
:dashboard-files
|
||||
:dashboard-libraries
|
||||
:dashboard-fonts
|
||||
:dashboard-font-providers
|
||||
:dashboard-team-members
|
||||
:dashboard-team-invitations
|
||||
:dashboard-team-webhooks
|
||||
:dashboard-team-settings)
|
||||
(let [team-id (some-> params :path :team-id uuid)
|
||||
project-id (some-> params :path :project-id uuid)
|
||||
search-term (some-> params :query :search-term)
|
||||
plugin-url (some-> params :query :plugin)]
|
||||
|
||||
:dashboard-members
|
||||
:dashboard-invitations
|
||||
:dashboard-webhooks
|
||||
:dashboard-settings)
|
||||
(let [params (get params :query)
|
||||
team-id (some-> params :team-id uuid)
|
||||
project-id (some-> params :project-id uuid)
|
||||
search-term (some-> params :search-term)
|
||||
plugin-url (some-> params :plugin)]
|
||||
[:?
|
||||
#_[:& app.main.ui.releases/release-notes-modal {:version "2.3"}]
|
||||
#_[:& app.main.ui.onboarding/onboarding-templates-modal]
|
||||
|
@ -154,13 +154,105 @@
|
|||
|
||||
[:> team-container* {:team-id team-id}
|
||||
[:> dashboard-page {:profile profile
|
||||
:route-name route-name
|
||||
:section section
|
||||
:team-id team-id
|
||||
:search-term search-term
|
||||
:plugin-url plugin-url
|
||||
:project-id project-id}]]])
|
||||
|
||||
(:dashboard-legacy-search
|
||||
:dashboard-legacy-projects
|
||||
:dashboard-legacy-files
|
||||
:dashboard-legacy-libraries
|
||||
:dashboard-legacy-fonts
|
||||
:dashboard-legacy-font-providers
|
||||
:dashboard-legacy-team-members
|
||||
:dashboard-legacy-team-invitations
|
||||
:dashboard-legacy-team-webhooks
|
||||
:dashboard-legacy-team-settings)
|
||||
(let [team-id (some-> params :path :team-id uuid)
|
||||
project-id (some-> params :path :project-id uuid)
|
||||
search-term (some-> params :query :search-term)
|
||||
plugin-url (some-> params :query :plugin)
|
||||
section (case section
|
||||
:dashboard-legacy-search
|
||||
:dashboard-search
|
||||
:dashboard-legacy-projects
|
||||
:dashboard-recent
|
||||
:dashboard-legacy-files
|
||||
:dashboard-files
|
||||
:dashboard-legacy-libraries
|
||||
:dashboard-libraries
|
||||
:dashboard-legacy-fonts
|
||||
:dashboard-fonts
|
||||
:dashboard-legacy-font-providers
|
||||
:dashboard-font-providers
|
||||
:dashboard-legacy-team-members
|
||||
:dashboard-members
|
||||
:dashboard-legacy-team-invitations
|
||||
:dashboard-invitations
|
||||
:dashboard-legacy-team-webhooks
|
||||
:dashboard-webhooks
|
||||
:dashboard-legacy-team-settings
|
||||
:dashboard-settings)]
|
||||
[:?
|
||||
#_[:& app.main.ui.releases/release-notes-modal {:version "2.3"}]
|
||||
#_[:& app.main.ui.onboarding/onboarding-templates-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-modal]
|
||||
#_[:& app.main.ui.onboarding.team-choice/onboarding-team-modal]
|
||||
|
||||
(cond
|
||||
show-question-modal?
|
||||
[:& questions-modal]
|
||||
|
||||
show-newsletter-modal?
|
||||
[:& onboarding-newsletter]
|
||||
|
||||
show-team-modal?
|
||||
[:& onboarding-team-modal {:go-to-team? true}]
|
||||
|
||||
show-release-modal?
|
||||
[:& release-notes-modal {:version (:main cf/version)}])
|
||||
|
||||
[:> team-container* {:team-id team-id}
|
||||
[:> dashboard-page {:profile profile
|
||||
:section section
|
||||
:team-id team-id
|
||||
:search-term search-term
|
||||
:plugin-url plugin-url
|
||||
:project-id project-id}]]])
|
||||
|
||||
:workspace
|
||||
(let [params (get params :query)
|
||||
team-id (some-> params :team-id uuid)
|
||||
project-id (some-> params :project-id uuid)
|
||||
file-id (some-> params :file-id uuid)
|
||||
page-id (some-> params :page-id uuid)
|
||||
layout (some-> params :layout keyword)]
|
||||
[:? {}
|
||||
(when (cf/external-feature-flag "onboarding-03" "test")
|
||||
(cond
|
||||
show-question-modal?
|
||||
[:& questions-modal]
|
||||
|
||||
show-newsletter-modal?
|
||||
[:& onboarding-newsletter]
|
||||
|
||||
show-team-modal?
|
||||
[:& onboarding-team-modal {:go-to-team? false}]
|
||||
|
||||
show-release-modal?
|
||||
[:& release-notes-modal {:version (:main cf/version)}]))
|
||||
|
||||
[:> team-container* {:team-id team-id}
|
||||
[:> workspace-page {:project-id project-id
|
||||
:team-id team-id
|
||||
:file-id file-id
|
||||
:page-id page-id
|
||||
:layout-name layout
|
||||
:key file-id}]]])
|
||||
|
||||
:workspace-legacy
|
||||
(let [project-id (some-> params :path :project-id uuid)
|
||||
file-id (some-> params :path :file-id uuid)
|
||||
page-id (some-> params :query :page-id uuid)
|
||||
|
@ -181,14 +273,38 @@
|
|||
[:& release-notes-modal {:version (:main cf/version)}]))
|
||||
|
||||
[:*
|
||||
[:& workspace-page {:project-id project-id
|
||||
[:> workspace-page {:project-id project-id
|
||||
:file-id file-id
|
||||
:page-id page-id
|
||||
:layout-name layout
|
||||
:key file-id}]]])
|
||||
|
||||
|
||||
:viewer
|
||||
(let [params (get params :query)
|
||||
index (some-> (:index params) parse-long)
|
||||
share-id (some-> (:share-id params) parse-uuid)
|
||||
section (or (some-> (:section params) keyword)
|
||||
:interactions)
|
||||
|
||||
file-id (some-> (:file-id params) parse-uuid)
|
||||
page-id (some-> (:page-id params) parse-uuid)
|
||||
imode (or (some-> (:interactions-mode params) keyword)
|
||||
:show-on-click)
|
||||
frame-id (some-> (:frame-id params) parse-uuid)
|
||||
share (:share params)]
|
||||
|
||||
[:? {}
|
||||
[:> viewer-page
|
||||
{:page-id page-id
|
||||
:file-id file-id
|
||||
:frame-id frame-id
|
||||
:section section
|
||||
:index index
|
||||
:share-id share-id
|
||||
:interactions-mode imode
|
||||
:share share}]])
|
||||
|
||||
:viewer-legacy
|
||||
(let [{:keys [query-params path-params]} route
|
||||
{:keys [index share-id section page-id interactions-mode frame-id share]
|
||||
:or {section :interactions interactions-mode :show-on-click}} query-params
|
||||
|
@ -200,17 +316,17 @@
|
|||
[:div.main-message (tr "viewer.breaking-change.message")]
|
||||
[:div.desc-message (tr "viewer.breaking-change.description")]]
|
||||
|
||||
[:& viewer-page
|
||||
[:> viewer-page
|
||||
{:page-id page-id
|
||||
:file-id file-id
|
||||
:section section
|
||||
:index index
|
||||
:share-id share-id
|
||||
:interactions-mode (keyword interactions-mode)
|
||||
:interactions-show? (case (keyword interactions-mode)
|
||||
:hide false
|
||||
:show true
|
||||
:show-on-click false)
|
||||
:show-interactions (case (keyword interactions-mode)
|
||||
:hide false
|
||||
:show true
|
||||
:show-on-click false)
|
||||
:frame-id frame-id
|
||||
:share share}])])
|
||||
|
||||
|
@ -237,4 +353,4 @@
|
|||
[:> error-boundary* {:fallback static/internal-error*}
|
||||
[:& notifications/current-notification]
|
||||
(when route
|
||||
[:> page-container* {:route route :profile profile}])])]]))
|
||||
[:> page* {:route route :profile profile}])])]]))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.main.data.auth :as da]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.button-link :as bl]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
|
@ -22,7 +23,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.keyboard :as k]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as s]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -124,7 +124,7 @@
|
|||
(mf/use-fn
|
||||
(fn [data]
|
||||
(when-let [token (:invitation-token data)]
|
||||
(st/emit! (rt/nav :auth-verify-token {} {:token token})))))
|
||||
(st/emit! (rt/nav :auth-verify-token {:token token})))))
|
||||
|
||||
on-success
|
||||
(fn [data]
|
||||
|
@ -283,7 +283,7 @@
|
|||
[{:keys [params] :as props}]
|
||||
(let [go-register
|
||||
(mf/use-fn
|
||||
#(st/emit! (rt/nav :auth-register {} params)))]
|
||||
#(st/emit! (rt/nav :auth-register params)))]
|
||||
|
||||
[:div {:class (stl/css :auth-form-wrapper)}
|
||||
[:h1 {:class (stl/css :auth-title)
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
[app.common.schema :as sm]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private schema:recovery-form
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
[app.common.schema :as sm]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.components.link :as lk]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
[app.main.data.auth :as da]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.auth.login :as login]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.components.link :as lk]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -74,7 +74,7 @@
|
|||
on-success (fn [data]
|
||||
(if (fn? on-success-callback)
|
||||
(on-success-callback data)
|
||||
(st/emit! (rt/nav :auth-register-validate {} data))))]
|
||||
(st/emit! (rt/nav :auth-register-validate data))))]
|
||||
|
||||
(->> (rp/cmd! :prepare-register-profile cdata)
|
||||
(rx/map #(merge % params))
|
||||
|
@ -131,7 +131,7 @@
|
|||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :account)}
|
||||
[:span {:class (stl/css :account-text)} (tr "auth.already-have-account") " "]
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params))
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-login params))
|
||||
:class (stl/css :account-link)
|
||||
:data-testid "login-here-link"}
|
||||
(tr "auth.login-here")]]
|
||||
|
@ -191,7 +191,7 @@
|
|||
(cond
|
||||
(some? (:invitation-token params))
|
||||
(let [token (:invitation-token params)]
|
||||
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
|
||||
(st/emit! (rt/nav :auth-verify-token {:token token})))
|
||||
|
||||
(:is-active params)
|
||||
(st/emit! (da/login-from-register))
|
||||
|
@ -257,7 +257,7 @@
|
|||
|
||||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :go-back)}
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {}))
|
||||
:class (stl/css :go-back-link)}
|
||||
(tr "labels.go-back")]]]])
|
||||
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
(ns app.main.ui.auth.verify-token
|
||||
(:require
|
||||
[app.main.data.auth :as da]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||
[app.main.ui.static :as static]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.timers :as ts]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -43,15 +44,16 @@
|
|||
[tdata]
|
||||
(case (:state tdata)
|
||||
:created
|
||||
(st/emit!
|
||||
(ntf/success (tr "auth.notifications.team-invitation-accepted"))
|
||||
(du/fetch-profile)
|
||||
(rt/nav :dashboard-projects {:team-id (:team-id tdata)}))
|
||||
(let [team-id (:team-id tdata)]
|
||||
(st/emit!
|
||||
(ntf/success (tr "auth.notifications.team-invitation-accepted"))
|
||||
(du/fetch-profile)
|
||||
(dcm/go-to-dashboard-recent :team-id team-id)))
|
||||
|
||||
:pending
|
||||
(let [token (:invitation-token tdata)
|
||||
route-id (:redirect-to tdata :auth-register)]
|
||||
(st/emit! (rt/nav route-id {} {:invitation-token token})))))
|
||||
(st/emit! (rt/nav route-id {:invitation-token token})))))
|
||||
|
||||
(defmethod handle-token :default
|
||||
[_tdata]
|
||||
|
|
|
@ -253,8 +253,8 @@
|
|||
:disabled disabled?}]]]))
|
||||
|
||||
(mf/defc comment-item
|
||||
[{:keys [comment thread users origin] :as props}]
|
||||
(let [owner (get users (:owner-id comment))
|
||||
[{:keys [comment thread profiles origin] :as props}]
|
||||
(let [owner (get profiles (:owner-id comment))
|
||||
profile (mf/deref refs/profile)
|
||||
options (mf/deref comments-local-options)
|
||||
edition? (mf/use-state false)
|
||||
|
@ -384,7 +384,7 @@
|
|||
|
||||
(mf/defc thread-comments
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [thread zoom users origin position-modifier viewport]}]
|
||||
[{:keys [thread zoom profiles origin position-modifier viewport]}]
|
||||
(let [ref (mf/use-ref)
|
||||
thread-id (:id thread)
|
||||
thread-pos (:position thread)
|
||||
|
@ -435,13 +435,13 @@
|
|||
|
||||
[:div {:class (stl/css :comments)}
|
||||
[:& comment-item {:comment comment
|
||||
:users users
|
||||
:profiles profiles
|
||||
:thread thread
|
||||
:origin origin}]
|
||||
(for [item (rest comments)]
|
||||
[:* {:key (dm/str (:id item))}
|
||||
[:& comment-item {:comment item
|
||||
:users users
|
||||
:profiles profiles
|
||||
:origin origin}]])]
|
||||
[:& reply-form {:thread thread}]
|
||||
[:div {:ref ref}]])))
|
||||
|
@ -573,8 +573,8 @@
|
|||
[:span (:seqn thread)]]))
|
||||
|
||||
(mf/defc comment-thread
|
||||
[{:keys [item users on-click]}]
|
||||
(let [owner (get users (:owner-id item))
|
||||
[{:keys [item profiles on-click]}]
|
||||
(let [owner (get profiles (:owner-id item))
|
||||
on-click*
|
||||
(mf/use-fn
|
||||
(mf/deps item)
|
||||
|
@ -613,7 +613,7 @@
|
|||
[:span {:class (stl/css :new-replies)} (str unread " new replies")]))])]]))
|
||||
|
||||
(mf/defc comment-thread-group
|
||||
[{:keys [group users on-thread-click]}]
|
||||
[{:keys [group profiles on-thread-click]}]
|
||||
[:div {:class (stl/css :thread-group)}
|
||||
(if (:file-name group)
|
||||
[:div {:class (stl/css :section-title)
|
||||
|
@ -631,5 +631,5 @@
|
|||
[:& comment-thread
|
||||
{:item item
|
||||
:on-click on-thread-click
|
||||
:users users
|
||||
:profiles profiles
|
||||
:key (:id item)}])]])
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.main.data.notifications :as notif]
|
||||
[app.main.data.plugins :as dp]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.dashboard.files :refer [files-section*]]
|
||||
|
@ -33,7 +34,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[goog.events :as events]
|
||||
[okulary.core :as l]
|
||||
|
@ -84,7 +84,7 @@
|
|||
:on-click clear-selected-fn
|
||||
:ref container}
|
||||
(case section
|
||||
:dashboard-projects
|
||||
:dashboard-recent
|
||||
[:*
|
||||
[:> projects-section*
|
||||
{:team team
|
||||
|
@ -126,16 +126,16 @@
|
|||
[:> libraries-page* {:team team
|
||||
:default-project default-project}]
|
||||
|
||||
:dashboard-team-members
|
||||
:dashboard-members
|
||||
[:> team-members-page* {:team team :profile profile}]
|
||||
|
||||
:dashboard-team-invitations
|
||||
:dashboard-invitations
|
||||
[:> team-invitations-page* {:team team}]
|
||||
|
||||
:dashboard-team-webhooks
|
||||
:dashboard-webhooks
|
||||
[:> webhooks-page* {:team team}]
|
||||
|
||||
:dashboard-team-settings
|
||||
:dashboard-settings
|
||||
[:> team-settings-page* {:team team :profile profile}]
|
||||
|
||||
nil)]))
|
||||
|
@ -151,8 +151,9 @@
|
|||
(st/emit!
|
||||
(dp/delay-open-plugin plugin)
|
||||
(rt/nav :workspace
|
||||
{:project-id project-id :file-id id}
|
||||
{:page-id (dm/get-in data [:pages 0])})))
|
||||
{:page-id (dm/get-in data [:pages 0])
|
||||
:project-id project-id
|
||||
:file-id id})))
|
||||
|
||||
create-file!
|
||||
(fn [plugin]
|
||||
|
@ -182,11 +183,11 @@
|
|||
:on-accept
|
||||
#(do (preg/install-plugin! plugin)
|
||||
(st/emit! (modal/hide)
|
||||
(rt/nav :dashboard-projects {:team-id team-id})
|
||||
(rt/nav :dashboard-recent {:team-id team-id})
|
||||
(open-try-out-dialog plugin)))
|
||||
:on-close
|
||||
#(st/emit! (modal/hide)
|
||||
(rt/nav :dashboard-projects {:team-id team-id}))}))]
|
||||
(rt/nav :dashboard-recent {:team-id team-id}))}))]
|
||||
|
||||
(mf/with-layout-effect
|
||||
[plugin-url team-id project-id]
|
||||
|
@ -204,7 +205,7 @@
|
|||
|
||||
(mf/defc dashboard*
|
||||
{::mf/props :obj}
|
||||
[{:keys [profile project-id team-id search-term plugin-url route-name]}]
|
||||
[{:keys [profile project-id team-id search-term plugin-url section]}]
|
||||
(let [team (mf/deref refs/team)
|
||||
projects (mf/deref refs/projects)
|
||||
|
||||
|
@ -253,7 +254,7 @@
|
|||
:project project
|
||||
:default-project default-project
|
||||
:profile profile
|
||||
:section route-name
|
||||
:section section
|
||||
:search-term search-term}]
|
||||
(when (seq projects)
|
||||
[:> dashboard-content*
|
||||
|
@ -261,6 +262,6 @@
|
|||
:profile profile
|
||||
:project project
|
||||
:default-project default-project
|
||||
:section route-name
|
||||
:section section
|
||||
:search-term search-term
|
||||
:team team}])]]))
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
(mf/defc comments-section
|
||||
[{:keys [profile team show? on-hide-comments]}]
|
||||
(let [threads-map (mf/deref refs/comment-threads)
|
||||
users (mf/deref refs/current-team-comments-users)
|
||||
profiles (mf/deref refs/profiles)
|
||||
team-id (:id team)
|
||||
|
||||
tgroups (->> (vals threads-map)
|
||||
|
@ -114,13 +114,13 @@
|
|||
{:group (first tgroups)
|
||||
:on-thread-click on-navigate
|
||||
:show-file-name true
|
||||
:users users}]
|
||||
:profiles profiles}]
|
||||
(for [tgroup (rest tgroups)]
|
||||
[:& cmt/comment-thread-group
|
||||
{:group tgroup
|
||||
:on-thread-click on-navigate
|
||||
:show-file-name true
|
||||
:users users
|
||||
:profiles profiles
|
||||
:key (:page-id tgroup)}])]
|
||||
|
||||
[:div {:class (stl/css :thread-groups-placeholder)}
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
[app.main.data.notifications :as ntf]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.context-menu-a11y :refer [context-menu*]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -85,10 +85,9 @@
|
|||
|
||||
on-new-tab
|
||||
(fn [_]
|
||||
(let [path-params {:project-id (:project-id file)
|
||||
:file-id (:id file)}]
|
||||
(st/emit! (rt/nav-new-window* {:rname :workspace
|
||||
:path-params path-params}))))
|
||||
(st/emit! (dcm/go-to-workspace
|
||||
{:file-id (:id file)
|
||||
::rt/new-window true})))
|
||||
|
||||
on-duplicate
|
||||
(fn [_]
|
||||
|
@ -134,7 +133,9 @@
|
|||
(st/emit! (ntf/success (tr "dashboard.success-move-files")))
|
||||
(st/emit! (ntf/success (tr "dashboard.success-move-file"))))
|
||||
(if (or navigate (not= team-id current-team-id))
|
||||
(st/emit! (dd/go-to-files project-id team-id))
|
||||
(st/emit! (dcm/go-to-dashboard-files
|
||||
{:project-id project-id
|
||||
:team-id team-id}))
|
||||
(st/emit! (dd/fetch-recent-files)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
(ns app.main.ui.dashboard.files
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.project :as dpj]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.grid :refer [grid]]
|
||||
|
@ -21,7 +23,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -32,9 +33,12 @@
|
|||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [project create-fn can-edit]}]
|
||||
(let [local (mf/use-state
|
||||
{:menu-open false
|
||||
:edition false})
|
||||
(let [project-id (:id project)
|
||||
|
||||
local
|
||||
(mf/use-state
|
||||
{:menu-open false
|
||||
:edition false})
|
||||
|
||||
on-create-click
|
||||
(mf/use-fn
|
||||
|
@ -63,9 +67,9 @@
|
|||
|
||||
on-import
|
||||
(mf/use-fn
|
||||
(mf/deps (:id project))
|
||||
(mf/deps project-id)
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-files {:project-id (:id project)})
|
||||
(st/emit! (dpj/fetch-files project-id)
|
||||
(dd/clear-selected-files))))]
|
||||
|
||||
|
||||
|
@ -153,11 +157,10 @@
|
|||
|
||||
on-file-created
|
||||
(mf/use-fn
|
||||
(fn [data]
|
||||
(let [pparams {:project-id (:project-id data)
|
||||
:file-id (:id data)}
|
||||
qparams {:page-id (get-in data [:data :pages 0])}]
|
||||
(st/emit! (rt/nav :workspace pparams qparams)))))
|
||||
(fn [file-data]
|
||||
(let [file-id (:id file-data)
|
||||
page-id (get-in file-data [:pages 0])]
|
||||
(st/emit! (dcm/go-to-workspace :file-id file-id :page-id page-id)))))
|
||||
|
||||
create-file
|
||||
(mf/use-fn
|
||||
|
@ -176,7 +179,7 @@
|
|||
(dom/set-html-title (tr "title.dashboard.files" pname)))))
|
||||
|
||||
(mf/with-effect [project-id]
|
||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||
(st/emit! (dpj/fetch-files project-id)
|
||||
(dd/clear-selected-files)))
|
||||
|
||||
[:*
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.logging :as log]
|
||||
[app.config :as cf]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.project :as dpj]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.features :as features]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.rasterizer :as thr]
|
||||
|
@ -79,8 +82,7 @@
|
|||
revn (get file :revn)
|
||||
thumbnail-id (get file :thumbnail-id)
|
||||
|
||||
;; FIXME: revisit maybe bug
|
||||
bg-color (dm/get-in file [:data :options :background])
|
||||
bg-color (dm/get-in file [:data :background])
|
||||
|
||||
container (mf/use-ref)
|
||||
visible? (h/use-visible container :once? true)]
|
||||
|
@ -270,12 +272,12 @@
|
|||
|
||||
on-navigate
|
||||
(mf/use-fn
|
||||
(mf/deps file)
|
||||
(mf/deps file-id)
|
||||
(fn [event]
|
||||
(let [menu-icon (mf/ref-val menu-ref)
|
||||
target (dom/get-target event)]
|
||||
(when-not (dom/child? target menu-icon)
|
||||
(st/emit! (dd/go-to-workspace file))))))
|
||||
(st/emit! (dcm/go-to-workspace :file-id file-id))))))
|
||||
|
||||
on-drag-start
|
||||
(mf/use-fn
|
||||
|
@ -427,10 +429,12 @@
|
|||
on-finish-import
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||
(dd/fetch-shared-files)
|
||||
(st/emit! (dpj/fetch-files project-id)
|
||||
(dtm/fetch-shared-files)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
|
||||
|
||||
import-files (use-import-file project-id on-finish-import)
|
||||
|
||||
on-drag-enter
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.grid :refer [grid]]
|
||||
|
@ -41,7 +42,7 @@
|
|||
(dom/set-html-title (tr "title.dashboard.shared-libraries" tname))))
|
||||
|
||||
(mf/with-effect [team]
|
||||
(st/emit! (dd/fetch-shared-files)
|
||||
(st/emit! (dtm/fetch-shared-files)
|
||||
(dd/clear-selected-files)))
|
||||
|
||||
[:*
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.ui.dashboard.project-menu
|
||||
(:require
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
|
@ -16,7 +17,6 @@
|
|||
[app.main.ui.dashboard.import :as udi]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc project-menu*
|
||||
|
@ -32,9 +32,9 @@
|
|||
on-duplicate-success
|
||||
(fn [new-project]
|
||||
(st/emit! (ntf/success (tr "dashboard.success-duplicate-project"))
|
||||
(rt/nav :dashboard-files
|
||||
{:team-id (:team-id new-project)
|
||||
:project-id (:id new-project)})))
|
||||
(dcm/go-to-dashboard-files
|
||||
:team-id (:team-id new-project)
|
||||
:project-id (:id new-project))))
|
||||
|
||||
on-duplicate
|
||||
(fn []
|
||||
|
@ -46,7 +46,7 @@
|
|||
|
||||
on-move-success
|
||||
(fn [team-id]
|
||||
(st/emit! (dd/go-to-projects team-id)))
|
||||
(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)))
|
||||
|
||||
on-move
|
||||
(fn [team-id]
|
||||
|
@ -57,9 +57,10 @@
|
|||
|
||||
delete-fn
|
||||
(fn [_]
|
||||
(st/emit! (ntf/success (tr "dashboard.success-delete-project"))
|
||||
(dd/delete-project project)
|
||||
(dd/go-to-projects (:team-id project))))
|
||||
(let [team-id (:team-id project)]
|
||||
(st/emit! (ntf/success (tr "dashboard.success-delete-project"))
|
||||
(dd/delete-project project)
|
||||
(dcm/go-to-dashboard-recent :team-id team-id))))
|
||||
|
||||
on-delete
|
||||
#(st/emit!
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.project :as dpj]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.grid :refer [line-grid]]
|
||||
|
@ -23,7 +25,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.time :as dt]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -62,7 +63,7 @@
|
|||
{::mf/wrap [mf/memo]
|
||||
::mf/props :obj}
|
||||
[{:keys [team on-close]}]
|
||||
(let [on-nav-members-click (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
||||
(let [on-nav-members-click (mf/use-fn #(st/emit! (dcm/go-to-dashboard-members)))
|
||||
|
||||
on-invite
|
||||
(mf/use-fn
|
||||
|
@ -105,7 +106,6 @@
|
|||
(let [locale (mf/deref i18n/locale)
|
||||
|
||||
project-id (:id project)
|
||||
team-id (:id team)
|
||||
|
||||
file-count (or (:count project) 0)
|
||||
is-draft? (:is-default project)
|
||||
|
@ -124,11 +124,10 @@
|
|||
|
||||
on-nav
|
||||
(mf/use-fn
|
||||
(mf/deps project-id team-id)
|
||||
(mf/deps project-id)
|
||||
(fn []
|
||||
(st/emit! (rt/nav :dashboard-files
|
||||
{:team-id team-id
|
||||
:project-id project-id}))))
|
||||
(st/emit! (dcm/go-to-dashboard-files :project-id project-id))))
|
||||
|
||||
toggle-pin
|
||||
(mf/use-fn
|
||||
(mf/deps project)
|
||||
|
@ -171,11 +170,9 @@
|
|||
|
||||
on-file-created
|
||||
(mf/use-fn
|
||||
(fn [data]
|
||||
(let [pparams {:project-id (:project-id data)
|
||||
:file-id (:id data)}
|
||||
qparams {:page-id (get-in data [:data :pages 0])}]
|
||||
(st/emit! (rt/nav :workspace pparams qparams)))))
|
||||
(fn [{:keys [id data]}]
|
||||
(let [page-id (get-in data [:pages 0])]
|
||||
(st/emit! (dcm/go-to-workspace :file-id id :page-id page-id)))))
|
||||
|
||||
create-file
|
||||
(mf/use-fn
|
||||
|
@ -194,9 +191,9 @@
|
|||
|
||||
on-import
|
||||
(mf/use-fn
|
||||
(mf/deps project-id (:id team))
|
||||
(mf/deps project-id)
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||
(st/emit! (dpj/fetch-files project-id)
|
||||
(dd/fetch-recent-files)
|
||||
(dd/fetch-projects)
|
||||
(dd/clear-selected-files))))
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[app.main.data.auth :as da]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
|
||||
[app.main.ui.components.link :refer [link]]
|
||||
|
@ -29,7 +31,6 @@
|
|||
[app.util.dom.dnd :as dnd]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[app.util.timers :as ts]
|
||||
[beicon.v2.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
|
@ -73,32 +74,34 @@
|
|||
edit-id (:project-for-edit dstate)
|
||||
|
||||
local* (mf/use-state
|
||||
{:menu-open false
|
||||
:menu-pos nil
|
||||
:edition? (= (:id item) edit-id)
|
||||
:dragging? false})
|
||||
#(do {:menu-open false
|
||||
:menu-pos nil
|
||||
:edition? (= (:id item) edit-id)
|
||||
:dragging? false}))
|
||||
|
||||
local @local*
|
||||
local (deref local*)
|
||||
|
||||
project-id (get item :id)
|
||||
|
||||
on-click
|
||||
(mf/use-fn
|
||||
(mf/deps item)
|
||||
(mf/deps project-id)
|
||||
(fn []
|
||||
(st/emit! (dd/go-to-files (:id item)))))
|
||||
(st/emit! (dcm/go-to-dashboard-files :project-id project-id))))
|
||||
|
||||
on-key-down
|
||||
(mf/use-fn
|
||||
(mf/deps item)
|
||||
(mf/deps project-id)
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(st/emit! (dd/go-to-files (:id item))
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(let [project-title (dom/get-element (str (:id item)))]
|
||||
(when project-title
|
||||
(dom/set-attribute! project-title "tabindex" "0")
|
||||
(dom/focus! project-title)
|
||||
(dom/set-attribute! project-title "tabindex" "-1")))))))))
|
||||
(st/emit!
|
||||
(dcm/go-to-dashboard-files :project-id project-id)
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(when-let [title (dom/get-element (str project-id))]
|
||||
(dom/set-attribute! title "tabindex" "0")
|
||||
(dom/focus! title)
|
||||
(dom/set-attribute! title "tabindex" "-1"))))))))
|
||||
|
||||
on-menu-click
|
||||
(mf/use-fn
|
||||
|
@ -148,9 +151,10 @@
|
|||
|
||||
on-drop-success
|
||||
(mf/use-fn
|
||||
(mf/deps (:id item))
|
||||
#(st/emit! (ntf/success (tr "dashboard.success-move-file"))
|
||||
(dd/go-to-files (:id item))))
|
||||
(mf/deps project-id)
|
||||
(fn [_]
|
||||
(st/emit! (dcm/go-to-dashboard-files :project-id project-id)
|
||||
(ntf/success (tr "dashboard.success-move-file")))))
|
||||
|
||||
on-drop
|
||||
(mf/use-fn
|
||||
|
@ -201,19 +205,18 @@
|
|||
|
||||
on-search-change
|
||||
(mf/use-fn
|
||||
(mf/deps team-id)
|
||||
(fn [event]
|
||||
(let [value (dom/get-target-val event)]
|
||||
(emit! (dd/go-to-search value)))))
|
||||
(emit! (dcm/go-to-dashboard-search :term value)))))
|
||||
|
||||
on-clear-click
|
||||
(mf/use-fn
|
||||
(mf/deps team-id)
|
||||
(fn [e]
|
||||
(emit! (dcm/go-to-dashboard-search))
|
||||
(let [search-input (dom/get-element "search-input")]
|
||||
(dom/clean-value! search-input)
|
||||
(dom/focus! search-input)
|
||||
(emit! (dd/go-to-search))
|
||||
(dom/prevent-default e)
|
||||
(dom/stop-propagation e))))
|
||||
|
||||
|
@ -278,7 +281,8 @@
|
|||
(fn [event]
|
||||
(let [team-id (-> (dom/get-current-target event)
|
||||
(dom/get-data "value"))]
|
||||
(st/emit! (dd/go-to-projects team-id)))))
|
||||
|
||||
(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)))))
|
||||
|
||||
handle-select-default
|
||||
(mf/use-fn
|
||||
|
@ -343,10 +347,10 @@
|
|||
|
||||
(mf/defc team-options-dropdown
|
||||
[{:keys [team profile] :as props}]
|
||||
(let [go-members #(st/emit! (dd/go-to-team-members))
|
||||
go-invitations #(st/emit! (dd/go-to-team-invitations))
|
||||
go-webhooks #(st/emit! (dd/go-to-team-webhooks))
|
||||
go-settings #(st/emit! (dd/go-to-team-settings))
|
||||
(let [go-members #(st/emit! (dcm/go-to-dashboard-members))
|
||||
go-invitations #(st/emit! (dcm/go-to-dashboard-invitations))
|
||||
go-webhooks #(st/emit! (dcm/go-to-dashboard-webhooks))
|
||||
go-settings #(st/emit! (dcm/go-to-dashboard-settings))
|
||||
|
||||
members (get team :members)
|
||||
permissions (get team :permissions)
|
||||
|
@ -356,9 +360,9 @@
|
|||
on-success
|
||||
(fn []
|
||||
;; FIXME: this should be handled in the event, not here
|
||||
(st/emit! (dd/go-to-projects (:default-team-id profile))
|
||||
(modal/hide)
|
||||
(dtm/fetch-teams)))
|
||||
(let [team-id (:default-team-id profile)]
|
||||
(rx/of (dcm/go-to-dashboard-recent :team-id team-id)
|
||||
(modal/hide))))
|
||||
|
||||
on-error
|
||||
(fn [{:keys [code] :as error}]
|
||||
|
@ -692,38 +696,38 @@
|
|||
(let [default-project-id
|
||||
(get default-project :id)
|
||||
|
||||
projects? (= section :dashboard-projects)
|
||||
team-id (get team :id)
|
||||
|
||||
projects? (= section :dashboard-recent)
|
||||
fonts? (= section :dashboard-fonts)
|
||||
libs? (= section :dashboard-libraries)
|
||||
drafts? (and (= section :dashboard-files)
|
||||
(= (:id project) default-project-id))
|
||||
|
||||
go-projects
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-projects {:team-id (:id team)})))
|
||||
(mf/use-fn #(st/emit! (dcm/go-to-dashboard-recent)))
|
||||
|
||||
go-projects-with-key
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-projects {:team-id (:id team)})
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(let [projects-title (dom/get-element "dashboard-projects-title")]
|
||||
(when projects-title
|
||||
(dom/set-attribute! projects-title "tabindex" "0")
|
||||
(dom/focus! projects-title)
|
||||
(dom/set-attribute! projects-title "tabindex" "-1")))))))
|
||||
(mf/deps team-id)
|
||||
(fn []
|
||||
(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(when-let [projects-title (dom/get-element "dashboard-projects-title")]
|
||||
(dom/set-attribute! projects-title "tabindex" "0")
|
||||
(dom/focus! projects-title)
|
||||
(dom/set-attribute! projects-title "tabindex" "-1")))))))
|
||||
|
||||
go-fonts
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-fonts {:team-id (:id team)})))
|
||||
(mf/deps team-id)
|
||||
#(st/emit! (dcm/go-to-dashboard-fonts :team-id team-id)))
|
||||
|
||||
go-fonts-with-key
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-fonts {:team-id (:id team)})
|
||||
#(st/emit! (dcm/go-to-dashboard-fonts :team-id team-id)
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(let [font-title (dom/get-element "dashboard-fonts-title")]
|
||||
|
@ -733,34 +737,31 @@
|
|||
(dom/set-attribute! font-title "tabindex" "-1")))))))
|
||||
go-drafts
|
||||
(mf/use-fn
|
||||
(mf/deps team default-project-id)
|
||||
(mf/deps team-id default-project-id)
|
||||
(fn []
|
||||
(st/emit! (rt/nav :dashboard-files
|
||||
{:team-id (:id team)
|
||||
:project-id default-project-id}))))
|
||||
(st/emit! (dcm/go-to-dashboard-files :team-id team-id :project-id default-project-id))))
|
||||
|
||||
go-drafts-with-key
|
||||
(mf/use-fn
|
||||
(mf/deps team default-project-id)
|
||||
#(st/emit! (rt/nav :dashboard-files {:team-id (:id team)
|
||||
:project-id default-project-id})
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(let [drafts-title (dom/get-element "dashboard-drafts-title")]
|
||||
(when drafts-title
|
||||
(dom/set-attribute! drafts-title "tabindex" "0")
|
||||
(dom/focus! drafts-title)
|
||||
(dom/set-attribute! drafts-title "tabindex" "-1")))))))
|
||||
(mf/deps team-id default-project-id)
|
||||
(fn []
|
||||
(st/emit! (dcm/go-to-dashboard-files :team-id team-id :project-id default-project-id))
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(when-let [title (dom/get-element "dashboard-drafts-title")]
|
||||
(dom/set-attribute! title "tabindex" "0")
|
||||
(dom/focus! title)
|
||||
(dom/set-attribute! title "tabindex" "-1"))))))
|
||||
|
||||
go-libs
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-libraries {:team-id (:id team)})))
|
||||
(mf/deps team-id)
|
||||
#(st/emit! (dcm/go-to-dashboard-libraries :team-id team-id)))
|
||||
|
||||
go-libs-with-key
|
||||
(mf/use-fn
|
||||
(mf/deps team)
|
||||
#(st/emit! (rt/nav :dashboard-libraries {:team-id (:id team)})
|
||||
(mf/deps team-id)
|
||||
#(st/emit! (dcm/go-to-dashboard-libraries :team-id team-id)
|
||||
(ts/schedule-on-idle
|
||||
(fn []
|
||||
(let [libs-title (dom/get-element "dashboard-libraries-title")]
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
|
@ -62,10 +62,10 @@
|
|||
{::mf/wrap [mf/memo]
|
||||
::mf/props :obj}
|
||||
[{:keys [section team]}]
|
||||
(let [on-nav-members (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
||||
on-nav-settings (mf/use-fn #(st/emit! (dd/go-to-team-settings)))
|
||||
on-nav-invitations (mf/use-fn #(st/emit! (dd/go-to-team-invitations)))
|
||||
on-nav-webhooks (mf/use-fn #(st/emit! (dd/go-to-team-webhooks)))
|
||||
(let [on-nav-members (mf/use-fn #(st/emit! (dcm/go-to-dashboard-members)))
|
||||
on-nav-settings (mf/use-fn #(st/emit! (dcm/go-to-dashboard-settings)))
|
||||
on-nav-invitations (mf/use-fn #(st/emit! (dcm/go-to-dashboard-invitations)))
|
||||
on-nav-webhooks (mf/use-fn #(st/emit! (dcm/go-to-dashboard-webhooks)))
|
||||
|
||||
route (mf/deref refs/route)
|
||||
invite-email (-> route :query-params :invite-email)
|
||||
|
@ -375,7 +375,7 @@
|
|||
(st/emit! (modal/show params)))))
|
||||
|
||||
on-success
|
||||
(mf/use-fn (fn [] (rx/of (dd/go-to-default-team))))
|
||||
(mf/use-fn #(rx/of (dcm/go-to-dashboard-recent :team-id :default)))
|
||||
|
||||
on-error
|
||||
(mf/use-fn
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.schema :as sm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
|
@ -18,7 +19,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -28,15 +28,15 @@
|
|||
|
||||
(defn- on-create-success
|
||||
[_form response]
|
||||
(let [msg "Team created successfully"]
|
||||
(st/emit! (ntf/success msg)
|
||||
(modal/hide)
|
||||
(rt/nav :dashboard-projects {:team-id (:id response)}))))
|
||||
(let [message "Team created successfully"
|
||||
team-id (:id response)]
|
||||
(st/emit! (ntf/success message)
|
||||
(dcm/go-to-dashboard-recent :team-id team-id))))
|
||||
|
||||
(defn- on-update-success
|
||||
[_form _response]
|
||||
(let [msg "Team created successfully"]
|
||||
(st/emit! (ntf/success msg)
|
||||
(let [message "Team created successfully"]
|
||||
(st/emit! (ntf/success message)
|
||||
(modal/hide))))
|
||||
|
||||
(defn- on-error
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.config :as cf]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
|
@ -18,7 +19,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :as storage]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
|
@ -43,9 +43,9 @@
|
|||
:section section})
|
||||
|
||||
(when-not (some? project-id)
|
||||
(rt/nav :dashboard-files
|
||||
{:team-id team-id
|
||||
:project-id default-project-id}))))]
|
||||
(dcm/go-to-dashboard-recent
|
||||
:team-id team-id
|
||||
:project-id default-project-id))))]
|
||||
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "import-template-launch"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.data.team :as dtm]
|
||||
|
@ -17,7 +18,6 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -84,7 +84,7 @@
|
|||
(st/emit! (du/update-profile-props {:onboarding-team-id team-id
|
||||
:onboarding-viewed true})
|
||||
(when go-to-team?
|
||||
(rt/nav :dashboard-projects {:team-id team-id}))))))
|
||||
(dcm/go-to-dashboard-recent :team-id team-id))))))
|
||||
|
||||
on-error
|
||||
(mf/use-fn
|
||||
|
|
|
@ -7,34 +7,17 @@
|
|||
(ns app.main.ui.routes
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uri :as u]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(s/def ::page-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::section ::us/keyword)
|
||||
(s/def ::index ::us/integer)
|
||||
(s/def ::token (s/nilable ::us/not-empty-string))
|
||||
(s/def ::share-id ::us/uuid)
|
||||
|
||||
(s/def ::viewer-path-params
|
||||
(s/keys :req-un [::file-id]))
|
||||
|
||||
(s/def ::viewer-query-params
|
||||
(s/keys :opt-un [::index ::share-id ::section ::page-id]))
|
||||
|
||||
(s/def ::any any?)
|
||||
|
||||
(def routes
|
||||
[["/auth"
|
||||
["/login" :auth-login]
|
||||
|
@ -53,11 +36,10 @@
|
|||
["/access-tokens" :settings-access-tokens]]
|
||||
|
||||
["/frame-preview" :frame-preview]
|
||||
["/view/:file-id"
|
||||
{:name :viewer
|
||||
:conform
|
||||
{:path-params ::viewer-path-params
|
||||
:query-params ::viewer-query-params}}]
|
||||
|
||||
["/view" :viewer]
|
||||
|
||||
["/view/:file-id" :viewer-legacy]
|
||||
|
||||
(when *assert*
|
||||
["/debug/icons-preview" :debug-icons-preview])
|
||||
|
@ -65,33 +47,32 @@
|
|||
;; Used for export
|
||||
["/render-sprite/:file-id" :render-sprite]
|
||||
|
||||
["/dashboard/team/:team-id"
|
||||
["/members" :dashboard-team-members]
|
||||
["/invitations" :dashboard-team-invitations]
|
||||
["/webhooks" :dashboard-team-webhooks]
|
||||
["/settings" :dashboard-team-settings]
|
||||
["/projects" :dashboard-projects]
|
||||
["/dashboard"
|
||||
["/members" :dashboard-members]
|
||||
["/invitations" :dashboard-invitations]
|
||||
["/webhooks" :dashboard-webhooks]
|
||||
["/settings" :dashboard-settings]
|
||||
["/recent" :dashboard-recent]
|
||||
["/search" :dashboard-search]
|
||||
["/fonts" :dashboard-fonts]
|
||||
["/fonts/providers" :dashboard-font-providers]
|
||||
["/libraries" :dashboard-libraries]
|
||||
["/projects/:project-id" :dashboard-files]]
|
||||
["/files" :dashboard-files]]
|
||||
|
||||
["/workspace/:project-id/:file-id" :workspace]])
|
||||
["/dashboard/team/:team-id"
|
||||
["/members" :dashboard-legacy-team-members]
|
||||
["/invitations" :dashboard-legacy-team-invitations]
|
||||
["/webhooks" :dashboard-legacy-team-webhooks]
|
||||
["/settings" :dashboard-legacy-team-settings]
|
||||
["/projects" :dashboard-legacy-projects]
|
||||
["/search" :dashboard-legacy-search]
|
||||
["/fonts" :dashboard-legacy-fonts]
|
||||
["/fonts/providers" :dashboard-legacy-font-providers]
|
||||
["/libraries" :dashboard-legacy-libraries]
|
||||
["/projects/:project-id" :dashboard-legacy-files]]
|
||||
|
||||
(defn- match-path
|
||||
[router path]
|
||||
(when-let [match (rt/match router path)]
|
||||
(if-let [conform (get-in match [:data :conform])]
|
||||
(let [spath (get conform :path-params ::any)
|
||||
squery (get conform :query-params ::any)]
|
||||
(try
|
||||
(-> (dissoc match :params)
|
||||
(assoc :path-params (us/conform spath (get match :path-params))
|
||||
:query-params (us/conform squery (get match :query-params))))
|
||||
(catch :default _
|
||||
nil)))
|
||||
match)))
|
||||
["/workspace" :workspace]
|
||||
["/workspace/:project-id/:file-id" :workspace-legacy]])
|
||||
|
||||
(defn on-navigate
|
||||
[router path]
|
||||
|
@ -99,8 +80,9 @@
|
|||
[base-path qs] (str/split path "?")
|
||||
location-path (dm/str (.-origin location) (.-pathname location))
|
||||
valid-location? (= location-path (dm/str cf/public-uri))
|
||||
match (match-path router path)
|
||||
match (rt/match router path)
|
||||
empty-path? (or (= base-path "") (= base-path "/"))]
|
||||
|
||||
(cond
|
||||
(not valid-location?)
|
||||
(st/emit! (rt/assign-exception {:type :not-found}))
|
||||
|
@ -121,9 +103,9 @@
|
|||
empty-path?
|
||||
(let [team-id (or (dtm/get-last-team-id)
|
||||
(:default-team-id profile))]
|
||||
(st/emit! (rt/nav :dashboard-projects
|
||||
{:team-id team-id}
|
||||
(u/query-string->map qs))))
|
||||
(st/emit! (rt/nav :dashboard-recent
|
||||
(-> (u/query-string->map qs)
|
||||
(assoc :team-id team-id)))))
|
||||
|
||||
:else
|
||||
(st/emit! (rt/assign-exception {:type :not-found})))))))))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.main.data.dashboard.shortcuts :as sc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.settings.access-tokens :refer [access-tokens-page]]
|
||||
|
@ -20,7 +21,6 @@
|
|||
[app.main.ui.settings.profile :refer [profile-page]]
|
||||
[app.main.ui.settings.sidebar :refer [sidebar]]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc header
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.config :as cf]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.sidebar :refer [profile-section*]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -26,6 +27,7 @@
|
|||
(def ^:private feedback-icon
|
||||
(i/icon-xref :feedback (stl/css :feedback-icon)))
|
||||
|
||||
;; FIXME: move to common
|
||||
(def ^:private go-settings-profile
|
||||
#(st/emit! (rt/nav :settings-profile)))
|
||||
|
||||
|
@ -64,7 +66,7 @@
|
|||
go-dashboard
|
||||
(mf/use-fn
|
||||
(mf/deps team-id)
|
||||
#(st/emit! (rt/nav :dashboard-projects {:team-id team-id})))]
|
||||
#(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)))]
|
||||
|
||||
[:div {:class (stl/css :sidebar-content)}
|
||||
[:div {:class (stl/css :sidebar-content-section)}
|
||||
|
|
|
@ -11,10 +11,11 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.pprint :as pp]
|
||||
[app.common.uri :as u]
|
||||
[app.main.data.common :as dc]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.auth.login :refer [login-methods]]
|
||||
[app.main.ui.auth.recovery-request :refer [recovery-request-page recovery-sent-page]]
|
||||
|
@ -26,7 +27,6 @@
|
|||
[app.main.ui.viewer.header :as viewer.header]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -213,7 +213,8 @@
|
|||
(mf/use-fn
|
||||
(mf/deps profile)
|
||||
(fn []
|
||||
(st/emit! (rt/nav :dashboard-projects {:team-id (:default-team-id profile)}))))
|
||||
(let [team-id (:default-team-id profile)]
|
||||
(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)))))
|
||||
|
||||
on-success
|
||||
(mf/use-fn
|
||||
|
@ -233,7 +234,7 @@
|
|||
{:team-id team-id})
|
||||
mdata {:on-success on-success
|
||||
:on-error on-error}]
|
||||
(st/emit! (dc/create-team-access-request
|
||||
(st/emit! (dcm/create-team-access-request
|
||||
(with-meta params mdata))))))]
|
||||
|
||||
[:*
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
|
||||
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar*]]
|
||||
[app.main.ui.viewer.header :as header]
|
||||
[app.main.ui.viewer.inspect :as inspect]
|
||||
[app.main.ui.viewer.interactions :as interactions]
|
||||
|
@ -129,8 +129,8 @@
|
|||
:comment-sidebar show-sidebar?}]
|
||||
|
||||
(when show-sidebar?
|
||||
[:& comments-sidebar
|
||||
{:users users
|
||||
[:> comments-sidebar*
|
||||
{:profiles users
|
||||
:frame frame
|
||||
:page page}])]))
|
||||
|
||||
|
@ -274,9 +274,9 @@
|
|||
:page page
|
||||
:zoom zoom}])]])
|
||||
|
||||
(mf/defc viewer-content
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [data page-id share-id section index interactions-mode share] :as props}]
|
||||
(mf/defc viewer-content*
|
||||
{::mf/props :obj}
|
||||
[{:keys [data page-id share-id section index interactions-mode share]}]
|
||||
(let [{:keys [file users project permissions]} data
|
||||
allowed (or
|
||||
(= section :interactions)
|
||||
|
@ -620,8 +620,8 @@
|
|||
|
||||
;; --- Component: Viewer
|
||||
|
||||
(mf/defc viewer
|
||||
{::mf/wrap-props false}
|
||||
(mf/defc viewer*
|
||||
{::mf/props :obj}
|
||||
[{:keys [file-id share-id page-id] :as props}]
|
||||
(mf/with-effect [file-id page-id share-id]
|
||||
(let [params {:file-id file-id
|
||||
|
@ -630,9 +630,10 @@
|
|||
(st/emit! (dv/initialize params))
|
||||
(fn []
|
||||
(st/emit! (dv/finalize params)))))
|
||||
|
||||
(if-let [data (mf/deref refs/viewer-data)]
|
||||
(let [props (obj/merge props #js {:data data :key (dm/str file-id)})]
|
||||
[:> viewer-content props])
|
||||
[:> viewer-content* props])
|
||||
|
||||
[:> loader* {:title (tr "labels.loading")
|
||||
:overlay true}]))
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
{:thread thread
|
||||
:position-modifier modifier1
|
||||
:viewport {:offset-x 0 :offset-y 0 :width (:width vsize) :height (:height vsize)}
|
||||
:users users
|
||||
:profiles users
|
||||
:zoom zoom}])
|
||||
|
||||
(when-let [draft (:draft local)]
|
||||
|
@ -231,10 +231,11 @@
|
|||
:on-submit on-draft-submit
|
||||
:zoom zoom}])]]]))
|
||||
|
||||
(mf/defc comments-sidebar
|
||||
[{:keys [users frame page]}]
|
||||
(mf/defc comments-sidebar*
|
||||
{::mf/props :obj}
|
||||
[{:keys [profiles frame page]}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
local (mf/deref refs/comments-local)
|
||||
local (mf/deref refs/comments-local)
|
||||
threads-map (mf/deref refs/comment-threads)
|
||||
threads (->> (vals threads-map)
|
||||
(dcm/apply-filters local profile)
|
||||
|
@ -242,4 +243,8 @@
|
|||
(gsh/has-point? frame position))))]
|
||||
[:aside {:class (stl/css :comments-sidebar)}
|
||||
[:div {:class (stl/css :settings-bar-inside)}
|
||||
[:& wc/comments-sidebar {:from-viewer true :users users :threads threads :page-id (:id page)}]]]))
|
||||
[:> wc/comments-sidebar*
|
||||
{:from-viewer true
|
||||
:profiles profiles
|
||||
:threads threads
|
||||
:page-id (:id page)}]]]))
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.viewer.comments :refer [comments-menu]]
|
||||
[app.main.ui.viewer.interactions :refer [flows-menu* interactions-menu]]
|
||||
[app.main.ui.viewer.interactions :refer [flows-menu* interactions-menu*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[okulary.core :as l]
|
||||
|
@ -173,7 +173,8 @@
|
|||
:interactions [:*
|
||||
(when index
|
||||
[:> flows-menu* {:page page :index index}])
|
||||
[:& interactions-menu {:interactions-mode interactions-mode}]]
|
||||
[:> interactions-menu*
|
||||
{:interactions-mode interactions-mode}]]
|
||||
:comments [:& comments-menu]
|
||||
[:div {:class (stl/css :view-options)}])
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
[app.util.webapi :as wapi]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -49,13 +50,26 @@
|
|||
</body>
|
||||
</html>")
|
||||
|
||||
;; FIXME: this code need to be refactored
|
||||
(defn get-viewer-objects
|
||||
([]
|
||||
(let [route (deref refs/route)
|
||||
page-id (:page-id (:query-params route))]
|
||||
(get-viewer-objects page-id)))
|
||||
([page-id]
|
||||
(l/derived
|
||||
(fn [state]
|
||||
(let [objects (refs/get-viewer-objects state page-id)]
|
||||
objects))
|
||||
st/state =)))
|
||||
|
||||
(defn- use-objects [from]
|
||||
(let [page-objects-ref
|
||||
(mf/with-memo [from]
|
||||
(if (= from :workspace)
|
||||
;; FIXME: fix naming consistency issues
|
||||
refs/workspace-page-objects
|
||||
(refs/get-viewer-objects)))]
|
||||
(get-viewer-objects)))]
|
||||
(mf/deref page-objects-ref)))
|
||||
|
||||
(defn- shapes->images
|
||||
|
|
|
@ -267,7 +267,8 @@
|
|||
(when (= flow-id (:id current-flow))
|
||||
[:span {:class (stl/css :icon)} i/tick])])]]])))
|
||||
|
||||
(mf/defc interactions-menu
|
||||
(mf/defc interactions-menu*
|
||||
{::mf/props :obj}
|
||||
[{:keys [interactions-mode]}]
|
||||
(let [show-dropdown? (mf/use-state false)
|
||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||
|
@ -281,6 +282,7 @@
|
|||
(keyword))]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dv/set-interactions-mode mode)))))]
|
||||
|
||||
[:div {:on-click toggle-dropdown
|
||||
:class (stl/css :view-options)}
|
||||
[:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.shapes.bool :as bool]
|
||||
[app.main.ui.shapes.circle :as circle]
|
||||
|
@ -26,7 +27,6 @@
|
|||
[app.main.ui.shapes.text :as text]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[app.util.router :as rt]
|
||||
[app.util.timers :as tm]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -34,8 +34,8 @@
|
|||
(def base-frame-ctx (mf/create-context nil))
|
||||
(def frame-offset-ctx (mf/create-context nil))
|
||||
|
||||
(def viewer-interactions-show?
|
||||
(l/derived :interactions-show? refs/viewer-local))
|
||||
(def ^:private ref:viewer-show-interactions
|
||||
(l/derived :show-interactions refs/viewer-local))
|
||||
|
||||
(defn- find-relative-to-base-frame
|
||||
[shape objects overlays-ids base-frame]
|
||||
|
@ -280,7 +280,7 @@
|
|||
sems))))
|
||||
|
||||
(mf/defc interaction
|
||||
[{:keys [shape interactions interactions-show?]}]
|
||||
[{:keys [shape interactions show-interactions]}]
|
||||
(let [{:keys [x y width height]} (:selrect shape)]
|
||||
(when-not (empty? interactions)
|
||||
[:rect {:x (- x 1)
|
||||
|
@ -289,8 +289,8 @@
|
|||
:height (+ height 2)
|
||||
:fill "var(--color-accent-tertiary)"
|
||||
:stroke "var(--color-accent-tertiary)"
|
||||
:stroke-width (if interactions-show? 1 0)
|
||||
:fill-opacity (if interactions-show? 0.2 0)
|
||||
:stroke-width (if show-interactions 1 0)
|
||||
:fill-opacity (if show-interactions 0.2 0)
|
||||
:transform (gsh/transform-str shape)}])))
|
||||
|
||||
|
||||
|
@ -309,7 +309,7 @@
|
|||
all-objects (or (unchecked-get props "all-objects") objects)
|
||||
base-frame (mf/use-ctx base-frame-ctx)
|
||||
frame-offset (mf/use-ctx frame-offset-ctx)
|
||||
interactions-show? (mf/deref viewer-interactions-show?)
|
||||
show-interactions (mf/deref ref:viewer-show-interactions)
|
||||
overlays (mf/deref refs/viewer-overlays)
|
||||
interactions (:interactions shape)
|
||||
svg-element? (and (= :svg-raw (:type shape))
|
||||
|
@ -355,7 +355,7 @@
|
|||
|
||||
[:& interaction {:shape shape
|
||||
:interactions interactions
|
||||
:interactions-show? interactions-show?}]]
|
||||
:show-interactions show-interactions}]]
|
||||
|
||||
;; Don't wrap svg elements inside a <g> otherwise some can break
|
||||
[:& component {:shape shape
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.select :refer [select]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.webapi :as wapi]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -69,17 +69,16 @@
|
|||
(= (:pages %) pages))
|
||||
slinks)]
|
||||
(when slink
|
||||
(let [pparams (:path-params route)
|
||||
page-id (d/seek #(contains? (:pages slink) %) page-ids)
|
||||
qparams (-> (:query-params route)
|
||||
(let [page-id (d/seek #(contains? (:pages slink) %) page-ids)
|
||||
params (-> (:query-params route)
|
||||
(assoc :share-id (:id slink))
|
||||
(assoc :page-id page-id)
|
||||
(assoc :index "0"))
|
||||
qparams (if (nil? zoom-type)
|
||||
(dissoc qparams :zoom)
|
||||
(assoc qparams :zoom zoom-type))
|
||||
params (if (nil? zoom-type)
|
||||
(dissoc params :zoom)
|
||||
(assoc params :zoom zoom-type))
|
||||
|
||||
href (rt/resolve router :viewer pparams qparams)]
|
||||
href (rt/resolve router :viewer params)]
|
||||
(dm/str (assoc cf/public-uri :fragment href))))))
|
||||
|
||||
on-close
|
||||
|
|
|
@ -8,12 +8,10 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.persistence :as dps]
|
||||
[app.main.data.plugins :as dpl]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -46,7 +44,7 @@
|
|||
[file-id]
|
||||
(l/derived (fn [state]
|
||||
(let [data (:workspace-data state)]
|
||||
(and (:workspace-ready? state)
|
||||
(and (:workspace-ready state)
|
||||
(= file-id (:current-file-id state))
|
||||
(= file-id (:id data)))))
|
||||
st/state))
|
||||
|
@ -125,14 +123,17 @@
|
|||
:file file
|
||||
:page-id page-id}]])]))
|
||||
|
||||
(mf/defc workspace-loader
|
||||
(mf/defc workspace-loader*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[]
|
||||
[:> loader* {:title (tr "labels.loading")
|
||||
:class (stl/css :workspace-loader)
|
||||
:overlay true}])
|
||||
|
||||
(mf/defc workspace-page
|
||||
{::mf/wrap-props false}
|
||||
(mf/defc workspace-page*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [page-id file layout wglobal]}]
|
||||
(let [page-id (hooks/use-equal-memo page-id)
|
||||
page-ready* (mf/with-memo [page-id]
|
||||
|
@ -147,18 +148,20 @@
|
|||
(mf/with-effect [page-id]
|
||||
(if (some? page-id)
|
||||
(st/emit! (dw/initialize-page page-id))
|
||||
(st/emit! (dw/go-to-page)))
|
||||
(st/emit! (dcm/go-to-workspace)))
|
||||
(fn []
|
||||
(when (some? page-id)
|
||||
(st/emit! (dw/finalize-page page-id)))))
|
||||
|
||||
(if ^boolean page-ready?
|
||||
[:& workspace-content {:page-id page-id
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
[:& workspace-loader])))
|
||||
[:& workspace-loader*])))
|
||||
|
||||
(mf/defc workspace
|
||||
|
||||
(mf/defc workspace*
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo]}
|
||||
[{:keys [project-id file-id page-id layout-name]}]
|
||||
|
@ -168,9 +171,7 @@
|
|||
|
||||
team (mf/deref refs/team)
|
||||
file (mf/deref refs/workspace-file)
|
||||
project (mf/deref refs/workspace-project)
|
||||
|
||||
team-id (:team-id project)
|
||||
file-name (:name file)
|
||||
permissions (:permissions team)
|
||||
|
||||
|
@ -192,36 +193,32 @@
|
|||
|
||||
;; Setting the layout preset by its name
|
||||
(mf/with-effect [layout-name]
|
||||
(st/emit! (dw/initialize-layout layout-name)))
|
||||
(st/emit! (dw/initialize-workspace-layout layout-name)))
|
||||
|
||||
(mf/with-effect [file-name]
|
||||
(when file-name
|
||||
(dom/set-html-title (tr "title.workspace" file-name))))
|
||||
|
||||
(mf/with-effect [project-id file-id]
|
||||
(st/emit! (dw/initialize-file project-id file-id))
|
||||
(mf/with-effect [file-id]
|
||||
(st/emit! (dw/initialize-workspace file-id))
|
||||
(fn []
|
||||
(st/emit! ::dps/force-persist
|
||||
(dc/stop-picker)
|
||||
(modal/hide)
|
||||
(ntf/hide)
|
||||
(dw/finalize-file project-id file-id))))
|
||||
(dw/finalize-workspace file-id))))
|
||||
|
||||
[:& (mf/provider ctx/current-file-id) {:value file-id}
|
||||
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
||||
[:& (mf/provider ctx/current-team-id) {:value team-id}
|
||||
[:& (mf/provider ctx/current-page-id) {:value page-id}
|
||||
[:& (mf/provider ctx/components-v2) {:value components-v2?}
|
||||
[:& (mf/provider ctx/design-tokens) {:value design-tokens?}
|
||||
[:& (mf/provider ctx/workspace-read-only?) {:value read-only?}
|
||||
[:& (mf/provider ctx/permissions) {:value permissions}
|
||||
[:section {:class (stl/css :workspace)
|
||||
:style {:background-color background-color
|
||||
:touch-action "none"}}
|
||||
[:& context-menu]
|
||||
(if ^boolean file-ready?
|
||||
[:& workspace-page {:page-id page-id
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
[:& workspace-loader])]]]]]]]]]))
|
||||
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
||||
[:& (mf/provider ctx/current-file-id) {:value file-id}
|
||||
[:& (mf/provider ctx/current-page-id) {:value page-id}
|
||||
[:& (mf/provider ctx/components-v2) {:value components-v2?}
|
||||
[:& (mf/provider ctx/design-tokens) {:value design-tokens?}
|
||||
[:& (mf/provider ctx/workspace-read-only?) {:value read-only?}
|
||||
[:section {:class (stl/css :workspace)
|
||||
:style {:background-color background-color
|
||||
:touch-action "none"}}
|
||||
[:& context-menu]
|
||||
|
||||
(if ^boolean file-ready?
|
||||
[:> workspace-page* {:page-id page-id
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
[:> workspace-loader* {}])]]]]]]]))
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
(ns app.main.ui.workspace.comments
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.comments :as dcmt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.comments :as dwcm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.comments :as cmt]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
|
@ -37,14 +39,14 @@
|
|||
(let [mode (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(keyword))]
|
||||
(st/emit! (dcm/update-filters {:mode mode})))))
|
||||
(st/emit! (dcmt/update-filters {:mode mode})))))
|
||||
|
||||
update-show
|
||||
(mf/use-fn
|
||||
(mf/deps cshow)
|
||||
(fn []
|
||||
(let [mode (if (= :pending cshow) :all :pending)]
|
||||
(st/emit! (dcm/update-filters {:show mode})))))]
|
||||
(st/emit! (dcmt/update-filters {:show mode})))))]
|
||||
|
||||
[:ul {:class (stl/css-case :comment-mode-dropdown true
|
||||
:viewer-dropdown from-viewer)}
|
||||
|
@ -68,13 +70,13 @@
|
|||
[:span {:class (stl/css :label)} (tr "labels.hide-resolved-comments")]
|
||||
[:span {:class (stl/css :icon)} i/tick]]]))
|
||||
|
||||
(mf/defc comments-sidebar
|
||||
(mf/defc comments-sidebar*
|
||||
{::mf/props :obj}
|
||||
[{:keys [users threads page-id from-viewer]}]
|
||||
[{:keys [profiles threads page-id from-viewer]}]
|
||||
(let [threads-map (mf/deref refs/threads-ref)
|
||||
profile (mf/deref refs/profile)
|
||||
users-refs (mf/deref refs/current-file-comments-users)
|
||||
users (or users users-refs)
|
||||
profiles' (mf/deref refs/profiles)
|
||||
profiles (or profiles profiles')
|
||||
local (mf/deref refs/comments-local)
|
||||
|
||||
state* (mf/use-state false)
|
||||
|
@ -84,7 +86,7 @@
|
|||
(->> (vals threads-map)
|
||||
(sort-by :modified-at)
|
||||
(reverse)
|
||||
(dcm/apply-filters local profile))
|
||||
(dcmt/apply-filters local profile))
|
||||
threads)
|
||||
|
||||
close-section
|
||||
|
@ -92,12 +94,12 @@
|
|||
(mf/deps from-viewer)
|
||||
(fn []
|
||||
(if from-viewer
|
||||
(st/emit! (dcm/update-options {:show-sidebar? false}))
|
||||
(st/emit! (dcmt/update-options {:show-sidebar? false}))
|
||||
(st/emit! (dw/clear-edition-mode)
|
||||
(dw/deselect-all true)))))
|
||||
|
||||
tgroups (->> threads
|
||||
(dcm/group-threads-by-page))
|
||||
(dcmt/group-threads-by-page))
|
||||
|
||||
page-id (or page-id (mf/use-ctx ctx/current-page-id))
|
||||
|
||||
|
@ -112,14 +114,16 @@
|
|||
(mf/deps page-id)
|
||||
(fn [thread]
|
||||
(when (not= page-id (:page-id thread))
|
||||
(st/emit! (dw/go-to-page (:page-id thread))))
|
||||
(st/emit! (dcm/go-to-workspace :page-id (:page-id thread)
|
||||
::rt/new-window true)))
|
||||
(tm/schedule
|
||||
(fn []
|
||||
(st/emit! (when (not= page-id (:page-id thread))
|
||||
(dw/select-for-drawing :comments))
|
||||
(dwcm/center-to-comment-thread thread)
|
||||
(-> (dcm/open-thread thread)
|
||||
(-> (dcmt/open-thread thread)
|
||||
(with-meta {::ev/origin "workspace"})))))))]
|
||||
|
||||
[:div {:class (stl/css-case :comments-section true
|
||||
:from-viewer from-viewer)}
|
||||
[:div {:class (stl/css-case :comments-section-title true
|
||||
|
@ -149,12 +153,12 @@
|
|||
[:& cmt/comment-thread-group
|
||||
{:group (first tgroups)
|
||||
:on-thread-click on-thread-click
|
||||
:users users}]
|
||||
:profiles profiles}]
|
||||
(for [tgroup (rest tgroups)]
|
||||
[:& cmt/comment-thread-group
|
||||
{:group tgroup
|
||||
:on-thread-click on-thread-click
|
||||
:users users
|
||||
:profiles profiles
|
||||
:key (:page-id tgroup)}])]
|
||||
|
||||
[:div {:class (stl/css :thread-group-placeholder)}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as i]
|
||||
|
@ -19,21 +21,20 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;; --- Header Component
|
||||
|
||||
(mf/defc left-header
|
||||
{::mf/wrap-props false}
|
||||
{::mf/props :obj}
|
||||
[{:keys [file layout project page-id class]}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
file-id (:id file)
|
||||
file-name (:name file)
|
||||
project-id (:id project)
|
||||
team-id (:team-id project)
|
||||
shared? (:is-shared file)
|
||||
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
||||
editing* (mf/use-state false)
|
||||
|
@ -69,22 +70,20 @@
|
|||
|
||||
go-back
|
||||
(mf/use-fn
|
||||
(mf/deps project)
|
||||
(fn []
|
||||
(close-modals)
|
||||
;; FIXME: move set-mode to uri?
|
||||
(st/emit! (dw/set-options-mode :design)
|
||||
(dw/go-to-dashboard project))))
|
||||
(dcm/go-to-dashboard-recent))))
|
||||
|
||||
nav-to-project
|
||||
(mf/use-fn
|
||||
(mf/deps team-id project-id)
|
||||
#(st/emit! (rt/nav-new-window* {:rname :dashboard-files
|
||||
:path-params {:team-id team-id
|
||||
:project-id project-id}})))]
|
||||
#(st/emit! (dcm/go-to-dashboard-files ::rt/new-window true)))]
|
||||
|
||||
(mf/with-effect [editing?]
|
||||
(when ^boolean editing?
|
||||
(dom/select-text! (mf/ref-val input-ref))))
|
||||
|
||||
[:header {:class (dm/str class " " (stl/css :workspace-header-left))}
|
||||
[:a {:on-click go-back
|
||||
:class (stl/css :main-icon)} i/logo-icon]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[app.config :as cf]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.data.workspace.colors :as mdc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -103,10 +104,10 @@
|
|||
[:li {:class (stl/css :element-count)}
|
||||
(tr "workspace.libraries.typography" typography-count)])])
|
||||
|
||||
|
||||
(mf/defc libraries-tab
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [file-id shared? linked-libraries shared-libraries]}]
|
||||
(mf/defc libraries-tab*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [file-id is-shared linked-libraries shared-libraries]}]
|
||||
(let [search-term* (mf/use-state "")
|
||||
search-term (deref search-term*)
|
||||
library-ref (mf/with-memo [file-id]
|
||||
|
@ -127,7 +128,7 @@
|
|||
shared-libraries
|
||||
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
|
||||
(when shared-libraries
|
||||
(->> shared-libraries
|
||||
(->> (vals shared-libraries)
|
||||
(remove #(= (:id %) file-id))
|
||||
(remove #(contains? linked-libraries (:id %)))
|
||||
(filter #(matches-search (:name %) search-term))
|
||||
|
@ -219,7 +220,7 @@
|
|||
:graphics-count (count media)
|
||||
:colors-count (count colors)
|
||||
:typography-count (count typographies)}]]]
|
||||
(if ^boolean shared?
|
||||
(if ^boolean is-shared
|
||||
[:input {:class (stl/css :item-unpublish)
|
||||
:type "button"
|
||||
:value (tr "common.unpublish")
|
||||
|
@ -348,8 +349,9 @@
|
|||
:colors colors
|
||||
:typographies typographies}]))
|
||||
|
||||
(mf/defc updates-tab
|
||||
{::mf/wrap-props false}
|
||||
(mf/defc updates-tab*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [file-id file-data libraries]}]
|
||||
(let [summary?* (mf/use-state true)
|
||||
summary? (deref summary?*)
|
||||
|
@ -487,11 +489,9 @@
|
|||
{::mf/register modal/components
|
||||
::mf/register-as :libraries-dialog}
|
||||
[{:keys [starting-tab] :as props :or {starting-tab :libraries}}]
|
||||
(let [project (mf/deref refs/workspace-project)
|
||||
file-data (mf/deref refs/workspace-data)
|
||||
(let [file-data (mf/deref refs/workspace-data)
|
||||
file (mf/deref ref:workspace-file)
|
||||
|
||||
team-id (:team-id project)
|
||||
file-id (:id file)
|
||||
shared? (:is-shared file)
|
||||
|
||||
|
@ -499,37 +499,44 @@
|
|||
libraries (mf/with-memo [libraries]
|
||||
(d/removem (fn [[_ val]] (:is-indirect val)) libraries))
|
||||
|
||||
;; NOTE: we really don't need react on shared files
|
||||
shared-libraries
|
||||
(mf/deref refs/workspace-shared-files)
|
||||
(mf/deref refs/shared-files)
|
||||
|
||||
close-dialog-outside
|
||||
(mf/use-fn (fn [event]
|
||||
(when (= (dom/get-target event) (dom/get-current-target event))
|
||||
(modal/hide!))))
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(when (= (dom/get-target event) (dom/get-current-target event))
|
||||
(modal/hide!))))
|
||||
|
||||
close-dialog
|
||||
(mf/use-fn (fn [_]
|
||||
(modal/hide!)
|
||||
(modal/disallow-click-outside!)))
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(modal/hide!)
|
||||
(modal/disallow-click-outside!)))
|
||||
|
||||
libraries-tab
|
||||
(mf/html [:> libraries-tab*
|
||||
{:file-id file-id
|
||||
:is-shared shared?
|
||||
:linked-libraries libraries
|
||||
:shared-libraries shared-libraries}])
|
||||
|
||||
updates-tab
|
||||
(mf/html [:> updates-tab*
|
||||
{:file-id file-id
|
||||
:file-data file-data
|
||||
:libraries libraries}])
|
||||
|
||||
tabs
|
||||
#js [#js {:label (tr "workspace.libraries.libraries")
|
||||
:id "libraries"
|
||||
:content (mf/html [:& libraries-tab {:file-id file-id
|
||||
:shared? shared?
|
||||
:linked-libraries libraries
|
||||
:shared-libraries shared-libraries}])}
|
||||
|
||||
:content libraries-tab}
|
||||
#js {:label (tr "workspace.libraries.updates")
|
||||
:id "updates"
|
||||
:content (mf/html [:& updates-tab {:file-id file-id
|
||||
:file-data file-data
|
||||
:libraries libraries}])}]]
|
||||
:content updates-tab}]]
|
||||
|
||||
(mf/with-effect [team-id]
|
||||
(when team-id
|
||||
(st/emit! (dwl/fetch-shared-files {:team-id team-id}))))
|
||||
(mf/with-effect []
|
||||
(st/emit! (dtm/fetch-shared-files)))
|
||||
|
||||
[:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside :data-testid "libraries-modal"}
|
||||
[:div {:class (stl/css :modal-dialog)}
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -68,7 +67,7 @@
|
|||
(mf/use-fn #(dom/open-new-window "https://penpot.app/terms"))
|
||||
|
||||
nav-to-feedback
|
||||
(mf/use-fn #(st/emit! (rt/nav-new-window* {:rname :settings-feedback})))
|
||||
(mf/use-fn #(st/emit! (dcm/go-to-feedback)))
|
||||
|
||||
plugins?
|
||||
(features/active-feature? @st/state "plugins/runtime")
|
||||
|
@ -540,9 +539,8 @@
|
|||
|
||||
on-pin-version
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [_]
|
||||
(st/emit! (dwv/create-version file-id))))
|
||||
(st/emit! (dwv/create-version))))
|
||||
|
||||
on-pin-version-key-down
|
||||
(mf/use-fn
|
||||
|
|
|
@ -32,14 +32,14 @@
|
|||
(mf/defc active-sessions
|
||||
{::mf/memo true}
|
||||
[]
|
||||
(let [users (mf/deref refs/users)
|
||||
presence (mf/deref refs/workspace-presence)
|
||||
(let [profiles (mf/deref refs/profiles)
|
||||
presence (mf/deref refs/workspace-presence)
|
||||
|
||||
sessions (vals presence)
|
||||
num-sessions (count sessions)
|
||||
sessions (vals presence)
|
||||
num-sessions (count sessions)
|
||||
|
||||
open* (mf/use-state false)
|
||||
open? (and ^boolean (deref open*) (> num-sessions 2))
|
||||
open* (mf/use-state false)
|
||||
open? (and ^boolean (deref open*) (> num-sessions 2))
|
||||
on-open
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
|
@ -61,7 +61,7 @@
|
|||
[:& session-widget
|
||||
{:color (:color session)
|
||||
:index 0
|
||||
:profile (get users (:profile-id session))
|
||||
:profile (get profiles (:profile-id session))
|
||||
:key (dm/str (:id session))}])]])
|
||||
|
||||
[:button {:class (stl/css-case :active-users true)
|
||||
|
@ -74,5 +74,5 @@
|
|||
[:& session-widget
|
||||
{:color (:color session)
|
||||
:index index
|
||||
:profile (get users (:profile-id session))
|
||||
:profile (get profiles (:profile-id session))
|
||||
:key (dm/str (:id session))}])]]]))
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.config :as cf]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.shortcuts :as scd]
|
||||
|
@ -169,7 +170,7 @@
|
|||
(let [params {:page-id page-id
|
||||
:file-id file-id
|
||||
:section "interactions"}]
|
||||
(st/emit! (dw/go-to-viewer params)))))
|
||||
(st/emit! (dcm/go-to-viewer params)))))
|
||||
|
||||
active-comments
|
||||
(mf/use-fn
|
||||
|
|
|
@ -8,14 +8,16 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
||||
[app.main.ui.workspace.comments :refer [comments-sidebar]]
|
||||
[app.main.ui.workspace.comments :refer [comments-sidebar*]]
|
||||
[app.main.ui.workspace.left-header :refer [left-header]]
|
||||
[app.main.ui.workspace.right-header :refer [right-header]]
|
||||
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
|
||||
|
@ -47,36 +49,44 @@
|
|||
|
||||
(mf/defc left-sidebar
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
::mf/props :obj}
|
||||
[{:keys [layout file page-id] :as props}]
|
||||
(let [options-mode (mf/deref refs/options-mode-global)
|
||||
project (mf/deref refs/project)
|
||||
|
||||
design-tokens? (features/use-feature "design-tokens/v1")
|
||||
mode-inspect? (= options-mode :inspect)
|
||||
project (mf/deref refs/workspace-project)
|
||||
|
||||
design-tokens? (mf/use-ctx muc/design-tokens)
|
||||
|
||||
section (cond (or mode-inspect? (contains? layout :layers)) :layers
|
||||
(contains? layout :assets) :assets
|
||||
(contains? layout :tokens) :tokens)
|
||||
|
||||
shortcuts? (contains? layout :shortcuts)
|
||||
show-debug? (contains? layout :debug-panel)
|
||||
|
||||
{on-pointer-down :on-pointer-down on-lost-pointer-capture :on-lost-pointer-capture on-pointer-move :on-pointer-move parent-ref :parent-ref size :size}
|
||||
section (cond
|
||||
(or mode-inspect? (contains? layout :layers)) :layers
|
||||
(contains? layout :assets) :assets
|
||||
(contains? layout :tokens) :tokens)
|
||||
|
||||
{on-pointer-down :on-pointer-down
|
||||
on-lost-pointer-capture :on-lost-pointer-capture
|
||||
on-pointer-move :on-pointer-move
|
||||
parent-ref :parent-ref
|
||||
size :size}
|
||||
(use-resize-hook :left-sidebar 275 275 500 :x false :left)
|
||||
|
||||
{on-pointer-down-pages :on-pointer-down on-lost-pointer-capture-pages :on-lost-pointer-capture on-pointer-move-pages :on-pointer-move size-pages-opened :size}
|
||||
{on-pointer-down-pages :on-pointer-down
|
||||
on-lost-pointer-capture-pages :on-lost-pointer-capture
|
||||
on-pointer-move-pages :on-pointer-move
|
||||
size-pages-opened :size}
|
||||
(use-resize-hook :sitemap 200 38 400 :y false nil)
|
||||
|
||||
show-pages? (mf/use-state true)
|
||||
toggle-pages (mf/use-callback #(reset! show-pages? not))
|
||||
size-pages (mf/use-memo (mf/deps show-pages? size-pages-opened) (fn [] (if @show-pages? size-pages-opened 32)))
|
||||
toggle-pages (mf/use-fn #(reset! show-pages? not))
|
||||
size-pages (mf/with-memo [show-pages? size-pages-opened]
|
||||
(if @show-pages? size-pages-opened 32))
|
||||
|
||||
handle-collapse
|
||||
(mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
|
||||
|
||||
on-tab-change
|
||||
(mf/use-fn #(st/emit! (dw/go-to-layout (keyword %))))
|
||||
(mf/use-fn #(st/emit! (dcm/go-to-workspace :layout (keyword %))))
|
||||
|
||||
layers-tab
|
||||
(mf/html
|
||||
|
@ -138,8 +148,12 @@
|
|||
:global/four-row (> size 400))
|
||||
:style #js {"--width" (dm/str size "px")}}
|
||||
|
||||
[:& left-header {:file file :layout layout :project project :page-id page-id
|
||||
:class (stl/css :left-header)}]
|
||||
[:& left-header
|
||||
{:file file
|
||||
:layout layout
|
||||
:project project
|
||||
:page-id page-id
|
||||
:class (stl/css :left-header)}]
|
||||
|
||||
[:div {:on-pointer-down on-pointer-down
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
|
@ -234,7 +248,7 @@
|
|||
[:& debug-shape-info]
|
||||
|
||||
(true? is-comments?)
|
||||
[:& comments-sidebar]
|
||||
[:> comments-sidebar* {}]
|
||||
|
||||
(true? is-history?)
|
||||
[:> tab-switcher*
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc assets-libraries
|
||||
(mf/defc assets-libraries*
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [filters]}]
|
||||
(let [libraries (mf/deref refs/workspace-libraries)
|
||||
libraries (mf/with-memo [libraries]
|
||||
|
@ -193,4 +194,4 @@
|
|||
[:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
|
||||
[:*
|
||||
[:& assets-local-library {:filters filters}]
|
||||
[:& assets-libraries {:filters filters}]]]]]]))
|
||||
[:> assets-libraries* {:filters filters}]]]]]]))
|
||||
|
|
|
@ -391,20 +391,18 @@
|
|||
(do-update-remote-component))
|
||||
|
||||
do-show-in-assets
|
||||
#(st/emit! (if components-v2
|
||||
(dw/show-component-in-assets component-id)
|
||||
(dw/go-to-component component-id)))
|
||||
#(st/emit! (dw/show-component-in-assets component-id))
|
||||
|
||||
do-create-annotation
|
||||
#(st/emit! (dw/set-annotations-id-for-create id))
|
||||
|
||||
do-show-local-component
|
||||
#(st/emit! (dw/go-to-component component-id))
|
||||
#(st/emit! (dwl/go-to-local-component component-id))
|
||||
|
||||
;; When the show-remote is after a restore, the component may still be deleted
|
||||
do-show-remote-component
|
||||
#(let [comp (find-component shape true)] ;; When the show-remote is after a restore, the component may still be deleted
|
||||
(when comp
|
||||
(st/emit! (dwl/nav-to-component-file library-id comp))))
|
||||
#(when-let [comp (find-component shape true)]
|
||||
(st/emit! (dwl/go-to-component-file library-id comp)))
|
||||
|
||||
do-show-component
|
||||
(fn []
|
||||
|
|
|
@ -98,8 +98,8 @@
|
|||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(if local
|
||||
(st/emit! (dw/go-to-component component-id))
|
||||
(st/emit! (dwl/nav-to-component-file file-id component)))))
|
||||
(st/emit! (dwl/go-to-local-component component-id))
|
||||
(st/emit! (dwl/go-to-component-file file-id component)))))
|
||||
|
||||
on-drop
|
||||
(mf/use-fn
|
||||
|
@ -491,9 +491,9 @@
|
|||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(if local?
|
||||
(st/emit! (dw/go-to-component current-component-id))
|
||||
(st/emit! (dwl/go-to-local-component :id current-component-id))
|
||||
(let [component (d/seek #(= (:id %) current-component-id) components)]
|
||||
(st/emit! (dwl/nav-to-component-file file-id component))))))
|
||||
(st/emit! (dwl/go-to-component-file file-id component))))))
|
||||
|
||||
on-asset-click
|
||||
(mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
[app.main.ui.context :as ctx]
|
||||
|
@ -27,54 +28,53 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def lens:open-status
|
||||
(def ^:private ref:open-status
|
||||
(l/derived (l/in [:workspace-assets :open-status]) st/state))
|
||||
|
||||
(def lens:selected
|
||||
(def ^:private ref:selected
|
||||
(-> (l/in [:workspace-assets :selected])
|
||||
(l/derived st/state)))
|
||||
|
||||
(mf/defc file-library-title
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [open? local? project-id file-id page-id file-name]}]
|
||||
(mf/defc file-library-title*
|
||||
{::mf/props :obj}
|
||||
[{:keys [is-open is-local file-id page-id file-name]}]
|
||||
(let [router (mf/deref refs/router)
|
||||
team-id (mf/use-ctx ctx/current-team-id)
|
||||
url (rt/resolve router :workspace
|
||||
{:project-id project-id
|
||||
:file-id file-id}
|
||||
{:page-id page-id})
|
||||
{:team-id team-id
|
||||
:file-id file-id
|
||||
:page-id page-id})
|
||||
toggle-open
|
||||
(mf/use-fn
|
||||
(mf/deps file-id open?)
|
||||
(mf/deps file-id is-open)
|
||||
(fn []
|
||||
(st/emit! (dw/set-assets-section-open file-id :library (not open?)))))
|
||||
(st/emit! (dw/set-assets-section-open file-id :library (not is-open)))))
|
||||
|
||||
on-click
|
||||
(mf/use-fn
|
||||
(fn [ev]
|
||||
(dom/stop-propagation ev)
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "navigate-to-library-file"}))))]
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "navigate-to-library-file"}))))]
|
||||
|
||||
[:div {:class (stl/css-case :library-title true
|
||||
:open open?)}
|
||||
:open is-open)}
|
||||
[:& title-bar {:collapsable true
|
||||
:collapsed (not open?)
|
||||
:collapsed (not is-open)
|
||||
:all-clickable true
|
||||
:on-collapsed toggle-open
|
||||
:title (if local?
|
||||
:title (if is-local
|
||||
(mf/html [:div {:class (stl/css :special-title)}
|
||||
(tr "workspace.assets.local-library")])
|
||||
;; Do we need to add shared info here?
|
||||
|
||||
(mf/html [:div {:class (stl/css :special-title)}
|
||||
file-name]))}
|
||||
(when-not local?
|
||||
(when-not is-local
|
||||
[:span {:title (tr "workspace.assets.open-library")}
|
||||
[:a {:class (stl/css :file-link)
|
||||
:href (str "#" url)
|
||||
|
@ -138,7 +138,7 @@
|
|||
|
||||
selected-lens (mf/with-memo [file-id]
|
||||
(-> (l/key file-id)
|
||||
(l/derived lens:selected)))
|
||||
(l/derived ref:selected)))
|
||||
|
||||
selected (mf/deref selected-lens)
|
||||
|
||||
|
@ -329,17 +329,15 @@
|
|||
(some #(> 60 (count %)) [filtered-components filtered-colors filtered-media filtered-typographies]))))
|
||||
|
||||
(mf/defc file-library
|
||||
{::mf/wrap-props false}
|
||||
{::mf/props :obj}
|
||||
[{:keys [file local? default-open? filters]}]
|
||||
(let [file-id (:id file)
|
||||
file-name (:name file)
|
||||
shared? (:is-shared file)
|
||||
project-id (:project-id file)
|
||||
page-id (dm/get-in file [:data :pages 0])
|
||||
|
||||
open-status-ref (mf/with-memo [file-id]
|
||||
(-> (l/key file-id)
|
||||
(l/derived lens:open-status)))
|
||||
(l/derived ref:open-status)))
|
||||
open-status (mf/deref open-status-ref)
|
||||
force-open-lib? (force-lib-open? file-id filters)
|
||||
|
||||
|
@ -356,14 +354,12 @@
|
|||
[:div {:class (stl/css :tool-window)
|
||||
:on-context-menu dom/prevent-default
|
||||
:on-click unselect-all}
|
||||
[:& file-library-title
|
||||
{:project-id project-id
|
||||
:file-id file-id
|
||||
[:> file-library-title*
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:file-name file-name
|
||||
:open? open?
|
||||
:local? local?
|
||||
:shared? shared?}]
|
||||
:is-open open?
|
||||
:is-local local?}]
|
||||
(when ^boolean open?
|
||||
[:& file-library-content
|
||||
{:file file
|
||||
|
|
|
@ -277,7 +277,6 @@
|
|||
(assoc file :data data))))]
|
||||
(l/derived get-libraries st/state)))
|
||||
|
||||
|
||||
(defn- find-common-path
|
||||
([components]
|
||||
(let [paths (map (comp cfh/split-path :path) components)]
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.text :as txt]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.fonts :as fts]
|
||||
[app.main.data.shortcuts :as dsc]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.features :as features]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -564,7 +564,7 @@
|
|||
(mf/deps file-id)
|
||||
(fn []
|
||||
(when file-id
|
||||
(st/emit! (dw/navigate-to-library file-id)))))
|
||||
(st/emit! (dcm/go-to-workspace :file-id file-id)))))
|
||||
|
||||
on-key-down
|
||||
(mf/use-fn
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -34,7 +35,7 @@
|
|||
(let [input-ref (mf/use-ref)
|
||||
id (:id page)
|
||||
delete-fn (mf/use-fn (mf/deps id) #(st/emit! (dw/delete-page id)))
|
||||
navigate-fn (mf/use-fn (mf/deps id) #(st/emit! :interrupt (dw/go-to-page id)))
|
||||
navigate-fn (mf/use-fn (mf/deps id) #(st/emit! :interrupt (dcm/go-to-workspace :page-id id)))
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
||||
on-delete
|
||||
|
|
|
@ -226,11 +226,11 @@
|
|||
|
||||
(mf/defc versions-toolbox
|
||||
[]
|
||||
(let [users (mf/deref refs/users)
|
||||
profile (mf/deref refs/profile)
|
||||
project-id (mf/deref refs/current-project-id)
|
||||
file-id (mf/deref refs/current-file-id)
|
||||
expanded (mf/use-state #{})
|
||||
(let [profiles (mf/deref refs/profiles)
|
||||
profile (mf/deref refs/profile)
|
||||
|
||||
expanded (mf/use-state #{})
|
||||
|
||||
|
||||
{:keys [status data editing]}
|
||||
(mf/deref versions)
|
||||
|
@ -242,7 +242,6 @@
|
|||
(fn []
|
||||
(into #{} (keep (fn [{:keys [created-by profile-id]}]
|
||||
(when (= "user" created-by) profile-id))) data)))
|
||||
|
||||
data
|
||||
(mf/use-memo
|
||||
(mf/deps @versions)
|
||||
|
@ -257,7 +256,7 @@
|
|||
handle-create-version
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (dwv/create-version file-id))))
|
||||
(st/emit! (dwv/create-version))))
|
||||
|
||||
handle-toggle-expand
|
||||
(mf/use-fn
|
||||
|
@ -271,14 +270,12 @@
|
|||
|
||||
handle-rename-version
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [id label]
|
||||
(st/emit! (dwv/rename-version file-id id label))))
|
||||
(st/emit! (dwv/rename-version id label))))
|
||||
|
||||
|
||||
handle-restore-version
|
||||
(mf/use-fn
|
||||
(mf/deps project-id file-id)
|
||||
(fn [origin id]
|
||||
(st/emit!
|
||||
(ntf/dialog
|
||||
|
@ -289,7 +286,7 @@
|
|||
:callback #(st/emit! (ntf/hide))}
|
||||
{:label (tr "labels.restore")
|
||||
:type :primary
|
||||
:callback #(st/emit! (dwv/restore-version project-id file-id id origin))}]
|
||||
:callback #(st/emit! (dwv/restore-version id origin))}]
|
||||
:tag :restore-dialog))))
|
||||
|
||||
handle-restore-version-pinned
|
||||
|
@ -306,15 +303,13 @@
|
|||
|
||||
handle-delete-version
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [id]
|
||||
(st/emit! (dwv/delete-version file-id id))))
|
||||
(st/emit! (dwv/delete-version id))))
|
||||
|
||||
handle-pin-version
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [id]
|
||||
(st/emit! (dwv/pin-version file-id id))))
|
||||
(st/emit! (dwv/pin-version id))))
|
||||
|
||||
handle-change-filter
|
||||
(mf/use-fn
|
||||
|
@ -329,10 +324,8 @@
|
|||
:else
|
||||
(st/emit! (dwv/update-version-state {:filter filter})))))]
|
||||
|
||||
(mf/with-effect
|
||||
[file-id]
|
||||
(when file-id
|
||||
(st/emit! (dwv/init-version-state file-id))))
|
||||
(mf/with-effect []
|
||||
(st/emit! (dwv/init-version-state)))
|
||||
|
||||
[:div {:class (stl/css :version-toolbox)}
|
||||
[:& select
|
||||
|
@ -343,7 +336,7 @@
|
|||
(->> data-users
|
||||
(keep
|
||||
(fn [id]
|
||||
(let [{:keys [fullname]} (get users id)]
|
||||
(let [{:keys [fullname]} (get profiles id)]
|
||||
(when (not= id (:id profile))
|
||||
{:value id :label (tr "workspace.versions.filter.user" fullname)}))))))
|
||||
:on-change handle-change-filter}]
|
||||
|
@ -374,7 +367,7 @@
|
|||
[:& version-entry {:key idx-entry
|
||||
:entry entry
|
||||
:editing? (= (:id entry) editing)
|
||||
:profile (get users (:profile-id entry))
|
||||
:profile (get profiles (:profile-id entry))
|
||||
:on-rename-version handle-rename-version
|
||||
:on-restore-version handle-restore-version-pinned
|
||||
:on-delete-version handle-delete-version}]
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
pos-y (* (- vbox-y) zoom)
|
||||
|
||||
profile (mf/deref refs/profile)
|
||||
users (mf/deref refs/current-file-comments-users)
|
||||
profiles (mf/deref refs/profiles)
|
||||
local (mf/deref refs/comments-local)
|
||||
|
||||
positions-ref
|
||||
|
@ -84,7 +84,7 @@
|
|||
(when-let [thread (get threads-map id)]
|
||||
(when (seq (dcm/apply-filters local profile [thread]))
|
||||
[:& cmt/thread-comments {:thread (update-position positions thread)
|
||||
:users users
|
||||
:profiles profiles
|
||||
:viewport {:offset-x pos-x :offset-y pos-y :width (:width vport) :height (:height vport)}
|
||||
:zoom zoom}])))
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
{::mf/props :obj}
|
||||
[{:keys [page-id]}]
|
||||
(let [counter (mf/use-state 0)
|
||||
users (mf/deref refs/users)
|
||||
profiles (mf/deref refs/profiles)
|
||||
sessions (mf/deref refs/workspace-presence)
|
||||
zoom (mf/deref refs/selected-zoom)
|
||||
|
||||
|
@ -73,5 +73,5 @@
|
|||
[:& session-cursor
|
||||
{:session session
|
||||
:zoom zoom
|
||||
:profile (get users (:profile-id session))
|
||||
:profile (get profiles (:profile-id session))
|
||||
:key (dm/str (:id session))}])))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.interactions :as dwi]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -291,7 +292,7 @@
|
|||
(when (dom/left-mouse? event)
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dw/go-to-viewer params))))))
|
||||
(st/emit! (dcm/go-to-viewer params))))))
|
||||
|
||||
on-double-click
|
||||
(mf/use-fn
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as ch]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.bool :as dwb]
|
||||
[app.main.data.workspace.colors :as dwc]
|
||||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.media :as dwm]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.events :as events]
|
||||
[app.plugins.file :as file]
|
||||
|
@ -409,7 +411,7 @@
|
|||
(let [params {:page-id (:current-page-id @st/state)
|
||||
:file-id (:current-file-id @st/state)
|
||||
:section "interactions"}]
|
||||
(st/emit! (dw/go-to-viewer params))))
|
||||
(st/emit! (dcm/go-to-viewer params))))
|
||||
|
||||
:createPage
|
||||
(fn []
|
||||
|
@ -420,7 +422,7 @@
|
|||
:openPage
|
||||
(fn [page]
|
||||
(let [id (obj/get page "$id")]
|
||||
(st/emit! (dw/go-to-page id))))
|
||||
(st/emit! (dcm/go-to-workspace :page-id id ::rt/new-window true))))
|
||||
|
||||
:alignHorizontal
|
||||
(fn [shapes direction]
|
||||
|
|
|
@ -70,14 +70,15 @@
|
|||
|
||||
:restore
|
||||
(fn []
|
||||
(cond
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :restore "Plugin doesn't have 'content:write' permission")
|
||||
(js/Promise.
|
||||
(fn [resolve reject]
|
||||
(cond
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/reject-not-valid reject :restore "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [project-id (:current-project-id @st/state)
|
||||
version-id (get @data :id)]
|
||||
(st/emit! (dwv/restore-version project-id file-id version-id :plugin)))))
|
||||
:else
|
||||
(let [version-id (get @data :id)]
|
||||
(st/emit! (dwv/restore-version-from-plugin file-id version-id resolve reject)))))))
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
|
@ -90,7 +91,8 @@
|
|||
:else
|
||||
(let [version-id (:id @data)]
|
||||
(->> (rp/cmd! :delete-file-snapshot {:id version-id})
|
||||
(rx/subs! #(resolve) reject)))))))
|
||||
(rx/map (constantly nil))
|
||||
(rx/subs! resolve reject)))))))
|
||||
|
||||
:pin
|
||||
(fn []
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.comments :as dc]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.guides :as dwgu]
|
||||
[app.main.data.workspace.interactions :as dwi]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as-alias rt]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.comments :as pc]
|
||||
[app.plugins.format :as format]
|
||||
|
@ -266,7 +268,7 @@
|
|||
(u/display-not-valid :openPage "Plugin doesn't have 'content:read' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/go-to-page id))))
|
||||
(st/emit! (dcm/go-to-workspace :page-id id ::rt/new-window true))))
|
||||
|
||||
:createFlow
|
||||
(fn [name frame]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[app.util.webapi :as wapi]
|
||||
[cuerdas.core :as str]
|
||||
[goog.dom :as dom]
|
||||
[potok.v2.core :as ptk]
|
||||
[promesa.core :as p])
|
||||
(:import goog.events.BrowserEvent))
|
||||
|
||||
|
@ -853,3 +854,10 @@
|
|||
measures (.measureText context-2d text)]
|
||||
{:descent (.-actualBoundingBoxDescent measures)
|
||||
:ascent (.-actualBoundingBoxAscent measures)}))
|
||||
|
||||
(defmethod ptk/resolve ::focus-element
|
||||
[_ {:keys [name]}]
|
||||
(ptk/reify ::focus-element
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(focus! (get-element name)))))
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as dwc]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard.shortcuts]
|
||||
[app.main.data.preview :as dp]
|
||||
[app.main.data.viewer.shortcuts]
|
||||
|
@ -232,7 +233,7 @@
|
|||
(defn ^:export select-by-object-id
|
||||
[object-id]
|
||||
(let [[_ page-id shape-id _] (str/split object-id #"/")]
|
||||
(st/emit! (dw/go-to-page (uuid/uuid page-id)))
|
||||
(st/emit! (dcm/go-to-workspace :page-id (uuid/uuid page-id)))
|
||||
(st/emit! (dws/select-shape (uuid/uuid shape-id)))))
|
||||
|
||||
(defn ^:export select-by-id
|
||||
|
|
Loading…
Add table
Reference in a new issue