mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
Merge branch 'iop-vc-preview' into branch-id-reroute
This commit is contained in:
commit
8444ee5595
@ -702,6 +702,7 @@
|
||||
JOIN file AS sf ON (sf.id = fb.source_file_id)
|
||||
WHERE fb.source_file_id = ?
|
||||
AND fb.deleted_at IS NULL
|
||||
AND fb.status != 'merged'
|
||||
AND (?::boolean OR fb.status = 'open')
|
||||
ORDER BY fb.created_at DESC")
|
||||
|
||||
@ -1091,12 +1092,7 @@
|
||||
[:expected-main-revn {:optional true} ::sm/int]
|
||||
;; what the user says about the merge; kept in its record
|
||||
;; (`file_branch_merge`), shown in the list of merges of main
|
||||
[:comment {:optional true} [:string {:max 4000}]]
|
||||
;; when false (the default) the branch and its file are logically
|
||||
;; deleted right after a successful merge, in the SAME transaction (so
|
||||
;; merged copies do not pile up); when true the branch is kept as
|
||||
;; "merged", staying readable with status merged until it is deleted.
|
||||
[:keep-branch {:optional true} ::sm/boolean]])
|
||||
[:comment {:optional true} [:string {:max 4000}]]])
|
||||
|
||||
(sv/defmethod ::merge-file-branch
|
||||
"Merge a branch into its source file (main).
|
||||
@ -1109,15 +1105,15 @@
|
||||
`{:status :unsupported}` so no change is silently dropped. Otherwise it
|
||||
takes a safety snapshot of main, applies the merge to main through the
|
||||
production change pipeline, records the merge with its `comment`
|
||||
(`file_branch_merge`), deletes the branch and its file unless
|
||||
`keep-branch` asks to keep it, and notifies open clients via msgbus."
|
||||
(`file_branch_merge`), deletes the branch and its file and notifies
|
||||
open clients via msgbus."
|
||||
{::doc/added "2.16"
|
||||
::webhooks/event? true
|
||||
::sm/params schema:merge-file-branch
|
||||
::climit/id [[:merge-file-branch/by-profile ::rpc/profile-id]
|
||||
[:merge-file-branch/global]]}
|
||||
[{:keys [::mbus/msgbus] :as cfg}
|
||||
{:keys [::rpc/profile-id ::rpc/session-id branch-id resolutions expected-main-revn comment keep-branch excluded]}]
|
||||
{:keys [::rpc/profile-id ::rpc/session-id branch-id resolutions expected-main-revn comment excluded]}]
|
||||
(bp/with-policies
|
||||
(check-branching-enabled!)
|
||||
(let [branch (db/get* cfg :file-branch {:id branch-id})]
|
||||
@ -1207,16 +1203,13 @@
|
||||
|
||||
finish-branch!
|
||||
(fn [ts]
|
||||
;; record the merge and mark the branch merged. The
|
||||
;; pinned base snapshot stays for a KEPT branch (its
|
||||
;; state is derived from that snapshot and the op
|
||||
;; log); delete-branch! releases it on the delete
|
||||
;; path. Unless the user chose to keep it the branch
|
||||
;; and its file are deleted in this same transaction
|
||||
;; record the merge, mark the branch merged and
|
||||
;; delete it and its file in this same transaction
|
||||
;; (no client-driven second call, no window where a
|
||||
;; crash leaves a stale copy). The record is written
|
||||
;; first: it reads the open pull request the lines
|
||||
;; below close.
|
||||
;; crash leaves a stale copy); delete-branch!
|
||||
;; releases the pinned base snapshot. The record is
|
||||
;; written first: it reads the open pull request the
|
||||
;; lines below close.
|
||||
(record-merge! conn branch {:profile-id profile-id
|
||||
:comment comment
|
||||
:created-at ts})
|
||||
@ -1235,10 +1228,9 @@
|
||||
{:profile-id profile-id
|
||||
:status "merged"
|
||||
:deleted-at (ct/in-future delay)})
|
||||
(when-not keep-branch
|
||||
(vswap! messages conj
|
||||
(delete-branch! cfg branch {:profile-id profile-id
|
||||
:session-id session-id})))))]
|
||||
(vswap! messages conj
|
||||
(delete-branch! cfg branch {:profile-id profile-id
|
||||
:session-id session-id}))))]
|
||||
(cond
|
||||
(seq unresolved)
|
||||
(audited {:status :conflicts :conflicts conflicts :main-revn (:revn main-file)}
|
||||
@ -1940,6 +1932,7 @@
|
||||
"SELECT count(*) AS count
|
||||
FROM file_branch AS fb
|
||||
WHERE fb.deleted_at IS NULL
|
||||
AND fb.status != 'merged'
|
||||
AND fb.source_file_id = coalesce((SELECT b.source_file_id
|
||||
FROM file_branch AS b
|
||||
WHERE b.branch_file_id = ?
|
||||
@ -1947,8 +1940,8 @@
|
||||
?)")
|
||||
|
||||
(sv/defmethod ::get-file-branch-count
|
||||
"How many branches the file has, archived and merged ones included, as
|
||||
the listing with `:include-archived` returns them. When the file is
|
||||
"How many branches the file has, archived ones included, as the
|
||||
listing with `:include-archived` returns them. When the file is
|
||||
itself a branch, the branches of its source (main) are counted.
|
||||
|
||||
The workspace header asks this on every file open to decide whether to
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.files.migrations :as fmg]
|
||||
[app.common.time :as ct]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
@ -1412,67 +1411,3 @@
|
||||
row (th/db-get :file-media-object {:id ref})]
|
||||
(t/is (some? row))
|
||||
(t/is (= main-id (:file-id row)))))))
|
||||
|
||||
(t/deftest merge-with-keep-branch-leaves-the-branch-readable
|
||||
(with-redefs [cf/flags (conj cf/flags :branching)]
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
proj-id (:default-project-id profile)
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id proj-id
|
||||
:is-shared false})
|
||||
create (create-branch* profile (:id file) "oplog-keep")
|
||||
branch-file-id (:branch-file-id create)
|
||||
branch-id (:id create)
|
||||
color-id (uuid/random)]
|
||||
|
||||
(apply-change* profile branch-file-id
|
||||
{:type :add-color
|
||||
:color {:id color-id :name "C" :color "#112233" :opacity 1}})
|
||||
|
||||
(let [out (th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (= :merged (-> out :result :status))))
|
||||
|
||||
(t/testing "the kept branch still derives its state"
|
||||
(let [out (th/command! {::th/type :get-file
|
||||
::rpc/profile-id (:id profile)
|
||||
:id branch-file-id})]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (contains? (-> out :result :data :colors) color-id))))
|
||||
|
||||
(t/testing "the base pin survives while the branch is kept"
|
||||
(let [rows (->> (th/db-query :file-change {:file-id (:id file)})
|
||||
(filter #(some-> (:label %) (str/starts-with? "branch-base/"))))]
|
||||
(t/is (seq rows))
|
||||
(t/is (every? (fn [{:keys [deleted-at]}]
|
||||
(or (nil? deleted-at)
|
||||
(ct/is-after? deleted-at (ct/in-future {:days 400}))))
|
||||
rows)))))))
|
||||
|
||||
(t/deftest a-kept-merged-branch-refuses-saves
|
||||
(with-redefs [cf/flags (conj cf/flags :branching)]
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
proj-id (:default-project-id profile)
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id proj-id
|
||||
:is-shared false})
|
||||
create (create-branch* profile (:id file) "oplog-merged")
|
||||
branch-file-id (:branch-file-id create)
|
||||
branch-id (:id create)]
|
||||
|
||||
(th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})
|
||||
|
||||
(let [out (apply-change* profile branch-file-id
|
||||
{:type :add-color
|
||||
:color {:id (uuid/random) :name "C" :color "#112233" :opacity 1}})]
|
||||
(t/is (th/ex-of-type? (:error out) :validation))
|
||||
(t/is (th/ex-of-code? (:error out) :branch-merged)))
|
||||
|
||||
(t/testing "nothing reaches the op log"
|
||||
(t/is (empty? (oplog-rows branch-file-id)))))))
|
||||
|
||||
@ -3236,60 +3236,3 @@
|
||||
(= main-1 (:id %))
|
||||
(= :deleted (:status %)))
|
||||
(:changes diff))))))))
|
||||
|
||||
(t/deftest merge-with-keep-branch-archives-it
|
||||
(with-redefs [cf/flags (conj cf/flags :branching)]
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
proj-id (:default-project-id profile)
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id proj-id})
|
||||
create (:result (th/command! {::th/type :create-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:file-id (:id file)
|
||||
:name "kept"}))
|
||||
branch-id (:id create)
|
||||
branch-file-id (:branch-file-id create)]
|
||||
|
||||
(let [out (th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (= :merged (-> out :result :status))))
|
||||
|
||||
(let [[row] (th/db-query :file-branch {:id branch-id})
|
||||
bf (th/db-get :file {:id branch-file-id})]
|
||||
(t/is (= "merged" (:status row)))
|
||||
(t/is (nil? (:deleted-at row)))
|
||||
(t/is (nil? (:deleted-at bf)))))))
|
||||
|
||||
(t/deftest delete-keeps-the-status-the-branch-carries
|
||||
;; deleting a kept merged branch must not rewrite its status: the
|
||||
;; record is the only place left that says the branch was merged
|
||||
(with-redefs [cf/flags (conj cf/flags :branching)]
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
proj-id (:default-project-id profile)
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id proj-id})
|
||||
create (:result (th/command! {::th/type :create-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:file-id (:id file)
|
||||
:name "kept"}))
|
||||
branch-id (:id create)
|
||||
branch-file-id (:branch-file-id create)
|
||||
cid (uuid/random)]
|
||||
(apply-change* profile branch-file-id
|
||||
{:type :add-color :color {:id cid :name "C" :color "#112233" :opacity 1}})
|
||||
(let [out (th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})]
|
||||
(t/is (= :merged (-> out :result :status))))
|
||||
(let [out (th/command! {::th/type :delete-file-branch
|
||||
::rpc/profile-id (:id profile)
|
||||
:id branch-id})]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (= :deleted (-> out :result :status))))
|
||||
(let [[row] (th/db-query :file-branch {:id branch-id})]
|
||||
(t/is (= "merged" (:status row)))
|
||||
(t/is (some? (:deleted-at row)))))))
|
||||
|
||||
@ -792,78 +792,3 @@
|
||||
(t/is (empty? @seen))
|
||||
(t/is (empty? (th/db-query :file-pull-request
|
||||
{:file-branch-id (:id branch)})))))))
|
||||
|
||||
(t/deftest create-serializes-against-a-kept-concurrent-merge
|
||||
;; same race, but the merge keeps the branch: its row stays readable
|
||||
;; with status "merged" and its file is not deleted, so without the
|
||||
;; re-read the create sails past the stale status check and INSERTS a
|
||||
;; pull request for a branch the merge already closed.
|
||||
(with-redefs [cf/flags pr-flags]
|
||||
(let [author (th/create-profile* 1 {:is-active true})
|
||||
file (th/create-file* 1 {:profile-id (:id author)
|
||||
:project-id (:default-project-id author)})
|
||||
branch (create-branch* author file "contested")
|
||||
branch-id (:id branch)
|
||||
branch-file-id (:branch-file-id branch)]
|
||||
(add-color* author branch-file-id "Brand")
|
||||
(let [orig-lock db/xact-lock!
|
||||
merging? (atom false)
|
||||
merged (atom nil)]
|
||||
(with-redefs [db/xact-lock!
|
||||
(fn [conn id]
|
||||
;; the first lock the create takes is the signal:
|
||||
;; merge the same branch through the pool in its
|
||||
;; own transaction BEFORE the create locks
|
||||
(when (compare-and-set! merging? false true)
|
||||
(reset! merged (th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id author)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})))
|
||||
(orig-lock conn id))]
|
||||
(let [out (th/command! {::th/type :create-pull-request
|
||||
::rpc/profile-id (:id author)
|
||||
:branch-id branch-id
|
||||
:title "review me"})]
|
||||
(t/is (= :merged (-> @merged :result :status)))
|
||||
(t/is (= "merged" (:status (first (th/db-query :file-branch {:id branch-id})))))
|
||||
(t/is (= :branch-not-open (-> out :error ex-data :code)))
|
||||
(t/is (= [] (th/db-query :file-pull-request {:file-branch-id branch-id})))))))))
|
||||
|
||||
(t/deftest reopen-serializes-against-a-kept-concurrent-merge
|
||||
;; same race for the reopen: the kept merge leaves the branch row
|
||||
;; readable with status "merged", so without the re-read the reopen
|
||||
;; sails past the stale status check and REOPENS the closed pull
|
||||
;; request over a branch the merge already closed.
|
||||
(with-redefs [cf/flags pr-flags]
|
||||
(let [author (th/create-profile* 1 {:is-active true})
|
||||
file (th/create-file* 1 {:profile-id (:id author)
|
||||
:project-id (:default-project-id author)})
|
||||
branch (create-branch* author file "contested")
|
||||
branch-id (:id branch)
|
||||
branch-file-id (:branch-file-id branch)]
|
||||
(add-color* author branch-file-id "Brand")
|
||||
(let [pr (:result (create-pr* author branch-id {}))]
|
||||
(t/is (nil? (:error (th/command! {::th/type :close-pull-request
|
||||
::rpc/profile-id (:id author)
|
||||
:id (:id pr)}))))
|
||||
(let [orig-lock db/xact-lock!
|
||||
merging? (atom false)
|
||||
merged (atom nil)]
|
||||
(with-redefs [db/xact-lock!
|
||||
(fn [conn id]
|
||||
;; the first lock the reopen takes is the signal:
|
||||
;; merge the same branch through the pool in its
|
||||
;; own transaction BEFORE the reopen locks
|
||||
(when (compare-and-set! merging? false true)
|
||||
(reset! merged (th/command! {::th/type :merge-file-branch
|
||||
::rpc/profile-id (:id author)
|
||||
:branch-id branch-id
|
||||
:keep-branch true})))
|
||||
(orig-lock conn id))]
|
||||
(let [out (th/command! {::th/type :reopen-pull-request
|
||||
::rpc/profile-id (:id author)
|
||||
:id (:id pr)})]
|
||||
(t/is (= :merged (-> @merged :result :status)))
|
||||
(t/is (= "merged" (:status (first (th/db-query :file-branch {:id branch-id})))))
|
||||
(t/is (= :branch-not-open (-> out :error ex-data :code)))
|
||||
(t/is (= "closed" (:status (first (th/db-query :file-pull-request {:id (:id pr)}))))))))))))
|
||||
|
||||
@ -745,19 +745,14 @@
|
||||
|
||||
(defn merge-branch
|
||||
"Merge `branch` (a branch row/context map with at least `:id`) into main.
|
||||
On success the server records the merge and, unless the branch is kept,
|
||||
deletes the branch and its file; open clients reload main via the
|
||||
`:file-merged` msgbus event.
|
||||
On success the server records the merge and deletes the branch and its
|
||||
file, and open clients reload main via the `:file-merged` msgbus event.
|
||||
|
||||
Options:
|
||||
- `:resolutions` — optional `{entity-id (:main|:branch)}` map used to
|
||||
resolve conflicts before integrating.
|
||||
- `:comment` — what the user says about the merge, kept with its
|
||||
record and shown in the reviews dialog.
|
||||
- `:keep-branch` — when true the merged branch is kept (it shows up
|
||||
under \"Archived\"); when false (default) the server deletes the
|
||||
branch and its file in the same transaction, so merged copies do not
|
||||
pile up and eat disk space.
|
||||
- `:excluded` — the per-change selection (change keys,
|
||||
`app.common.files.branch-merge/change-key`) naming the changes the
|
||||
user deselected, which main keeps its own value for.
|
||||
@ -769,7 +764,7 @@
|
||||
before that diff has loaded carry the revn of the conflict answer instead
|
||||
(`conflict-main-revn`). Unresolved conflicts open the resolution modal."
|
||||
([branch] (merge-branch branch nil))
|
||||
([branch {:keys [resolutions comment keep-branch excluded]}]
|
||||
([branch {:keys [resolutions comment excluded]}]
|
||||
(assert (uuid? (:id branch)) "expected a branch row with a valid `:id`")
|
||||
(ptk/reify ::merge-branch
|
||||
ptk/WatchEvent
|
||||
@ -787,7 +782,6 @@
|
||||
(seq resolutions) (assoc :resolutions resolutions)
|
||||
(seq excluded) (assoc :excluded excluded)
|
||||
(not (str/blank? comment)) (assoc :comment (str/trim comment))
|
||||
keep-branch (assoc :keep-branch true)
|
||||
(some? main-revn) (assoc :expected-main-revn main-revn)))
|
||||
(rx/mapcat
|
||||
(fn [{:keys [status source-file-id conflicts] :as answer}]
|
||||
@ -795,8 +789,8 @@
|
||||
;; the merged result lives in main: take the user there
|
||||
;; to see it (navigate if elsewhere, hard-reload if
|
||||
;; already on main). Other clients reload via the
|
||||
;; `:file-merged` event; the branch deletion (when not
|
||||
;; kept) already happened server-side.
|
||||
;; `:file-merged` event; the branch deletion already
|
||||
;; happened server-side.
|
||||
:merged (rx/of (ntf/success (tr "workspace.branches.merge.success"))
|
||||
(show-merge-result source-file-id))
|
||||
:conflicts (rx/of (open-conflict-resolutions {:branch branch
|
||||
|
||||
@ -24,10 +24,10 @@
|
||||
;; --- Merge / update confirmations
|
||||
|
||||
(defn confirm-merge!
|
||||
"Open the merge dialog for `branch` (merge into main is irreversible; the
|
||||
dialog asks for a comment for the merge's record and lets the user choose
|
||||
whether to keep the branch archived). `excluded` is the compare dialog's
|
||||
per-change selection, if any."
|
||||
"Open the merge dialog for `branch` (merge into main is irreversible and
|
||||
deletes the branch; the dialog asks for a comment for the merge's
|
||||
record). `excluded` is the compare dialog's per-change selection, if
|
||||
any."
|
||||
([branch] (confirm-merge! branch nil))
|
||||
([branch excluded]
|
||||
(modal/show! :merge-branch {:branch branch :excluded excluded})))
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
[app.main.data.workspace.branches :as dwb]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.controls.checkbox :refer [checkbox*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
@ -393,8 +392,6 @@
|
||||
(let [{:keys [diff resolutions status]} (mf/deref branch-diff)
|
||||
|
||||
loading? (= status :loading)
|
||||
keep?* (mf/use-state false)
|
||||
keep? (deref keep?*)
|
||||
selected* (mf/use-state 0)
|
||||
selected (deref selected*)
|
||||
|
||||
@ -465,7 +462,7 @@
|
||||
(when next-ix (reset! selected* next-ix)))))
|
||||
on-apply (mf/use-fn
|
||||
;; a merge sends again the comment of the merge dialog
|
||||
(mf/deps branch resolutions mode keep? excluded comment conflicts)
|
||||
(mf/deps branch resolutions mode excluded comment conflicts)
|
||||
(fn []
|
||||
(let [ids (into #{} (map :id) conflicts)
|
||||
res (into {} (filter (fn [[id _]] (contains? ids id))) resolutions)]
|
||||
@ -473,7 +470,6 @@
|
||||
(dwb/update-branch-from-main branch {:resolutions res
|
||||
:excluded excluded})
|
||||
(dwb/merge-branch branch {:resolutions res
|
||||
:keep-branch keep?
|
||||
:comment comment
|
||||
:excluded excluded}))))))]
|
||||
|
||||
@ -552,12 +548,7 @@
|
||||
(if all-done?
|
||||
[:div {:class (stl/css :footer-start)}
|
||||
[:> text* {:as "span" :typography t/body-small :class (stl/css :footer-ready)}
|
||||
(tr "workspace.branches.conflicts.footer-ready")]
|
||||
(when (not= mode :update)
|
||||
[:> checkbox* {:id "conflicts-archive-branch"
|
||||
:label (tr "workspace.branches.merge.archive-label")
|
||||
:checked keep?
|
||||
:on-change #(swap! keep?* not)}])]
|
||||
(tr "workspace.branches.conflicts.footer-ready")]]
|
||||
[:> text* {:as "span" :typography t/body-small :class (stl/css :footer-blocked)}
|
||||
(tr "workspace.branches.resolve.footer.blocked" (i18n/c pending))]))
|
||||
:footer-end
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.checkbox :refer [checkbox*]]
|
||||
[app.main.ui.ds.controls.input :refer [input*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.layout.menu :refer [menu* menu-item* menu-separator*]]
|
||||
@ -262,9 +261,7 @@
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :merge-branch}
|
||||
[{:keys [branch excluded]}]
|
||||
(let [archive?* (mf/use-state false)
|
||||
archive? (deref archive?*)
|
||||
comment* (mf/use-state "")
|
||||
(let [comment* (mf/use-state "")
|
||||
comment (deref comment*)
|
||||
|
||||
;; what goes in and what stays out, when the compare dialog of this
|
||||
@ -297,9 +294,6 @@
|
||||
(str sep (tr "workspace.branches.main") sep))]
|
||||
(str/split msg sep))
|
||||
|
||||
on-toggle-archive
|
||||
(mf/use-fn #(swap! archive?* not))
|
||||
|
||||
on-comment-change
|
||||
(mf/use-fn #(reset! comment* (dom/get-target-val %)))
|
||||
|
||||
@ -308,11 +302,9 @@
|
||||
|
||||
on-submit
|
||||
(mf/use-fn
|
||||
(mf/deps branch archive? comment excluded)
|
||||
(mf/deps branch comment excluded)
|
||||
(fn [_]
|
||||
(st/emit! (dwb/merge-branch branch {:keep-branch archive?
|
||||
:comment comment
|
||||
:excluded excluded})
|
||||
(st/emit! (dwb/merge-branch branch {:comment comment :excluded excluded})
|
||||
(modal/hide))))]
|
||||
|
||||
[:> modal* {:is-open true
|
||||
@ -344,22 +336,10 @@
|
||||
:on-change on-comment-change
|
||||
:rows 3}]]
|
||||
|
||||
[:> checkbox* {:id "merge-archive-branch"
|
||||
:label (tr "workspace.branches.merge.archive-label")
|
||||
:checked archive?
|
||||
:on-change on-toggle-archive}]
|
||||
|
||||
(cond
|
||||
archive?
|
||||
[:> context-notification* {:level :warning :type :context}
|
||||
(tr "workspace.branches.merge.archive-warning")]
|
||||
|
||||
(if (pos? left-out)
|
||||
;; deleting the branch takes the changes left out with it
|
||||
(pos? left-out)
|
||||
[:> context-notification* {:level :warning :type :context}
|
||||
(tr "workspace.branches.merge.left-out-lost" (i18n/c left-out))]
|
||||
|
||||
:else
|
||||
[:> context-notification* {:level :info :type :context}
|
||||
(tr "workspace.branches.merge.delete-info")])]
|
||||
|
||||
|
||||
@ -7323,16 +7323,6 @@ msgstr ""
|
||||
msgid "workspace.branches.merge.confirm-title"
|
||||
msgstr "Merge into main"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/branches.cljs:370, src/app/main/ui/workspace/sidebar/branches.cljs:1526
|
||||
msgid "workspace.branches.merge.archive-label"
|
||||
msgstr "Archive this branch"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/branches.cljs:376
|
||||
msgid "workspace.branches.merge.archive-warning"
|
||||
msgstr ""
|
||||
"Archived branches keep a full copy of the file so they can be restored "
|
||||
"later. Keeping many archived branches can take up a lot of storage."
|
||||
|
||||
#: src/app/main/data/workspace/branches.cljs:415
|
||||
#, unused
|
||||
msgid "workspace.branches.merge.conflicts"
|
||||
@ -7340,9 +7330,7 @@ msgstr "This branch has conflicts that must be resolved before merging"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/branches.cljs:378
|
||||
msgid "workspace.branches.merge.delete-info"
|
||||
msgstr ""
|
||||
"After merging, this branch and its file will be deleted to free up storage. "
|
||||
"Archive it if you might need to restore it later."
|
||||
msgstr "After merging, this branch and its file will be deleted to free up storage."
|
||||
|
||||
#: src/app/main/data/workspace/branches.cljs:451, src/app/main/data/workspace/branches.cljs:459
|
||||
msgid "workspace.branches.merge.error"
|
||||
@ -11800,8 +11788,8 @@ msgstr[1] "%s changes are left out."
|
||||
#: src/app/main/ui/workspace/sidebar/branches.cljs
|
||||
msgid "workspace.branches.merge.left-out-lost"
|
||||
msgid_plural "workspace.branches.merge.left-out-lost"
|
||||
msgstr[0] "The change you left out is lost when the branch is deleted. Archive the branch to keep it."
|
||||
msgstr[1] "The %s changes you left out are lost when the branch is deleted. Archive the branch to keep them."
|
||||
msgstr[0] "The change you left out is lost when the branch is deleted."
|
||||
msgstr[1] "The %s changes you left out are lost when the branch is deleted."
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/branch_review/compare.cljs
|
||||
msgid "workspace.branches.review.view.expand"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user