mirror of
https://github.com/penpot/penpot.git
synced 2025-06-01 18:41:38 +02:00
Merge pull request #2030 from penpot/eva-palba-share-link
Eva palba share link
This commit is contained in:
commit
cf2de3cfac
40 changed files with 701 additions and 647 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
- Allow for nested and rotated boards inside other boards and groups [Taiga #2874](https://tree.taiga.io/project/penpot/us/2874?milestone=319982)
|
||||
- View mode improvements to enable access and use in different conditions [Taiga #3023](https://tree.taiga.io/project/penpot/us/3023)
|
||||
- Improved share link options. Now you can allow non-team members to comment and/or inspect [Taiga #3056] (https://tree.taiga.io/project/penpot/us/3056)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
### :arrow_up: Deps updates
|
||||
|
|
|
@ -228,10 +228,13 @@
|
|||
:fn (mg/resource "app/migrations/sql/0072-mod-file-object-thumbnail-table.sql")}
|
||||
|
||||
{:name "0073-mod-file-media-object-constraints"
|
||||
:fn (mg/resource "app/migrations/sql/0073-mod-file-media-object-constraints.sql")}
|
||||
:fn (mg/resource "app/migrations/sql/0073-mod-file-media-object-constraints.sql")}
|
||||
|
||||
{:name "0074-mod-file-library-rel-constraints"
|
||||
:fn (mg/resource "app/migrations/sql/0074-mod-file-library-rel-constraints.sql")}
|
||||
|
||||
{:name "0075-mod-share-link-table"
|
||||
:fn (mg/resource "app/migrations/sql/0075-mod-share-link-table.sql")}
|
||||
])
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE share_link
|
||||
ADD COLUMN who_comment text NOT NULL DEFAULT('team'),
|
||||
ADD COLUMN who_inspect text NOT NULL DEFAULT('team'),
|
||||
DROP COLUMN flags;
|
|
@ -26,19 +26,21 @@
|
|||
|
||||
(s/def ::page-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::position ::gpt/point)
|
||||
(s/def ::content ::us/string)
|
||||
|
||||
(s/def ::create-comment-thread
|
||||
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id]))
|
||||
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::create-comment-thread
|
||||
{::retry/max-retries 3
|
||||
::retry/matches retry/conflict-db-insert?}
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id share-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(files/check-read-permissions! conn profile-id file-id)
|
||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||
(create-comment-thread conn params)))
|
||||
|
||||
(defn- retrieve-next-seqn
|
||||
|
@ -92,18 +94,20 @@
|
|||
;; --- Mutation: Update Comment Thread Status
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
|
||||
(s/def ::update-comment-thread-status
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
(s/keys :req-un [::profile-id ::id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::update-comment-thread-status
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id share-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [cthr (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||
(when-not cthr
|
||||
(ex/raise :type :not-found))
|
||||
|
||||
(files/check-read-permissions! conn profile-id (:file-id cthr))
|
||||
(files/check-comment-permissions! conn profile-id (:file-id cthr) share-id)
|
||||
(upsert-comment-thread-status! conn profile-id (:id cthr)))))
|
||||
|
||||
(def sql:upsert-comment-thread-status
|
||||
|
@ -122,16 +126,17 @@
|
|||
|
||||
(s/def ::is-resolved ::us/boolean)
|
||||
(s/def ::update-comment-thread
|
||||
(s/keys :req-un [::profile-id ::id ::is-resolved]))
|
||||
(s/keys :req-un [::profile-id ::id ::is-resolved]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::update-comment-thread
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id is-resolved] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id is-resolved share-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||
(when-not thread
|
||||
(ex/raise :type :not-found))
|
||||
|
||||
(files/check-read-permissions! conn profile-id (:file-id thread))
|
||||
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||
|
||||
(db/update! conn :comment-thread
|
||||
{:is-resolved is-resolved}
|
||||
|
@ -142,10 +147,11 @@
|
|||
;; --- Mutation: Add Comment
|
||||
|
||||
(s/def ::add-comment
|
||||
(s/keys :req-un [::profile-id ::thread-id ::content]))
|
||||
(s/keys :req-un [::profile-id ::thread-id ::content]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::add-comment
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id thread-id content] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id thread-id content share-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [thread (-> (db/get-by-id conn :comment-thread thread-id {:for-update true})
|
||||
(comments/decode-row))
|
||||
|
@ -155,7 +161,7 @@
|
|||
(when-not thread (ex/raise :type :not-found))
|
||||
|
||||
;; Permission Checks
|
||||
(files/check-read-permissions! conn profile-id (:file-id thread))
|
||||
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||
|
||||
;; Update the page-name cachedattribute on comment thread table.
|
||||
(when (not= pname (:page-name thread))
|
||||
|
@ -199,10 +205,11 @@
|
|||
;; --- Mutation: Update Comment
|
||||
|
||||
(s/def ::update-comment
|
||||
(s/keys :req-un [::profile-id ::id ::content]))
|
||||
(s/keys :req-un [::profile-id ::id ::content]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::update-comment
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id content] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id content share-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [comment (db/get-by-id conn :comment id {:for-update true})
|
||||
_ (when-not comment (ex/raise :type :not-found))
|
||||
|
@ -210,7 +217,7 @@
|
|||
_ (when-not thread (ex/raise :type :not-found))
|
||||
pname (retrieve-page-name conn thread)]
|
||||
|
||||
(files/check-read-permissions! conn profile-id (:file-id thread))
|
||||
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||
|
||||
;; Don't allow edit comments to not owners
|
||||
(when-not (= (:owner-id thread) profile-id)
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
(s/def ::id ::us/uuid)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::flags (s/every ::us/string :kind set?))
|
||||
(s/def ::who-comment ::us/string)
|
||||
(s/def ::who-inspect ::us/string)
|
||||
(s/def ::pages (s/every ::us/uuid :kind set?))
|
||||
|
||||
;; --- Mutation: Create Share Link
|
||||
|
@ -27,14 +28,13 @@
|
|||
(declare create-share-link)
|
||||
|
||||
(s/def ::create-share-link
|
||||
(s/keys :req-un [::profile-id ::file-id ::flags]
|
||||
:opt-un [::pages]))
|
||||
(s/keys :req-un [::profile-id ::file-id ::who-comment ::who-inspect ::pages]))
|
||||
|
||||
(sv/defmethod ::create-share-link
|
||||
"Creates a share-link object.
|
||||
|
||||
Share links are resources that allows external users access to
|
||||
specific files with specific permissions (flags)."
|
||||
Share links are resources that allows external users access to specific
|
||||
pages of a file with specific permissions (who-comment and who-inspect)."
|
||||
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
|
@ -42,19 +42,17 @@
|
|||
(create-share-link conn params)))
|
||||
|
||||
(defn create-share-link
|
||||
[conn {:keys [profile-id file-id pages flags]}]
|
||||
[conn {:keys [profile-id file-id pages who-comment who-inspect]}]
|
||||
(let [pages (db/create-array conn "uuid" pages)
|
||||
flags (->> (map name flags)
|
||||
(db/create-array conn "text"))
|
||||
slink (db/insert! conn :share-link
|
||||
{:id (uuid/next)
|
||||
:file-id file-id
|
||||
:flags flags
|
||||
:who-comment who-comment
|
||||
:who-inspect who-inspect
|
||||
:pages pages
|
||||
:owner-id profile-id})]
|
||||
(-> slink
|
||||
(update :pages db/decode-pgarray #{})
|
||||
(update :flags db/decode-pgarray #{}))))
|
||||
(update :pages db/decode-pgarray #{}))))
|
||||
|
||||
;; --- Mutation: Delete Share Link
|
||||
|
||||
|
|
|
@ -53,6 +53,16 @@
|
|||
([perms] (:can-read perms))
|
||||
([conn & args] (check (apply qfn conn args)))))
|
||||
|
||||
(defn make-comment-predicate-fn
|
||||
"A simple factory for comment permission predicate functions."
|
||||
[qfn]
|
||||
(us/assert fn? qfn)
|
||||
(fn check
|
||||
([perms]
|
||||
(and (:is-logged perms) (= (:who-comment perms) "all")))
|
||||
([conn & args]
|
||||
(check (apply qfn conn args)))))
|
||||
|
||||
(defn make-check-fn
|
||||
"Helper that converts a predicate permission function to a check
|
||||
function (function that raises an exception)."
|
||||
|
|
|
@ -25,16 +25,16 @@
|
|||
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
|
||||
(s/def ::comment-threads
|
||||
(s/and (s/keys :req-un [::profile-id]
|
||||
:opt-un [::file-id ::team-id])
|
||||
:opt-un [::file-id ::share-id ::team-id])
|
||||
#(or (:file-id %) (:team-id %))))
|
||||
|
||||
(sv/defmethod ::comment-threads
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
|
||||
[{:keys [pool] :as cfg} params]
|
||||
(with-open [conn (db/open pool)]
|
||||
(files/check-read-permissions! conn profile-id file-id)
|
||||
(retrieve-comment-threads conn params)))
|
||||
|
||||
(def sql:comment-threads
|
||||
|
@ -60,8 +60,8 @@
|
|||
window w as (partition by c.thread_id order by c.created_at asc)")
|
||||
|
||||
(defn- retrieve-comment-threads
|
||||
[conn {:keys [profile-id file-id]}]
|
||||
(files/check-read-permissions! conn profile-id file-id)
|
||||
[conn {:keys [profile-id file-id share-id]}]
|
||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||
(->> (db/exec! conn [sql:comment-threads profile-id file-id])
|
||||
(into [] (map decode-row))))
|
||||
|
||||
|
@ -116,13 +116,15 @@
|
|||
;; --- Query: Single Comment Thread
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
(s/def ::comment-thread
|
||||
(s/keys :req-un [::profile-id ::file-id ::id]))
|
||||
(s/keys :req-un [::profile-id ::file-id ::id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::comment-thread
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id id] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id id share-id] :as params}]
|
||||
(with-open [conn (db/open pool)]
|
||||
(files/check-read-permissions! conn profile-id file-id)
|
||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||
(let [sql (str "with threads as (" sql:comment-threads ")"
|
||||
"select * from threads where id = ?")]
|
||||
(-> (db/exec-one! conn [sql profile-id file-id id])
|
||||
|
@ -133,15 +135,17 @@
|
|||
(declare retrieve-comments)
|
||||
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
(s/def ::thread-id ::us/uuid)
|
||||
(s/def ::comments
|
||||
(s/keys :req-un [::profile-id ::thread-id]))
|
||||
(s/keys :req-un [::profile-id ::thread-id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::comments
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id thread-id] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id thread-id share-id] :as params}]
|
||||
(with-open [conn (db/open pool)]
|
||||
(let [thread (db/get-by-id conn :comment-thread thread-id)]
|
||||
(files/check-read-permissions! conn profile-id (:file-id thread))
|
||||
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||
(retrieve-comments conn thread-id))))
|
||||
|
||||
(def sql:comments
|
||||
|
@ -153,3 +157,40 @@
|
|||
[conn thread-id]
|
||||
(->> (db/exec! conn [sql:comments thread-id])
|
||||
(into [] (map decode-row))))
|
||||
|
||||
;; file-comments-users
|
||||
|
||||
(declare retrieve-file-comments-users)
|
||||
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::share-id (s/nilable ::us/uuid))
|
||||
|
||||
(s/def ::file-comments-users
|
||||
(s/keys :req-un [::profile-id ::file-id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::file-comments-users
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id share-id]}]
|
||||
(with-open [conn (db/open pool)]
|
||||
(files/check-comment-permissions! conn profile-id file-id share-id)
|
||||
(retrieve-file-comments-users conn file-id profile-id)))
|
||||
|
||||
(def sql:file-comment-users
|
||||
"select p.id,
|
||||
p.email,
|
||||
p.fullname as name,
|
||||
p.fullname as fullname,
|
||||
p.photo_id,
|
||||
p.is_active
|
||||
from profile p
|
||||
where p.id in
|
||||
(select owner_id from comment
|
||||
where thread_id in
|
||||
(select id from comment_thread
|
||||
where file_id=?))
|
||||
or p.id=?
|
||||
") ;; all the users that had comment the file, plus the current user
|
||||
|
||||
(defn retrieve-file-comments-users
|
||||
[conn file-id profile-id]
|
||||
(db/exec! conn [sql:file-comment-users file-id profile-id]))
|
||||
|
|
|
@ -98,7 +98,9 @@
|
|||
(some? perms) perms
|
||||
(some? ldata) {:type :share-link
|
||||
:can-read true
|
||||
:flags (:flags ldata)}))))
|
||||
:is-logged (some? profile-id)
|
||||
:who-comment (:who-comment ldata)
|
||||
:who-inspect (:who-inspect ldata)}))))
|
||||
|
||||
(def has-edit-permissions?
|
||||
(perms/make-edition-predicate-fn get-permissions))
|
||||
|
@ -106,12 +108,26 @@
|
|||
(def has-read-permissions?
|
||||
(perms/make-read-predicate-fn get-permissions))
|
||||
|
||||
(def has-comment-permissions?
|
||||
(perms/make-comment-predicate-fn get-permissions))
|
||||
|
||||
(def check-edition-permissions!
|
||||
(perms/make-check-fn has-edit-permissions?))
|
||||
|
||||
(def check-read-permissions!
|
||||
(perms/make-check-fn has-read-permissions?))
|
||||
|
||||
;; A user has comment permissions if she has read permissions, or comment permissions
|
||||
(defn check-comment-permissions!
|
||||
[conn profile-id file-id share-id]
|
||||
(let [can-read (has-read-permissions? conn profile-id file-id)
|
||||
can-comment (has-comment-permissions? conn profile-id file-id share-id)
|
||||
]
|
||||
(when-not (or can-read can-comment)
|
||||
(ex/raise :type :not-found
|
||||
:code :object-not-found
|
||||
:hint "not found"))))
|
||||
|
||||
;; --- Query: Files search
|
||||
|
||||
;; TODO: this query need to a good refactor
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
(defn decode-share-link-row
|
||||
[row]
|
||||
(-> row
|
||||
(update :flags db/decode-pgarray #{})
|
||||
(update :pages db/decode-pgarray #{})))
|
||||
|
||||
(defn retrieve-share-link
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
[app.common.exceptions :as ex]
|
||||
[app.common.spec :as us]
|
||||
[app.db :as db]
|
||||
[app.rpc.queries.comments :as comments]
|
||||
[app.rpc.queries.files :as files]
|
||||
[app.rpc.queries.share-link :as slnk]
|
||||
[app.rpc.queries.teams :as teams]
|
||||
[app.rpc.queries.share-link :as slnk]
|
||||
[app.util.services :as sv]
|
||||
[clojure.spec.alpha :as s]
|
||||
[promesa.core :as p]))
|
||||
|
@ -23,11 +23,11 @@
|
|||
(db/get-by-id pool :project id {:columns [:id :name :team-id]}))
|
||||
|
||||
(defn- retrieve-bundle
|
||||
[{:keys [pool] :as cfg} file-id]
|
||||
[{:keys [pool] :as cfg} file-id profile-id]
|
||||
(p/let [file (files/retrieve-file cfg file-id)
|
||||
project (retrieve-project pool (:project-id file))
|
||||
libs (files/retrieve-file-libraries cfg false file-id)
|
||||
users (teams/retrieve-users pool (:team-id project))
|
||||
users (comments/retrieve-file-comments-users pool file-id profile-id)
|
||||
|
||||
links (->> (db/query pool :share-link {:file-id file-id})
|
||||
(mapv slnk/decode-share-link-row))
|
||||
|
@ -54,7 +54,7 @@
|
|||
(p/let [slink (slnk/retrieve-share-link pool file-id share-id)
|
||||
perms (files/get-permissions pool profile-id file-id share-id)
|
||||
thumbs (files/retrieve-object-thumbnails cfg file-id)
|
||||
bundle (p/-> (retrieve-bundle cfg file-id)
|
||||
bundle (p/-> (retrieve-bundle cfg file-id profile-id)
|
||||
(assoc :permissions perms)
|
||||
(assoc-in [:file :thumbnails] thumbs))]
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:pages #{(get-in file [:data :pages 0])}
|
||||
:flags #{}}
|
||||
:who-comment "team"
|
||||
:who-inspect "all"}
|
||||
out (th/mutation! data)]
|
||||
|
||||
;; (th/print-result! out)
|
||||
|
|
|
@ -1,139 +1,240 @@
|
|||
.share-link-dialog {
|
||||
width: 475px;
|
||||
background-color: $color-white;
|
||||
.share-modal {
|
||||
display: block;
|
||||
top: 50px;
|
||||
left: calc(100vw - 500px);
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: unset;
|
||||
padding: 16px 26px;
|
||||
.share-link-dialog {
|
||||
width: 480px;
|
||||
background-color: $color-white;
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary,
|
||||
.btn-warning {
|
||||
width: 126px;
|
||||
margin-bottom: 0px;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: unset;
|
||||
|
||||
.description {
|
||||
font-size: $fs14;
|
||||
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.actions {
|
||||
.modal-content {
|
||||
padding: 16px 32px;
|
||||
&:first-child {
|
||||
border-top: 0px;
|
||||
padding: 0;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
padding: 26px;
|
||||
|
||||
&:first-child {
|
||||
border-top: 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
h2 {
|
||||
font-size: $fs18;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
.modal-close-button {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.share-link-section {
|
||||
margin-top: 12px;
|
||||
label {
|
||||
font-size: $fs12;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
.hint {
|
||||
padding-top: 10px;
|
||||
font-size: $fs14;
|
||||
color: $color-gray-40;
|
||||
}
|
||||
|
||||
.help-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.view-mode,
|
||||
.access-mode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
color: $color-black;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
margin-left: 32px;
|
||||
h2 {
|
||||
font-size: $fs18;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
.modal-close-button {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
|
||||
> .input-checkbox,
|
||||
> .input-radio {
|
||||
.share-link-section {
|
||||
.custom-input {
|
||||
display: flex;
|
||||
user-select: none;
|
||||
|
||||
/* input { */
|
||||
/* appearance: checkbox; */
|
||||
/* } */
|
||||
|
||||
label {
|
||||
flex-direction: row;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid $color-gray-20;
|
||||
input {
|
||||
padding: 0 0 0 15px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.hint-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.hint {
|
||||
font-size: $fs12;
|
||||
color: $color-gray-40;
|
||||
}
|
||||
.confirm-dialog {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $color-black;
|
||||
flex-direction: column;
|
||||
background-color: unset;
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
}
|
||||
.description {
|
||||
font-size: $fs12;
|
||||
margin-bottom: 16px;
|
||||
color: $color-black;
|
||||
}
|
||||
.btn-primary,
|
||||
.btn-secondary,
|
||||
.btn-warning {
|
||||
width: 126px;
|
||||
margin-bottom: 0px;
|
||||
|
||||
.hint {
|
||||
margin-left: 5px;
|
||||
&:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: $fs12;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
.help-icon {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-color: $color-gray-10;
|
||||
border-left: 1px solid $color-gray-20;
|
||||
svg {
|
||||
fill: $color-gray-30;
|
||||
}
|
||||
&:hover {
|
||||
background-color: $color-primary;
|
||||
svg {
|
||||
fill: $color-gray-60;
|
||||
}
|
||||
}
|
||||
}
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.ops-section {
|
||||
.manage-permissions {
|
||||
display: flex;
|
||||
color: $color-primary-dark;
|
||||
font-size: $fs12;
|
||||
cursor: pointer;
|
||||
.icon {
|
||||
svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
fill: $color-primary-dark;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.view-mode {
|
||||
min-height: 34px;
|
||||
.subtitle {
|
||||
height: 32px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.count-pages {
|
||||
font-size: $fs12;
|
||||
color: $color-gray-30;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
label {
|
||||
color: $color-gray-30;
|
||||
.current-tag {
|
||||
font-size: $fs12;
|
||||
color: $color-gray-30;
|
||||
}
|
||||
label {
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
.access-mode,
|
||||
.inspect-mode {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
.items {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.view-mode,
|
||||
.access-mode,
|
||||
.inspect-mode {
|
||||
margin: 8px 0;
|
||||
.subtitle {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
color: $color-black;
|
||||
font-size: $fs16;
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.items {
|
||||
.input-select {
|
||||
background-image: url("/images/icons/arrow-down.svg");
|
||||
margin: 0;
|
||||
padding-right: 28px;
|
||||
border: 1px solid $color-gray-10;
|
||||
max-width: 227px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
> .input-radio {
|
||||
display: flex;
|
||||
user-select: none;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $color-black;
|
||||
max-width: 115px;
|
||||
|
||||
&::before {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
.hint {
|
||||
margin-left: 5px;
|
||||
color: $color-gray-30;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
label {
|
||||
color: $color-gray-30;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pages-selection {
|
||||
border-top: 1px solid $color-gray-10;
|
||||
border-bottom: 1px solid $color-gray-10;
|
||||
padding-left: 20px;
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
user-select: none;
|
||||
|
||||
label {
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pages-selection {
|
||||
padding-left: 20px;
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
user-select: none;
|
||||
|
||||
label {
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-input {
|
||||
input {
|
||||
padding: 0 40px 0 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,20 +75,23 @@
|
|||
|
||||
(ptk/reify ::create-comment-thread
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :create-comment-thread params)
|
||||
(rx/mapcat #(rp/query :comment-thread {:file-id (:file-id %) :id (:id %)}))
|
||||
(rx/map #(partial created %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)
|
||||
params (assoc params :share-id share-id)]
|
||||
(->> (rp/mutation :create-comment-thread params)
|
||||
(rx/mapcat #(rp/query :comment-thread {:file-id (:file-id %) :id (:id %) :share-id share-id}))
|
||||
(rx/map #(partial created %))
|
||||
(rx/catch #(rx/throw {:type :comment-error}))))))))
|
||||
|
||||
(defn update-comment-thread-status
|
||||
[{:keys [id] :as thread}]
|
||||
(us/assert ::comment-thread thread)
|
||||
(ptk/reify ::update-comment-thread-status
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [done #(d/update-in-when % [:comment-threads id] assoc :count-unread-comments 0)]
|
||||
(->> (rp/mutation :update-comment-thread-status {:id id})
|
||||
(watch [_ state _]
|
||||
(let [done #(d/update-in-when % [:comment-threads id] assoc :count-unread-comments 0)
|
||||
share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/mutation :update-comment-thread-status {:id id :share-id share-id})
|
||||
(rx/map (constantly done))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
|
||||
|
@ -105,10 +108,11 @@
|
|||
(d/update-in-when state [:comment-threads id] assoc :is-resolved is-resolved))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :update-comment-thread {:id id :is-resolved is-resolved})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore)))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/mutation :update-comment-thread {:id id :is-resolved is-resolved :share-id share-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
|
||||
(defn add-comment
|
||||
|
@ -119,12 +123,13 @@
|
|||
(update-in state [:comments (:id thread)] assoc (:id comment) comment))]
|
||||
(ptk/reify ::create-comment
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/concat
|
||||
(->> (rp/mutation :add-comment {:thread-id (:id thread) :content content})
|
||||
(rx/map #(partial created %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))
|
||||
(rx/of (refresh-comment-thread thread)))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(rx/concat
|
||||
(->> (rp/mutation :add-comment {:thread-id (:id thread) :content content :share-id share-id})
|
||||
(rx/map #(partial created %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))
|
||||
(rx/of (refresh-comment-thread thread))))))))
|
||||
|
||||
(defn update-comment
|
||||
[{:keys [id content thread-id] :as comment}]
|
||||
|
@ -135,10 +140,11 @@
|
|||
(d/update-in-when state [:comments thread-id id] assoc :content content))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :update-comment {:id id :content content})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore)))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/mutation :update-comment {:id id :content content :share-id share-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-comment-thread
|
||||
[{:keys [id] :as thread}]
|
||||
|
@ -151,10 +157,11 @@
|
|||
(update :comment-threads dissoc id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :delete-comment-thread {:id id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore)))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/mutation :delete-comment-thread {:id id :share-id share-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-comment
|
||||
[{:keys [id thread-id] :as comment}]
|
||||
|
@ -165,10 +172,11 @@
|
|||
(d/update-in-when state [:comments thread-id] dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :delete-comment {:id id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore)))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/mutation :delete-comment {:id id :share-id share-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn refresh-comment-thread
|
||||
[{:keys [id file-id] :as thread}]
|
||||
|
@ -177,10 +185,11 @@
|
|||
(assoc-in state [:comment-threads id] thread))]
|
||||
(ptk/reify ::refresh-comment-thread
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/query :comment-thread {:file-id file-id :id id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/query :comment-thread {:file-id file-id :id id :share-id share-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error}))))))))
|
||||
|
||||
(defn retrieve-comment-threads
|
||||
[file-id]
|
||||
|
@ -189,10 +198,11 @@
|
|||
(assoc state :comment-threads (d/index-by :id data)))]
|
||||
(ptk/reify ::retrieve-comment-threads
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/query :comment-threads {:file-id file-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/query :comment-threads {:file-id file-id :share-id share-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error}))))))))
|
||||
|
||||
(defn retrieve-comments
|
||||
[thread-id]
|
||||
|
@ -201,10 +211,11 @@
|
|||
(update state :comments assoc thread-id (d/index-by :id comments)))]
|
||||
(ptk/reify ::retrieve-comments
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/query :comments {:thread-id thread-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/query :comments {:thread-id thread-id :share-id share-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch #(rx/throw {:type :comment-error}))))))))
|
||||
|
||||
(defn retrieve-unread-comment-threads
|
||||
"A event used mainly in dashboard for retrieve all unread threads of a team."
|
||||
|
|
|
@ -436,7 +436,6 @@
|
|||
(rx/map (constantly (fetch-profile)))
|
||||
(rx/catch on-error))))))
|
||||
|
||||
|
||||
(defn fetch-users
|
||||
[{:keys [team-id] :as params}]
|
||||
(us/assert ::us/uuid team-id)
|
||||
|
@ -450,6 +449,20 @@
|
|||
(->> (rp/query :team-users {:team-id team-id})
|
||||
(rx/map #(partial fetched %)))))))
|
||||
|
||||
(defn fetch-file-comments-users
|
||||
[{:keys [team-id] :as params}]
|
||||
(us/assert ::us/uuid team-id)
|
||||
(letfn [(fetched [users state]
|
||||
(->> users
|
||||
(d/index-by :id)
|
||||
(assoc state :file-comments-users)))]
|
||||
(ptk/reify ::fetch-team-users
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rp/query :file-comments-users {:team-id team-id :share-id share-id})
|
||||
(rx/map #(partial fetched %))))))))
|
||||
|
||||
;; --- EVENT: request-account-deletion
|
||||
|
||||
(defn request-account-deletion
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
:selected #{}
|
||||
:collapsed #{}
|
||||
:overlays []
|
||||
:hover nil})
|
||||
:hover nil
|
||||
:share-id ""
|
||||
:file-comments-users []})
|
||||
|
||||
(declare fetch-comment-threads)
|
||||
(declare fetch-bundle)
|
||||
|
@ -50,7 +52,7 @@
|
|||
:opt-un [::share-id ::page-id]))
|
||||
|
||||
(defn initialize
|
||||
[{:keys [file-id] :as params}]
|
||||
[{:keys [file-id share-id] :as params}]
|
||||
(us/assert ::initialize-params params)
|
||||
(ptk/reify ::initialize
|
||||
ptk/UpdateEvent
|
||||
|
@ -61,7 +63,8 @@
|
|||
(fn [lstate]
|
||||
(if (nil? lstate)
|
||||
default-local-state
|
||||
lstate)))))
|
||||
lstate)))
|
||||
(assoc-in [:viewer-local :share-id] share-id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
|
@ -138,7 +141,7 @@
|
|||
(rx/of (go-to-frame-auto))))))))
|
||||
|
||||
(defn fetch-comment-threads
|
||||
[{:keys [file-id page-id] :as params}]
|
||||
[{:keys [file-id page-id share-id] :as params}]
|
||||
(letfn [(fetched [data state]
|
||||
(->> data
|
||||
(filter #(= page-id (:page-id %)))
|
||||
|
@ -153,7 +156,7 @@
|
|||
(ptk/reify ::fetch-comment-threads
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/query :comment-threads {:file-id file-id})
|
||||
(->> (rp/query :comment-threads {:file-id file-id :share-id share-id})
|
||||
(rx/map #(partial fetched %))
|
||||
(rx/catch on-error))))))
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
(unchecked-set ug/global "name" name)))))
|
||||
|
||||
(defn- file-initialized
|
||||
[{:keys [file users project libraries] :as bundle}]
|
||||
[{:keys [file users project libraries file-comments-users] :as bundle}]
|
||||
(ptk/reify ::file-initialized
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -156,7 +156,8 @@
|
|||
;; the version number
|
||||
#_(assoc :version 17)
|
||||
#_(app.common.pages.migrations/migrate-data 19))
|
||||
:workspace-libraries (d/index-by :id libraries)))
|
||||
:workspace-libraries (d/index-by :id libraries)
|
||||
:current-file-comments-users (d/index-by :id file-comments-users)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
|
|
|
@ -258,20 +258,23 @@
|
|||
[project-id file-id]
|
||||
(ptk/reify ::fetch-bundle
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rx/zip (rp/query :file-raw {:id file-id})
|
||||
(rp/query :team-users {:file-id file-id})
|
||||
(rp/query :project {:id project-id})
|
||||
(rp/query :file-libraries {:file-id file-id}))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [[file-raw users project libraries]]
|
||||
{:file-raw file-raw
|
||||
:users users
|
||||
:project project
|
||||
:libraries libraries}))
|
||||
(rx/mapcat (fn [{:keys [project] :as bundle}]
|
||||
(rx/of (ptk/data-event ::bundle-fetched bundle)
|
||||
(df/load-team-fonts (:team-id project)))))))))
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(->> (rx/zip (rp/query :file-raw {:id file-id})
|
||||
(rp/query :team-users {:file-id file-id})
|
||||
(rp/query :project {:id project-id})
|
||||
(rp/query :file-libraries {:file-id file-id})
|
||||
(rp/query :file-comments-users {:file-id file-id :share-id share-id}))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [[file-raw users project libraries file-comments-users]]
|
||||
{:file-raw file-raw
|
||||
:users users
|
||||
:project project
|
||||
:libraries libraries
|
||||
:file-comments-users file-comments-users}))
|
||||
(rx/mapcat (fn [{:keys [project] :as bundle}]
|
||||
(rx/of (ptk/data-event ::bundle-fetched bundle)
|
||||
(df/load-team-fonts (:team-id project))))))))))
|
||||
|
||||
|
||||
;; --- Helpers
|
||||
|
|
|
@ -387,6 +387,9 @@
|
|||
(def users
|
||||
(l/derived :users st/state))
|
||||
|
||||
(def current-file-comments-users
|
||||
(l/derived :current-file-comments-users st/state))
|
||||
|
||||
(def viewer-fullscreen?
|
||||
(l/derived (fn [state]
|
||||
(dm/get-in state [:viewer-local :fullscreen?]))
|
||||
|
|
|
@ -345,7 +345,6 @@
|
|||
(mf/defc comment-thread
|
||||
[{:keys [item users on-click] :as props}]
|
||||
(let [owner (get users (:owner-id item))
|
||||
|
||||
on-click*
|
||||
(mf/use-callback
|
||||
(mf/deps item)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
show-dropdown (mf/use-fn #(reset! show-dropdown? true))
|
||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||
threads-map (mf/deref refs/comment-threads)
|
||||
users (mf/deref refs/users)
|
||||
users (mf/deref refs/current-file-comments-users)
|
||||
|
||||
tgroups (->> (vals threads-map)
|
||||
(sort-by :modified-at)
|
||||
|
|
|
@ -24,53 +24,66 @@
|
|||
(log/set-level! :warn)
|
||||
|
||||
(defn prepare-params
|
||||
[{:keys [sections pages pages-mode]}]
|
||||
{:pages pages
|
||||
:flags (-> #{}
|
||||
(into (map #(str "section-" %)) sections)
|
||||
(into (map #(str "pages-" %)) [pages-mode]))})
|
||||
[{:keys [pages who-comment who-inspect]}]
|
||||
|
||||
{:pages pages
|
||||
:who-comment who-comment
|
||||
:who-inspect who-inspect})
|
||||
|
||||
(mf/defc share-link-dialog
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :share-link}
|
||||
[{:keys [file page]}]
|
||||
(let [slinks (mf/deref refs/share-links)
|
||||
router (mf/deref refs/router)
|
||||
route (mf/deref refs/route)
|
||||
(let [current-page page
|
||||
slinks (mf/deref refs/share-links)
|
||||
router (mf/deref refs/router)
|
||||
route (mf/deref refs/route)
|
||||
|
||||
link (mf/use-state nil)
|
||||
confirm (mf/use-state false)
|
||||
link (mf/use-state nil)
|
||||
confirm (mf/use-state false)
|
||||
open-ops (mf/use-state false)
|
||||
|
||||
opts (mf/use-state
|
||||
{:pages-mode "current"
|
||||
:all-pages false
|
||||
:pages #{(:id page)}
|
||||
:who-comment "team"
|
||||
:who-inspect "team"})
|
||||
|
||||
opts (mf/use-state
|
||||
{:sections #{"viewer"}
|
||||
:pages-mode "current"
|
||||
:pages #{(:id page)}})
|
||||
|
||||
close
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (modal/hide)))
|
||||
(st/emit! (modal/hide))
|
||||
(modal/disallow-click-outside!))
|
||||
|
||||
select-pages-mode
|
||||
(fn [mode]
|
||||
toggle-all
|
||||
(fn []
|
||||
(reset! confirm false)
|
||||
(swap! opts
|
||||
(fn [state]
|
||||
(-> state
|
||||
(assoc :pages-mode mode)
|
||||
(cond-> (= mode "current") (assoc :pages #{(:id page)}))
|
||||
(cond-> (= mode "all") (assoc :pages (into #{} (get-in file [:data :pages]))))))))
|
||||
(if (= true (:all-pages state))
|
||||
(-> state
|
||||
(assoc :all-pages false)
|
||||
(assoc :pages #{(:id page)}))
|
||||
(-> state
|
||||
(assoc :all-pages true)
|
||||
(assoc :pages (into #{} (get-in file [:data :pages]))))))))
|
||||
|
||||
mark-checked-page
|
||||
(fn [event id]
|
||||
(let [target (dom/get-target event)
|
||||
checked? (.-checked ^js target)]
|
||||
(reset! confirm false)
|
||||
(swap! opts update :pages
|
||||
(fn [pages]
|
||||
(if checked?
|
||||
(conj pages id)
|
||||
(disj pages id))))))
|
||||
checked? (.-checked ^js target)
|
||||
dif-pages? (not= id (first (:pages @opts)))
|
||||
no-one-page (< 1 (count (:pages @opts)))
|
||||
should-change (or no-one-page dif-pages?)]
|
||||
(when should-change
|
||||
(reset! confirm false)
|
||||
(swap! opts update :pages
|
||||
(fn [pages]
|
||||
(if checked?
|
||||
(conj pages id)
|
||||
(disj pages id)))))))
|
||||
|
||||
create-link
|
||||
(fn [_]
|
||||
|
@ -83,7 +96,7 @@
|
|||
(wapi/write-to-clipboard @link)
|
||||
(st/emit! (dm/show {:type :info
|
||||
:content (tr "common.share-link.link-copied-success")
|
||||
:timeout 3000})))
|
||||
:timeout 1000})))
|
||||
|
||||
try-delete-link
|
||||
(fn [_]
|
||||
|
@ -94,17 +107,27 @@
|
|||
(let [params (prepare-params @opts)
|
||||
slink (d/seek #(= (:flags %) (:flags params)) slinks)]
|
||||
(reset! confirm false)
|
||||
(st/emit! (dc/delete-share-link slink)
|
||||
(dm/show {:type :info
|
||||
:content (tr "common.share-link.link-deleted-success")
|
||||
:timeout 3000}))))
|
||||
]
|
||||
(st/emit! (dc/delete-share-link slink))))
|
||||
|
||||
manage-open-ops
|
||||
(fn [_]
|
||||
(swap! open-ops not))
|
||||
|
||||
on-who-change
|
||||
(fn [type event]
|
||||
(let [target (dom/get-target event)
|
||||
value (dom/get-value target)
|
||||
value (keyword value)]
|
||||
(reset! confirm false)
|
||||
(if (= type :comment)
|
||||
(swap! opts assoc :who-comment (d/name value))
|
||||
(swap! opts assoc :who-inspect (d/name value)))))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps file slinks @opts)
|
||||
(fn []
|
||||
(let [{:keys [flags pages] :as params} (prepare-params @opts)
|
||||
slink (d/seek #(and (= (:flags %) flags) (= (:pages %) pages)) slinks)
|
||||
(let [{:keys [pages who-comment who-inspect] :as params} (prepare-params @opts)
|
||||
slink (d/seek #(and (= (:who-inspect %) who-inspect) (= (:who-comment %) who-comment) (= (:pages %) pages)) slinks)
|
||||
href (when slink
|
||||
(let [pparams (:path-params route)
|
||||
qparams (-> (:query-params route)
|
||||
|
@ -114,123 +137,123 @@
|
|||
(assoc cf/public-uri :fragment href)))]
|
||||
(reset! link (some-> href str)))))
|
||||
|
||||
[:div.modal-overlay
|
||||
[:div.modal-overlay.share-modal
|
||||
[:div.modal-container.share-link-dialog
|
||||
[:div.modal-content
|
||||
[:div.modal-content.initial
|
||||
[:div.title
|
||||
[:h2 (tr "common.share-link.title")]
|
||||
[:div.modal-close-button
|
||||
{:on-click close
|
||||
:title (tr "labels.close")}
|
||||
i/close]]
|
||||
|
||||
[:div.share-link-section
|
||||
[:label (tr "labels.link")]
|
||||
[:div.custom-input.with-icon
|
||||
[:input {:type "text"
|
||||
:value (or @link "")
|
||||
:placeholder (tr "common.share-link.placeholder")
|
||||
:read-only true}]
|
||||
(when (some? @link)
|
||||
[:div.help-icon {:title (tr "labels.copy")
|
||||
:on-click copy-link}
|
||||
i/copy])]
|
||||
|
||||
[:div.hint (tr "common.share-link.permissions-hint")]]]
|
||||
|
||||
i/close]]]
|
||||
[:div.modal-content
|
||||
(let [sections (:sections @opts)]
|
||||
[:div.access-mode
|
||||
[:div.title (tr "common.share-link.permissions-can-access")]
|
||||
[:div.items
|
||||
[:div.input-checkbox.check-primary.disabled
|
||||
[:input.check-primary.input-checkbox {:type "checkbox" :disabled true}]
|
||||
[:label (tr "labels.workspace")]]
|
||||
[:div.share-link-section
|
||||
(when (and (not @confirm) (some? @link))
|
||||
[:div.custom-input.with-icon
|
||||
[:input {:type "text"
|
||||
:value (or @link "")
|
||||
:placeholder (tr "common.share-link.placeholder")
|
||||
:read-only true}]
|
||||
[:div.help-icon {:title (tr "viewer.header.share.copy-link")
|
||||
:on-click copy-link}
|
||||
i/copy]])
|
||||
[:div.hint-wrapper
|
||||
(when (not @confirm) [:div.hint (tr "common.share-link.permissions-hint")])
|
||||
(cond
|
||||
(true? @confirm)
|
||||
[:div.confirm-dialog
|
||||
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
|
||||
[:div.actions
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:on-click #(reset! confirm false)
|
||||
:value (tr "labels.cancel")}]
|
||||
[:input.btn-warning
|
||||
{:type "button"
|
||||
:on-click delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]]]
|
||||
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:default-checked (contains? sections "viewer")}]
|
||||
[:label (tr "labels.viewer")
|
||||
[:span.hint "(" (tr "labels.default") ")"]]]
|
||||
|
||||
;; [:div.input-checkbox.check-primary
|
||||
;; [:input.check-primary.input-checkbox {:type "checkbox"}]
|
||||
;; [:label "Handoff" ]]
|
||||
]])
|
||||
|
||||
(let [mode (:pages-mode @opts)]
|
||||
[:*
|
||||
[:div.view-mode
|
||||
[:div.title (tr "common.share-link.permissions-can-view")]
|
||||
[:div.items
|
||||
[:div.input-radio.radio-primary
|
||||
[:input {:type "radio"
|
||||
:id "view-all"
|
||||
:checked (= "all" mode)
|
||||
:name "pages-mode"
|
||||
:on-change #(select-pages-mode "all")}]
|
||||
[:label {:for "view-all"} (tr "common.share-link.view-all-pages")]]
|
||||
|
||||
[:div.input-radio.radio-primary
|
||||
[:input {:type "radio"
|
||||
:id "view-current"
|
||||
:name "pages-mode"
|
||||
:checked (= "current" mode)
|
||||
:on-change #(select-pages-mode "current")}]
|
||||
[:label {:for "view-current"} (tr "common.share-link.view-current-page")]]
|
||||
|
||||
[:div.input-radio.radio-primary
|
||||
[:input {:type "radio"
|
||||
:id "view-selected"
|
||||
:name "pages-mode"
|
||||
:checked (= "selected" mode)
|
||||
:on-change #(select-pages-mode "selected")}]
|
||||
[:label {:for "view-selected"} (tr "common.share-link.view-selected-pages")]]]]
|
||||
|
||||
(when (= "selected" mode)
|
||||
(let [pages (->> (get-in file [:data :pages])
|
||||
(map #(get-in file [:data :pages-index %])))
|
||||
selected (:pages @opts)]
|
||||
[:ul.pages-selection
|
||||
(for [page pages]
|
||||
[:li.input-checkbox.check-primary {:key (str (:id page))}
|
||||
[:input {:type "checkbox"
|
||||
:id (str "page-" (:id page))
|
||||
:on-change #(mark-checked-page % (:id page))
|
||||
:checked (contains? selected (:id page))}]
|
||||
[:label {:for (str "page-" (:id page))} (:name page)]])]))])]
|
||||
|
||||
[:div.modal-footer
|
||||
(cond
|
||||
(true? @confirm)
|
||||
[:div.confirm-dialog
|
||||
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
|
||||
[:div.actions
|
||||
(some? @link)
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:on-click #(reset! confirm false)
|
||||
:value (tr "labels.cancel")}]
|
||||
[:input.btn-warning
|
||||
:class "primary"
|
||||
:on-click try-delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]
|
||||
|
||||
:else
|
||||
[:input.btn-primary
|
||||
{:type "button"
|
||||
:on-click delete-link
|
||||
:value (tr "common.share-link.remove-link")
|
||||
}]]]
|
||||
:class "primary"
|
||||
:on-click create-link
|
||||
:value (tr "common.share-link.get-link")}])]]]
|
||||
[:div.modal-content.ops-section
|
||||
[:div.manage-permissions
|
||||
{:on-click manage-open-ops}
|
||||
[:span.icon i/picker-hsv]
|
||||
[:div.title (tr "common.share-link.manage-ops")]]
|
||||
(when @open-ops
|
||||
[:*
|
||||
(let [all-selected? (:all-pages @opts)
|
||||
pages (->> (get-in file [:data :pages])
|
||||
(map #(get-in file [:data :pages-index %])))
|
||||
selected (:pages @opts)]
|
||||
|
||||
(some? @link)
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:class "primary"
|
||||
:on-click try-delete-link
|
||||
:value (tr "common.share-link.remove-link")}]
|
||||
[:*
|
||||
[:div.view-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/play]
|
||||
(tr "common.share-link.permissions-pages")]
|
||||
[:div.items
|
||||
(if (= 1 (count pages))
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (str "page-" (:id current-page))
|
||||
:on-change #(mark-checked-page % (:id current-page))
|
||||
:checked true}]
|
||||
[:label {:for (str "page-" (:id current-page))} (:name current-page)]
|
||||
[:span (str " " (tr "common.share-link.current-tag"))]]
|
||||
|
||||
:else
|
||||
[:input.btn-primary
|
||||
{:type "button"
|
||||
:class "primary"
|
||||
:on-click create-link
|
||||
:value (tr "common.share-link.get-link")}])]
|
||||
[:*
|
||||
[:div.row
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id "view-all"
|
||||
:checked all-selected?
|
||||
:name "pages-mode"
|
||||
:on-change toggle-all}]
|
||||
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
|
||||
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
||||
|
||||
]]))
|
||||
[:ul.pages-selection
|
||||
(for [page pages]
|
||||
[:li.input-checkbox.check-primary {:key (str (:id page))}
|
||||
[:input {:type "checkbox"
|
||||
:id (str "page-" (:id page))
|
||||
:on-change #(mark-checked-page % (:id page))
|
||||
:checked (contains? selected (:id page))}]
|
||||
(if (= (:id current-page) (:id page))
|
||||
[:*
|
||||
[:label {:for (str "page-" (:id page))} (:name page)]
|
||||
[:span.current-tag (str " " (tr "common.share-link.current-tag"))]]
|
||||
[:label {:for (str "page-" (:id page))} (:name page)])])]])]]])
|
||||
[:div.access-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/chat]
|
||||
(tr "common.share-link.permissions-can-comment")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change (partial on-who-change :comment)
|
||||
:value (:who-comment @opts)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
|
||||
[:div.inspect-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/code]
|
||||
(tr "common.share-link.permissions-can-inspect")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change (partial on-who-change :inspect)
|
||||
:value (:who-inspect @opts)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.share-link]
|
||||
[app.main.ui.static :as static]
|
||||
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
|
||||
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
|
||||
[app.main.ui.viewer.handoff :as handoff]
|
||||
[app.main.ui.viewer.header :refer [header]]
|
||||
[app.main.ui.viewer.interactions :as interactions]
|
||||
|
@ -84,7 +84,7 @@
|
|||
|
||||
(when show-comments-list
|
||||
[:& comments-sidebar {:users users :frame frame :page page}])
|
||||
|
||||
|
||||
[:div.viewer-wrapper
|
||||
{:style {:width (:width wrapper-size)
|
||||
:height (:height wrapper-size)}}
|
||||
|
@ -140,7 +140,7 @@
|
|||
:on-click #(when (:close-click-outside overlay)
|
||||
(close-overlay (:frame overlay)))}])
|
||||
[:div.viewport-container.viewer-overlay
|
||||
|
||||
|
||||
{:id (str "overlay-" (-> overlay :frame :id))
|
||||
:style {:width (:width size-over)
|
||||
:height (:height size-over)
|
||||
|
@ -169,6 +169,17 @@
|
|||
(let [{:keys [page-id section index]} params
|
||||
{:keys [file users project permissions]} data
|
||||
|
||||
allowed (or
|
||||
(= section :interactions)
|
||||
(and (= section :comments)
|
||||
(or (:can-edit permissions)
|
||||
(and (true? (:is-logged permissions))
|
||||
(= (:who-comment permissions) "all"))))
|
||||
(and (= section :handoff)
|
||||
(or (:can-edit permissions)
|
||||
(and (true? (:is-logged permissions))
|
||||
(= (:who-inspect permissions) "all")))))
|
||||
|
||||
local (mf/deref refs/viewer-local)
|
||||
|
||||
nav-scroll (:nav-scroll local)
|
||||
|
@ -241,6 +252,9 @@
|
|||
(when (nil? page)
|
||||
(ex/raise :type :not-found))
|
||||
|
||||
(when (not allowed)
|
||||
(st/emit! (dv/go-to-section :interactions)))
|
||||
|
||||
;; Set the page title
|
||||
(mf/use-effect
|
||||
(mf/deps (:name file))
|
||||
|
@ -394,24 +408,23 @@
|
|||
:index index
|
||||
:viewer-pagination viewer-pagination}]
|
||||
|
||||
|
||||
[:& viewer-wrapper
|
||||
{:wrapper-size wrapper-size
|
||||
:scroll scroll
|
||||
:orig-frame orig-frame
|
||||
:orig-viewport-ref orig-viewport-ref
|
||||
:orig-size orig-size
|
||||
:page page
|
||||
:file file
|
||||
:users users
|
||||
:current-viewport-ref current-viewport-ref
|
||||
:size size
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode
|
||||
:overlays overlays
|
||||
:zoom zoom
|
||||
:section section
|
||||
:index index}]))]]]))
|
||||
[:& viewer-wrapper
|
||||
{:wrapper-size wrapper-size
|
||||
:scroll scroll
|
||||
:orig-frame orig-frame
|
||||
:orig-viewport-ref orig-viewport-ref
|
||||
:orig-size orig-size
|
||||
:page page
|
||||
:file file
|
||||
:users users
|
||||
:current-viewport-ref current-viewport-ref
|
||||
:size size
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode
|
||||
:overlays overlays
|
||||
:zoom zoom
|
||||
:section section
|
||||
:index index}]))]]]))
|
||||
|
||||
;; --- Component: Viewer Page
|
||||
|
||||
|
|
|
@ -77,7 +77,8 @@
|
|||
(mf/use-callback
|
||||
(mf/deps page)
|
||||
(fn []
|
||||
(modal/show! :share-link {:page page :file file})))]
|
||||
(modal/show! :share-link {:page page :file file})
|
||||
(modal/allow-click-outside!)))]
|
||||
|
||||
[:div.options-zone
|
||||
(case section
|
||||
|
@ -187,7 +188,7 @@
|
|||
[:div.main-icon
|
||||
[:a {:on-click go-to-dashboard
|
||||
;; If the user doesn't have permission we disable the link
|
||||
:style {:pointer-events (when-not permissions "none")}} i/logo-icon]]
|
||||
:style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]]
|
||||
|
||||
[:& header-sitemap {:project project :file file :page page :frame frame :index index}]]
|
||||
|
||||
|
@ -198,7 +199,9 @@
|
|||
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||
i/play]
|
||||
|
||||
(when (:can-edit permissions)
|
||||
(when (or (:can-edit permissions)
|
||||
(and (true? (:is-logged permissions))
|
||||
(= (:who-comment permissions) "all")))
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click #(navigate :comments)
|
||||
:class (dom/classnames :active (= section :comments))
|
||||
|
@ -207,7 +210,8 @@
|
|||
|
||||
(when (or (= (:type permissions) :membership)
|
||||
(and (= (:type permissions) :share-link)
|
||||
(contains? (:flags permissions) :section-handoff)))
|
||||
(true? (:is-logged permissions))
|
||||
(= (:who-inspect permissions) "all")))
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click go-to-handoff
|
||||
:class (dom/classnames :active (= section :handoff))
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
[{:keys [users threads page-id]}]
|
||||
(let [threads-map (mf/deref refs/threads-ref)
|
||||
profile (mf/deref refs/profile)
|
||||
users-refs (mf/deref refs/users)
|
||||
users-refs (mf/deref refs/current-file-comments-users)
|
||||
users (or users users-refs)
|
||||
local (mf/deref refs/comments-local)
|
||||
options? (mf/use-state false)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
pos-y (* (- (:y vbox)) zoom)
|
||||
|
||||
profile (mf/deref refs/profile)
|
||||
users (mf/deref refs/users)
|
||||
users (mf/deref refs/current-file-comments-users)
|
||||
local (mf/deref refs/comments-local)
|
||||
threads-map (mf/deref refs/threads-ref)
|
||||
|
||||
|
|
|
@ -185,33 +185,15 @@ msgstr "S'ha copiat l'enllaç correctament"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "S'ha eliminat l'enllaç correctament"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Pot accedir"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Lector"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Qualsevol persona amb l'enllaç hi tindrà accés"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "L'enllaç per a compartir apareixerà aquí"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Elimina l'enllaç"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Compartiu prototips"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Totes les pàgines"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Només aquesta pàgina"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Pàgines seleccionades"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "Afegeix a la biblioteca compartida"
|
||||
|
|
|
@ -188,33 +188,15 @@ msgstr "Link wurde erfolgreich kopiert"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Link wurde erfolgreich gelöscht"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Freigabe für"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Sichtbar"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Jeder mit dem Link kann auf die Datei zugreifen"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Link zum Teilen wird hier erscheinen"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Link entfernen"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Prototypen teilen"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Alle Seiten"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Nur diese Seite"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Ausgewählte Seiten"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs,
|
||||
#: src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -183,11 +183,14 @@ msgstr "Link copied successfully"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Link deleted successfully"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Can access"
|
||||
msgid "common.share-link.permissions-can-comment"
|
||||
msgstr "Can comment"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Can view"
|
||||
msgid "common.share-link.permissions-can-inspect"
|
||||
msgstr "Can inspect code"
|
||||
|
||||
msgid "common.share-link.permissions-pages"
|
||||
msgstr "Pages shared"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Anyone with link will have access"
|
||||
|
@ -195,20 +198,31 @@ msgstr "Anyone with link will have access"
|
|||
msgid "common.share-link.placeholder"
|
||||
msgstr "Shareable link will appear here"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Remove link"
|
||||
msgid "common.share-link.destroy-link"
|
||||
msgstr "Destroy link"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Share prototypes"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "All pages"
|
||||
msgid "common.share-link.view-all"
|
||||
msgstr "Select All"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Only this page"
|
||||
msgid "common.share-link.current-tag"
|
||||
msgstr "(current)"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Selected pages"
|
||||
msgid "common.share-link.manage-ops"
|
||||
msgstr "Manage permissions"
|
||||
|
||||
msgid "common.share-link.team-members"
|
||||
msgstr "Only team members"
|
||||
|
||||
msgid "common.share-link.all-users"
|
||||
msgstr "All Penpot users"
|
||||
|
||||
msgid "common.share-link.page-shared"
|
||||
msgid_plural "common.share-link.page-shared"
|
||||
msgstr[0] "1 page shared"
|
||||
msgstr[1] "%s pages shared"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -188,11 +188,14 @@ msgstr "Enlace copiado satisfactoriamente"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Enlace eliminado correctamente"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Puede acceder a"
|
||||
msgid "common.share-link.permissions-can-comment"
|
||||
msgstr "Pueden comentar"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Puede ver"
|
||||
msgid "common.share-link.permissions-can-inspect"
|
||||
msgstr "Pueden ver código"
|
||||
|
||||
msgid "common.share-link.permissions-pages"
|
||||
msgstr "Páginas compartidas"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Cualquiera con el enlace puede acceder"
|
||||
|
@ -200,20 +203,31 @@ msgstr "Cualquiera con el enlace puede acceder"
|
|||
msgid "common.share-link.placeholder"
|
||||
msgstr "El enlace para compartir aparecerá aquí"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgid "common.share-link.destroy-link"
|
||||
msgstr "Eliminar enlace"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Compartir prototipos"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Todas las paginas"
|
||||
msgid "common.share-link.view-all"
|
||||
msgstr "Selecctionar todas"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Solo esta pagina"
|
||||
msgid "common.share-link.current-tag"
|
||||
msgstr "(actual)"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Paginas seleccionadas"
|
||||
msgid "common.share-link.manage-ops"
|
||||
msgstr "Gestionar permisos"
|
||||
|
||||
msgid "common.share-link.team-members"
|
||||
msgstr "Sólo integrantes del equipo"
|
||||
|
||||
msgid "common.share-link.all-users"
|
||||
msgstr "Todo usario de Penpot"
|
||||
|
||||
msgid "common.share-link.page-shared"
|
||||
msgid_plural "common.share-link.page-shared"
|
||||
msgstr[0] "1 página compartida"
|
||||
msgstr[1] "%s páginas compartidas"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs,
|
||||
#: src/app/main/ui/dashboard/file_menu.cljs
|
||||
|
|
|
@ -189,30 +189,12 @@ msgstr "لینک با موفقیت کپی شد"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "لینک با موفقیت حذف شد"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "میتواند دسترسی داشته باشد"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "میتواند مشاهده کند"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "هر کسی که لینک داشته باشد دسترسی خواهد داشت"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "حذف لینک"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "اشتراکگذاری پروتوتایپها"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "تمام صفحات"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "فقط این صفحه"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "صفحات انتخابشده"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "افزودن بهعنوان کتابخانه مشترک"
|
||||
|
|
|
@ -186,33 +186,15 @@ msgstr "Lien copié avec succès"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Lien supprimé avec succès"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Peut y accéder"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Peut le visionner"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "N'importe qui possédant ce lien peut y accéder"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Le lien à partager apparaîtra ici"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Supprimer le lien"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Partager les prototypes"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Toutes les pages"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Seulement cette page"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Pages sélectionnées"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs,
|
||||
#: src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -179,33 +179,15 @@ msgstr "הקישור הועתק בהצלחה"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "הקישור נמחק בהצלחה"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "יש גישה"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "אפשר לצפות"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "כל מי שיש לו את הקישור יכול לגשת"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "הקישור לשיתוף יופיע כאן"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "הסרת קישור"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "שיתוף אבות טיפוס"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "כל העמודים"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "רק העמוד הזה"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "עמודים נבחרים"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs,
|
||||
#: src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -189,20 +189,10 @@ msgstr "Tautan berhasil disalin"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Tautan berhasil dihapus"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Dapat mengakses"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Dapat melihat"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Siapapun yang memiliki tautan dapat mengakses"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Hanya halaman ini"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Halaman yang dipilih"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -188,33 +188,15 @@ msgstr "Nuoroda sėkmingai nukopijuota"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Nuoroda sėkmingai ištrinta"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Gali pasiekti"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Galima peržiūrėti"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Kiekvienas, turintis nuorodą, turės prieigą"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Bendrinama nuoroda bus rodoma čia"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Pašalinti nuorodą"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Dalinkitės prototipais"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Visi puslapiai"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Tik šis puslapis"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Parinkti puslapiai"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "Pridėti kaip bendrinamą biblioteką"
|
||||
|
|
|
@ -189,33 +189,15 @@ msgstr "കണ്ണി വിജയകരമായി പകർത്തി"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "കണ്ണി വിജയകരമായി മായിച്ചു"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "പ്രാപ്യമാണ്"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "കാണാവുന്നതാണ്"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "കണ്ണിയുള്ള ആർക്കും പ്രാപ്യമാകും"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "പങ്കുവെക്കാവുന്ന കണ്ണി ഇവിടെ ലഭ്യമാകും"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "കണ്ണി നീക്കുക"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "പ്രോട്ടോടൈപ്പുകൾ പങ്കുവെയ്ക്കുക"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "എല്ലാ താളുകളും"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "ഈ താൾ മാത്രം"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "തിരഞ്ഞെടുത്ത താളുകൾ"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "പങ്കിട്ട ലൈബ്രറിയായി ചേർക്കുക"
|
||||
|
|
|
@ -186,33 +186,15 @@ msgstr "Link skopiowano pomyślnie"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Link usunięto pomyślnie"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Można uzyskać dostęp"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Można zobaczyć"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Każdy, kto ma link, będzie miał dostęp"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Tutaj pojawi się link do udostępniania"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Usuń link"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Udostępnij prototypy"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Wszystkie strony"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Tylko ta strona"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Wybrane strony"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "Dodaj jako Udostępnioną Bibliotekę"
|
||||
|
|
|
@ -186,35 +186,16 @@ msgstr "Ссылка скопирована"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Ссылка удалена"
|
||||
|
||||
#, fuzzy
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Могут зайти"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Могут видеть"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Доступ открыт для получателей ссылки"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Ссылка появится здесь"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Удалить ссылку"
|
||||
|
||||
#, fuzzy
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Поделиться прототипами"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Все страницы"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Только эту страницу"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Выбранные страницы"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "Добавить как общую библиотеку"
|
||||
|
|
|
@ -186,33 +186,15 @@ msgstr "Bağlantı başarıyla kopyalandı"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "Bağlantı başarıyla silindi"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "Erişebilir"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "Görüntüleyebilir"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "Bağlantıya sahip olan herkes erişebilir"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "Paylaşılabilir bağlantı burada görünecek"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "Bağlantıyı kaldır"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "Prototipleri paylaş"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "Tüm sayfalar"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "Yalnızca bu sayfa"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "Seçili sayfalar"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs,
|
||||
#: src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
|
@ -177,13 +177,6 @@ msgstr "链接已复制"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "链接已移除"
|
||||
|
||||
#, fuzzy
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "可访问"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "可浏览"
|
||||
|
||||
#, fuzzy
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "任何人通过此链接都可访问"
|
||||
|
@ -191,21 +184,9 @@ msgstr "任何人通过此链接都可访问"
|
|||
msgid "common.share-link.placeholder"
|
||||
msgstr "可分享的链接会在此处显示"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "移除链接"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "分享原型"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "全部页面"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "仅此页面"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "选中的页面"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.add-shared"
|
||||
msgstr "添加为共享库"
|
||||
|
|
|
@ -181,33 +181,15 @@ msgstr "成功複製連結"
|
|||
msgid "common.share-link.link-deleted-success"
|
||||
msgstr "成功刪除連結"
|
||||
|
||||
msgid "common.share-link.permissions-can-access"
|
||||
msgstr "能夠存取"
|
||||
|
||||
msgid "common.share-link.permissions-can-view"
|
||||
msgstr "能夠檢視"
|
||||
|
||||
msgid "common.share-link.permissions-hint"
|
||||
msgstr "任何有連結的人皆能存取"
|
||||
|
||||
msgid "common.share-link.placeholder"
|
||||
msgstr "可分享的連結將會在此顯示"
|
||||
|
||||
msgid "common.share-link.remove-link"
|
||||
msgstr "移除連結"
|
||||
|
||||
msgid "common.share-link.title"
|
||||
msgstr "分享原型"
|
||||
|
||||
msgid "common.share-link.view-all-pages"
|
||||
msgstr "所有頁面"
|
||||
|
||||
msgid "common.share-link.view-current-page"
|
||||
msgstr "僅此頁面"
|
||||
|
||||
msgid "common.share-link.view-selected-pages"
|
||||
msgstr "選擇的頁面"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
#, fuzzy
|
||||
msgid "dashboard.add-shared"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue