Bounties view + related backend functionality & more
Changes to bounty/pull-request data model and logic * save git sha of pull request's HEAD instead of possible merge commit and save it for opened, merged and closed events * only look for bounties being accepted in pull-request closed via merge events (no need for compilicated logic with issue-closed event) * pull_request now has issue_id column to make many sql queries simpler Frontend * owner-bounties app-db structure changes * bounties view with confirm pending payout UI Other * removed lots of unused legacy code * bug fixes + refactoring * added comments + TODOs
This commit is contained in:
parent
ec5f07a578
commit
9cb48b5183
|
@ -41,7 +41,8 @@
|
||||||
[crypto-equality "1.0.0"]
|
[crypto-equality "1.0.0"]
|
||||||
[cheshire "5.7.0"]
|
[cheshire "5.7.0"]
|
||||||
[mpg "1.3.0"]
|
[mpg "1.3.0"]
|
||||||
[pandect "0.6.1"]]
|
[pandect "0.6.1"]
|
||||||
|
[prismatic/plumbing "0.5.3"]]
|
||||||
|
|
||||||
:min-lein-version "2.0.0"
|
:min-lein-version "2.0.0"
|
||||||
:source-paths ["src/clj" "src/cljc"]
|
:source-paths ["src/clj" "src/cljc"]
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE "public"."pull_requests"
|
||||||
|
ADD COLUMN "updated" timestamp without time zone DEFAULT timezone('utc'::text, now()),
|
||||||
|
ADD COLUMN "issue_id" integer,
|
||||||
|
ADD UNIQUE ("pr_id");
|
|
@ -121,8 +121,8 @@ INSERT INTO issues (repo_id, issue_id, issue_number, title)
|
||||||
FROM issues
|
FROM issues
|
||||||
WHERE repo_id = :repo_id AND issue_id = :issue_id);
|
WHERE repo_id = :repo_id AND issue_id = :issue_id);
|
||||||
|
|
||||||
-- :name close-issue! :<! :1
|
-- :name update-commit-id :<! :1
|
||||||
-- :doc updates issue with commit id
|
-- :doc updates issue with commit_id
|
||||||
UPDATE issues
|
UPDATE issues
|
||||||
SET commit_id = :commit_id
|
SET commit_id = :commit_id
|
||||||
WHERE issue_id = :issue_id
|
WHERE issue_id = :issue_id
|
||||||
|
@ -171,7 +171,7 @@ SELECT
|
||||||
transaction_hash
|
transaction_hash
|
||||||
FROM issues
|
FROM issues
|
||||||
WHERE contract_address IS NULL
|
WHERE contract_address IS NULL
|
||||||
AND issues.transaction_hash IS NOT NULL;
|
AND issues.transaction_hash IS NOT NULL;
|
||||||
|
|
||||||
-- Pull Requests -------------------------------------------------------------------
|
-- Pull Requests -------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -181,6 +181,7 @@ INSERT INTO pull_requests (pr_id,
|
||||||
repo_id,
|
repo_id,
|
||||||
pr_number,
|
pr_number,
|
||||||
issue_number,
|
issue_number,
|
||||||
|
issue_id,
|
||||||
commit_id,
|
commit_id,
|
||||||
user_id,
|
user_id,
|
||||||
state)
|
state)
|
||||||
|
@ -188,12 +189,14 @@ VALUES(:pr_id,
|
||||||
:repo_id,
|
:repo_id,
|
||||||
:pr_number,
|
:pr_number,
|
||||||
:issue_number,
|
:issue_number,
|
||||||
|
:issue_id,
|
||||||
:commit_id,
|
:commit_id,
|
||||||
:user_id,
|
:user_id,
|
||||||
:state)
|
:state)
|
||||||
ON CONFLICT (pr_id) DO UPDATE
|
ON CONFLICT (pr_id) DO UPDATE
|
||||||
SET
|
SET
|
||||||
state = :state,
|
state = :state,
|
||||||
|
updated = timezone('utc'::text, now()),
|
||||||
commit_id = :commit_id;
|
commit_id = :commit_id;
|
||||||
|
|
||||||
-- Bounties ------------------------------------------------------------------------
|
-- Bounties ------------------------------------------------------------------------
|
||||||
|
@ -206,7 +209,7 @@ SELECT
|
||||||
u.address AS payout_address
|
u.address AS payout_address
|
||||||
FROM issues i, pull_requests p, users u
|
FROM issues i, pull_requests p, users u
|
||||||
WHERE
|
WHERE
|
||||||
(p.commit_id = i.commit_id OR coalesce(p.issue_number, -1) = i.issue_number)
|
p.issue_id = i.issue_id
|
||||||
AND p.repo_id = i.repo_id
|
AND p.repo_id = i.repo_id
|
||||||
AND u.id = p.user_id
|
AND u.id = p.user_id
|
||||||
AND i.execute_hash IS NULL;
|
AND i.execute_hash IS NULL;
|
||||||
|
@ -216,10 +219,11 @@ AND i.execute_hash IS NULL;
|
||||||
SELECT
|
SELECT
|
||||||
i.contract_address AS contract_address,
|
i.contract_address AS contract_address,
|
||||||
i.issue_id AS issue_id,
|
i.issue_id AS issue_id,
|
||||||
u.address AS payout_address
|
u.address AS payout_address,
|
||||||
|
i.execute_hash AS execute_hash
|
||||||
FROM issues i, pull_requests p, users u
|
FROM issues i, pull_requests p, users u
|
||||||
WHERE
|
WHERE
|
||||||
(p.commit_id = i.commit_id OR coalesce(p.issue_number, -1) = i.issue_number)
|
p.issue_id = i.issue_id
|
||||||
AND p.repo_id = i.repo_id
|
AND p.repo_id = i.repo_id
|
||||||
AND u.id = p.user_id
|
AND u.id = p.user_id
|
||||||
AND i.confirm_hash IS NULL
|
AND i.confirm_hash IS NULL
|
||||||
|
@ -230,10 +234,11 @@ AND i.execute_hash IS NOT NULL;
|
||||||
SELECT
|
SELECT
|
||||||
i.contract_address AS contract_address,
|
i.contract_address AS contract_address,
|
||||||
i.issue_id AS issue_id,
|
i.issue_id AS issue_id,
|
||||||
u.address AS payout_address
|
u.address AS payout_address,
|
||||||
|
i.payout_hash AS payout_hash
|
||||||
FROM issues i, pull_requests p, users u
|
FROM issues i, pull_requests p, users u
|
||||||
WHERE
|
WHERE
|
||||||
(p.commit_id = i.commit_id OR coalesce(p.issue_number, -1) = i.issue_number)
|
p.issue_id = i.issue_id
|
||||||
AND p.repo_id = i.repo_id
|
AND p.repo_id = i.repo_id
|
||||||
AND u.id = p.user_id
|
AND u.id = p.user_id
|
||||||
AND i.payout_receipt IS NULL
|
AND i.payout_receipt IS NULL
|
||||||
|
@ -280,7 +285,7 @@ r.repo_id = i.repo_id
|
||||||
AND i.commit_id IS NULL;
|
AND i.commit_id IS NULL;
|
||||||
|
|
||||||
-- :name owner-bounties-list :? :*
|
-- :name owner-bounties-list :? :*
|
||||||
-- :doc lists fixed issues (bounties awaiting maintainer confirmation)
|
-- :doc all bounty issues for given owner
|
||||||
SELECT
|
SELECT
|
||||||
i.contract_address AS contract_address,
|
i.contract_address AS contract_address,
|
||||||
i.issue_id AS issue_id,
|
i.issue_id AS issue_id,
|
||||||
|
@ -291,24 +296,50 @@ SELECT
|
||||||
i.confirm_hash AS confirm_hash,
|
i.confirm_hash AS confirm_hash,
|
||||||
i.payout_hash AS payout_hash,
|
i.payout_hash AS payout_hash,
|
||||||
i.payout_receipt AS payout_receipt,
|
i.payout_receipt AS payout_receipt,
|
||||||
|
r.repo AS repo_name,
|
||||||
|
o.address AS owner_address
|
||||||
|
FROM issues i, users o, repositories r
|
||||||
|
WHERE
|
||||||
|
r.repo_id = i.repo_id
|
||||||
|
AND r.user_id = o.id
|
||||||
|
AND r.user_id = :owner_id;
|
||||||
|
-- AND i.confirm_hash IS NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
-- :name bounty-claims :? :*
|
||||||
|
-- :doc open, merged and closed PRs referencing given bounty issue
|
||||||
|
SELECT
|
||||||
|
i.contract_address AS contract_address,
|
||||||
|
i.issue_id AS issue_id,
|
||||||
|
i.issue_number AS issue_number,
|
||||||
|
i.title AS issue_title,
|
||||||
|
i.repo_id AS repo_id,
|
||||||
|
i.balance AS balance,
|
||||||
|
i.confirm_hash AS confirm_hash,
|
||||||
|
i.payout_hash AS payout_hash,
|
||||||
|
i.payout_receipt AS payout_receipt,
|
||||||
|
p.state AS pr_state,
|
||||||
p.pr_id AS pr_id,
|
p.pr_id AS pr_id,
|
||||||
p.user_id AS user_id,
|
p.user_id AS user_id,
|
||||||
p.pr_number AS pr_number,
|
p.pr_number AS pr_number,
|
||||||
u.address AS payout_address,
|
u.address AS payout_address,
|
||||||
u.login AS user_login,
|
u.login AS user_login,
|
||||||
u.name AS user_name,
|
u.name AS user_name,
|
||||||
r.login AS owner_name,
|
u.avatar_url AS user_avatar_url,
|
||||||
|
r.login AS owner_login,
|
||||||
r.repo AS repo_name,
|
r.repo AS repo_name,
|
||||||
o.address AS owner_address
|
o.address AS owner_address
|
||||||
FROM issues i, pull_requests p, users u, users o, repositories r
|
FROM issues i, pull_requests p, users u, users o, repositories r
|
||||||
WHERE
|
WHERE
|
||||||
(p.commit_id = i.commit_id OR coalesce(p.issue_number, -1) = i.issue_number)
|
p.issue_id = i.issue_id
|
||||||
AND p.repo_id = i.repo_id
|
AND p.repo_id = i.repo_id
|
||||||
AND u.id = p.user_id
|
AND u.id = p.user_id
|
||||||
AND r.repo_id = i.repo_id
|
AND r.repo_id = i.repo_id
|
||||||
AND r.user_id = o.id
|
AND r.user_id = o.id
|
||||||
AND r.user_id = :owner_id
|
AND i.issue_id = :issue_id;
|
||||||
AND i.confirm_hash IS NOT NULL;
|
--AND i.confirm_hash IS NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- :name owner-issues-list :? :*
|
-- :name owner-issues-list :? :*
|
||||||
-- :doc owner's bounty issues with no merged PR
|
-- :doc owner's bounty issues with no merged PR
|
||||||
|
@ -353,8 +384,7 @@ SELECT
|
||||||
i.issue_number AS issue_number,
|
i.issue_number AS issue_number,
|
||||||
i.balance AS balance,
|
i.balance AS balance,
|
||||||
r.login AS login,
|
r.login AS login,
|
||||||
r.repo AS repo,
|
r.repo AS repo
|
||||||
i.state AS state
|
|
||||||
FROM issues i, repositories r
|
FROM issues i, repositories r
|
||||||
WHERE i.issue_number = :issue_number
|
WHERE i.issue_number = :issue_number
|
||||||
AND r.repo_id = i.repo_id
|
AND r.repo_id = i.repo_id
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/owner-bounties-list con-db {:owner_id owner})))
|
(db/owner-bounties-list con-db {:owner_id owner})))
|
||||||
|
|
||||||
|
(defn bounty-claims
|
||||||
|
[issue-id]
|
||||||
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
|
(db/bounty-claims con-db {
|
||||||
|
:issue_id issue-id})))
|
||||||
|
|
||||||
(defn list-not-fixed-issues
|
(defn list-not-fixed-issues
|
||||||
[owner-id]
|
[owner-id]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
:issue_number issue-number
|
:issue_number issue-number
|
||||||
:title issue-title})))
|
:title issue-title})))
|
||||||
|
|
||||||
(defn close
|
(defn update-commit-id
|
||||||
"Updates issue with commit_id"
|
"Updates issue with commit_id"
|
||||||
[commit-id issue-id]
|
[commit-id issue-id]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/close-issue! con-db {:issue_id issue-id :commit_id commit-id})))
|
(db/update-commit-id con-db {:issue_id issue-id
|
||||||
|
:commit_id commit-id})))
|
||||||
|
|
||||||
(defn update-transaction-hash
|
(defn update-transaction-hash
|
||||||
"Updates issue with transaction-hash"
|
"Updates issue with transaction-hash"
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
:opened 0
|
:opened 0
|
||||||
:merged 1
|
:merged 1
|
||||||
:closed 2)]
|
:closed 2)]
|
||||||
(log/debug (assoc pull-request :state state))
|
|
||||||
|
(log/debug "save pr" (assoc pull-request :state state))
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/save-pull-request! con-db
|
(db/save-pull-request! con-db
|
||||||
(assoc pull-request :state state)))))
|
(assoc pull-request :state state)))))
|
||||||
|
|
|
@ -90,6 +90,19 @@
|
||||||
github-repos))))
|
github-repos))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn user-bounties [user]
|
||||||
|
(let [owner-bounties (bounties-db/list-owner-bounties (:id user))]
|
||||||
|
owner-bounties
|
||||||
|
(into {}
|
||||||
|
(for [b owner-bounties]
|
||||||
|
[(:issue_id b)
|
||||||
|
(conj b
|
||||||
|
(let [claims (bounties-db/bounty-claims (:issue_id b))
|
||||||
|
balance (:balance b)]
|
||||||
|
{:balance-eth (eth/hex->eth balance 6)
|
||||||
|
:claims claims}))]))))
|
||||||
|
|
||||||
|
|
||||||
(defapi service-routes
|
(defapi service-routes
|
||||||
{:swagger {:ui "/swagger-ui"
|
{:swagger {:ui "/swagger-ui"
|
||||||
:spec "/swagger.json"
|
:spec "/swagger.json"
|
||||||
|
@ -134,21 +147,22 @@
|
||||||
(POST "/bounty/:issue{[0-9]{1,9}}/payout" {:keys [params]}
|
(POST "/bounty/:issue{[0-9]{1,9}}/payout" {:keys [params]}
|
||||||
:auth-rules authenticated?
|
:auth-rules authenticated?
|
||||||
:current-user user
|
:current-user user
|
||||||
(let [{issue :issue
|
(do
|
||||||
payout-hash :payout-hash} params
|
(log/debug "/bounty/X/payout" params)
|
||||||
result (bounties-db/update-payout-hash
|
(let [{issue :issue
|
||||||
(Integer/parseInt issue)
|
payout-hash :payout-hash} params
|
||||||
payout-hash)]
|
result (bounties-db/update-payout-hash
|
||||||
(if (= 1 result)
|
(Integer/parseInt issue)
|
||||||
(ok)
|
payout-hash)]
|
||||||
(internal-server-error))))
|
(log/debug "result" result)
|
||||||
|
(if (= 1 result)
|
||||||
|
(ok)
|
||||||
|
(internal-server-error)))))
|
||||||
(GET "/bounties" []
|
(GET "/bounties" []
|
||||||
:auth-rules authenticated?
|
:auth-rules authenticated?
|
||||||
:current-user user
|
:current-user user
|
||||||
(log/debug "/user/bounties")
|
(log/debug "/user/bounties")
|
||||||
(ok (map #(conj % (let [balance (:balance %)]
|
(ok (user-bounties user)))
|
||||||
{:balance-eth (eth/hex->eth balance 6)}))
|
|
||||||
(bounties-db/list-owner-bounties (:id user)))))
|
|
||||||
(POST "/repository/toggle" {:keys [params]}
|
(POST "/repository/toggle" {:keys [params]}
|
||||||
:auth-rules authenticated?
|
:auth-rules authenticated?
|
||||||
:current-user user
|
:current-user user
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
[commiteth.util.digest :refer [hex-hmac-sha1]]
|
[commiteth.util.digest :refer [hex-hmac-sha1]]
|
||||||
[compojure.core :refer [defroutes POST]]
|
[compojure.core :refer [defroutes POST]]
|
||||||
[crypto.equality :as crypto]
|
[crypto.equality :as crypto]
|
||||||
[ring.util.http-response :refer [ok]])
|
[ring.util.http-response :refer [ok]]
|
||||||
|
[commiteth.db.bounties :as bounties-db])
|
||||||
(:import java.lang.Integer))
|
(:import java.lang.Integer))
|
||||||
|
|
||||||
(defn find-issue-event
|
(defn find-issue-event
|
||||||
|
@ -51,13 +52,20 @@
|
||||||
|
|
||||||
(defn handle-issue-closed
|
(defn handle-issue-closed
|
||||||
;; TODO: does not work in case the issue is closed on github web ui
|
;; TODO: does not work in case the issue is closed on github web ui
|
||||||
[{{{user :login} :owner repo :name} :repository
|
[{{{owner :login} :owner repo :name} :repository
|
||||||
{issue-id :id issue-number :number} :issue}]
|
{issue-id :id issue-number :number} :issue}]
|
||||||
(log/debug "handle-issue-closed")
|
(log/debug "handle-issue-closed" owner repo issue-number issue-id)
|
||||||
(future
|
(when-let [commit-id (find-commit-id owner repo issue-number ["referenced" "closed"])]
|
||||||
(when-let [commit-id (find-commit-id user repo issue-number ["referenced" "closed"])]
|
(log/debug (format "Issue %s/%s/%s closed with commit %s" owner repo issue-number commit-id))
|
||||||
(log/debug (format "Issue %s/%s/%s closed with commit %s" user repo issue-number commit-id))
|
(log/info "NOT considering event as bounty winner")
|
||||||
(issues/close commit-id issue-id))))
|
;; TODO: disabled for now since the system is meant to be used
|
||||||
|
;; exclusively via pull requests. issue closed event without a PR
|
||||||
|
;; closed via merge first means that the referencing commit was
|
||||||
|
;; pushed directly to master and thus never accepted by the
|
||||||
|
;; maintainer (could be that the bounty hunter had write access
|
||||||
|
;; to master, but that scenario should be very rare and better
|
||||||
|
;; not to support it)
|
||||||
|
#_(issues/close commit-id issue-id)))
|
||||||
|
|
||||||
(def ^:const keywords
|
(def ^:const keywords
|
||||||
[#"(?i)close:?\s+#(\d+)"
|
[#"(?i)close:?\s+#(\d+)"
|
||||||
|
@ -109,6 +117,8 @@
|
||||||
avatar_url :avatar_url
|
avatar_url :avatar_url
|
||||||
name :name} :user
|
name :name} :user
|
||||||
id :id
|
id :id
|
||||||
|
merged? :merged
|
||||||
|
{head-sha :sha} :head
|
||||||
pr-number :number
|
pr-number :number
|
||||||
pr-body :body
|
pr-body :body
|
||||||
pr-title :title} :pull_request}]
|
pr-title :title} :pull_request}]
|
||||||
|
@ -118,34 +128,39 @@
|
||||||
(extract-issue-number pr-body pr-title)
|
(extract-issue-number pr-body pr-title)
|
||||||
(first)
|
(first)
|
||||||
(ensure-bounty-issue owner repo))]
|
(ensure-bounty-issue owner repo))]
|
||||||
(log/debug "Referenced bounty issue found" bounty-issue-number)
|
(log/debug "Referenced bounty issue found" repo bounty-issue-number)
|
||||||
(users/create-user user-id login name nil avatar_url nil)
|
(users/create-user user-id login name nil avatar_url nil)
|
||||||
(let [pr-data {:repo_id repo-id
|
(let [issue (github/get-issue owner repo bounty-issue-number)
|
||||||
|
pr-data {:repo_id repo-id
|
||||||
:pr_id id
|
:pr_id id
|
||||||
:pr_number pr-number
|
:pr_number pr-number
|
||||||
:user_id user-id
|
:user_id user-id
|
||||||
:issue_number bounty-issue-number
|
:issue_number bounty-issue-number
|
||||||
|
:issue_id (:id issue)
|
||||||
:state event-type}]
|
:state event-type}]
|
||||||
|
|
||||||
|
;; TODO: in the opened case if the submitting user has no
|
||||||
|
;; Ethereum address stored, we could post a comment to the
|
||||||
|
;; Github PR explaining that payout is not possible if the PR is
|
||||||
|
;; merged
|
||||||
(case event-type
|
(case event-type
|
||||||
:opened (do
|
:opened (do
|
||||||
(log/info "PR with reference to bounty issue"
|
(log/info "PR with reference to bounty issue"
|
||||||
bounty-issue-number "opened")
|
bounty-issue-number "opened")
|
||||||
(pull-requests/save (merge pr-data {:state :opened
|
(pull-requests/save (merge pr-data {:state :opened
|
||||||
:commit_id nil})))
|
:commit_id head-sha})))
|
||||||
:closed (if-let [commit-id (find-commit-id owner
|
:closed (if merged?
|
||||||
repo
|
|
||||||
pr-number
|
|
||||||
["merged"])]
|
|
||||||
(do (log/info "PR with reference to bounty issue"
|
(do (log/info "PR with reference to bounty issue"
|
||||||
bounty-issue-number "merged")
|
bounty-issue-number "merged")
|
||||||
(pull-requests/save
|
(pull-requests/save
|
||||||
(merge pr-data {:state :merged
|
(merge pr-data {:state :merged
|
||||||
:commit_id commit-id})))
|
:commit_id head-sha}))
|
||||||
|
(issues/update-commit-id head-sha (:id issue)))
|
||||||
(do (log/info "PR with reference to bounty issue"
|
(do (log/info "PR with reference to bounty issue"
|
||||||
bounty-issue-number "closed with no merge")
|
bounty-issue-number "closed with no merge")
|
||||||
(pull-requests/save
|
(pull-requests/save
|
||||||
(merge pr-data {:state :closed
|
(merge pr-data {:state :closed
|
||||||
:commit_id nil}))))))))
|
:commit_id head-sha}))))))))
|
||||||
|
|
||||||
|
|
||||||
(defn handle-issue
|
(defn handle-issue
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
(when-let [confirm-hash (wallet/find-confirmation-hash receipt)]
|
(when-let [confirm-hash (wallet/find-confirmation-hash receipt)]
|
||||||
(db-bounties/update-confirm-hash issue-id confirm-hash)))))
|
(db-bounties/update-confirm-hash issue-id confirm-hash)))))
|
||||||
|
|
||||||
(defn update-payout-hash
|
(defn update-payout-receipt
|
||||||
"Gets transaction receipt for each confirmed payout and updates payout_hash"
|
"Gets transaction receipt for each confirmed payout and updates payout_hash"
|
||||||
[]
|
[]
|
||||||
(doseq [{issue-id :issue_id
|
(doseq [{issue-id :issue_id
|
||||||
|
@ -68,7 +68,9 @@
|
||||||
(log/debug "confirmed payout:" payout-hash)
|
(log/debug "confirmed payout:" payout-hash)
|
||||||
(when-let [receipt (eth/get-transaction-receipt payout-hash)]
|
(when-let [receipt (eth/get-transaction-receipt payout-hash)]
|
||||||
(log/info "payout receipt for issue #" issue-id ": " receipt)
|
(log/info "payout receipt for issue #" issue-id ": " receipt)
|
||||||
(db-bounties/update-payout-receipt issue-id receipt))))
|
;;TODO: not sure if saving the transaction-receipt clojure map as
|
||||||
|
;; a string is a good idea
|
||||||
|
(db-bounties/update-payout-receipt issue-id (str receipt)))))
|
||||||
|
|
||||||
(defn update-balance
|
(defn update-balance
|
||||||
[]
|
[]
|
||||||
|
@ -137,7 +139,7 @@
|
||||||
:start (restart-scheduler 60000
|
:start (restart-scheduler 60000
|
||||||
[update-issue-contract-address
|
[update-issue-contract-address
|
||||||
update-confirm-hash
|
update-confirm-hash
|
||||||
update-payout-hash
|
update-payout-receipt
|
||||||
self-sign-bounty
|
self-sign-bounty
|
||||||
update-balance])
|
update-balance])
|
||||||
:stop (stop-scheduler))
|
:stop (stop-scheduler))
|
||||||
|
|
|
@ -1,7 +1,63 @@
|
||||||
(ns commiteth.bounties
|
(ns commiteth.bounties
|
||||||
(:require [re-frame.core :as rf]))
|
(:require [re-frame.core :as rf]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn pr-url [{owner :owner_login
|
||||||
|
pr-number :pr_number
|
||||||
|
repo :repo_name}]
|
||||||
|
(str "https://github.com/" owner "/" repo "/pull/" pr-number))
|
||||||
|
|
||||||
|
(defn claim-card [claim]
|
||||||
|
(let [{pr-state :pr_state
|
||||||
|
user-name :user_name
|
||||||
|
avatar-url :user_avatar_url
|
||||||
|
issue-id :issue_id
|
||||||
|
issue-title :issue_title} claim
|
||||||
|
merged? (= 1 (:pr_state claim))
|
||||||
|
paid? ((comp not nil?) (:payout_hash claim))]
|
||||||
|
(println "paid?" paid? "merged?" merged? (and merged? (comp not) paid?))
|
||||||
|
[:div.activity-item
|
||||||
|
[:div.ui.grid.container
|
||||||
|
[:div.left-column
|
||||||
|
[:div.ui.circular.image
|
||||||
|
[:img {:src avatar-url}]]]
|
||||||
|
[:div.content
|
||||||
|
[:div.header user-name]
|
||||||
|
[:div.description "Submitted a claim for " [:a {:href (pr-url claim)}
|
||||||
|
issue-title]]
|
||||||
|
[:div.description (if paid?
|
||||||
|
"(paid)"
|
||||||
|
(str "(" (if merged? "merged" "open") ")"))]
|
||||||
|
[:div.time "1 day ago"] ;; TODO: claim timestamp
|
||||||
|
[:button.ui.button
|
||||||
|
(merge (if (and merged? (not paid?))
|
||||||
|
{}
|
||||||
|
{:disabled true})
|
||||||
|
{:on-click #(rf/dispatch [:confirm-payout claim])})
|
||||||
|
(if paid?
|
||||||
|
"Signed off"
|
||||||
|
"Confirm")]]]]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn claim-list [bounties]
|
||||||
|
(into [:div.activity-item-container]
|
||||||
|
(for [b (keys bounties)
|
||||||
|
claim (:claims (get bounties b))]
|
||||||
|
[claim-card claim])))
|
||||||
|
|
||||||
|
|
||||||
(defn bounties-page []
|
(defn bounties-page []
|
||||||
(fn []
|
(let [owner-bounties (rf/subscribe [:owner-bounties])]
|
||||||
[:div.ui.container
|
(fn []
|
||||||
[:div.ui.text "Bounties view coming soon"]]))
|
(let [paid-out? #(nil? (:payout_hash %))
|
||||||
|
paid-bounties (into {} (filter paid-out?
|
||||||
|
@owner-bounties))
|
||||||
|
unpaid-bounties (into {} (filter (comp not paid-out?)
|
||||||
|
@owner-bounties))]
|
||||||
|
(println "unpaid-bounties" unpaid-bounties)
|
||||||
|
[:div.ui.container
|
||||||
|
[:h3 "New claims"]
|
||||||
|
[claim-list unpaid-bounties]
|
||||||
|
[:h3 "Old claims"]
|
||||||
|
[claim-list paid-bounties]]))))
|
||||||
|
|
|
@ -175,11 +175,7 @@
|
||||||
:token js/token}]))
|
:token js/token}]))
|
||||||
(reset! active-user nil)))
|
(reset! active-user nil)))
|
||||||
|
|
||||||
(defn load-issues []
|
|
||||||
(rf/dispatch [:load-bounties]))
|
|
||||||
|
|
||||||
(defn load-data []
|
(defn load-data []
|
||||||
(load-issues)
|
|
||||||
(load-user))
|
(load-user))
|
||||||
|
|
||||||
(defonce timer-id (r/atom nil))
|
(defonce timer-id (r/atom nil))
|
||||||
|
|
|
@ -5,12 +5,7 @@
|
||||||
:user nil
|
:user nil
|
||||||
:repos-loading? false
|
:repos-loading? false
|
||||||
:repos {}
|
:repos {}
|
||||||
:all-bounties []
|
:owner-bounties {}
|
||||||
:owner-bounties []
|
|
||||||
:error nil
|
|
||||||
:pagination {}
|
|
||||||
:pagination-props {:page-size 10
|
|
||||||
:pages-max 10}
|
|
||||||
:top-hunters [{:profile-image-url "https://randomuser.me/api/portraits/men/4.jpg"
|
:top-hunters [{:profile-image-url "https://randomuser.me/api/portraits/men/4.jpg"
|
||||||
:display-name "Place Holder"
|
:display-name "Place Holder"
|
||||||
:eth-earned "11 000.00"}
|
:eth-earned "11 000.00"}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
(:require [commiteth.db :as db]
|
(:require [commiteth.db :as db]
|
||||||
[re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx]]
|
[re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx]]
|
||||||
[ajax.core :refer [GET POST]]
|
[ajax.core :refer [GET POST]]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]
|
||||||
|
[plumbing.core :refer [dissoc-in]]))
|
||||||
|
|
||||||
(reg-fx
|
(reg-fx
|
||||||
:http
|
:http
|
||||||
|
@ -59,14 +60,6 @@
|
||||||
(fn [db [_ table page]]
|
(fn [db [_ table page]]
|
||||||
(assoc-in db [:pagination table :page] page)))
|
(assoc-in db [:pagination table :page] page)))
|
||||||
|
|
||||||
(reg-event-db
|
|
||||||
:init-pagination
|
|
||||||
(fn [db [_ bounties]]
|
|
||||||
(let [{page-size :page-size} (:pagination-props db)]
|
|
||||||
(assoc-in db [:pagination :all-bounties]
|
|
||||||
{:page 0
|
|
||||||
:pages (Math/ceil (/ (count bounties) page-size))}))))
|
|
||||||
|
|
||||||
(reg-event-fx
|
(reg-event-fx
|
||||||
:set-active-user
|
:set-active-user
|
||||||
(fn [{:keys [db]} [_ user]]
|
(fn [{:keys [db]} [_ user]]
|
||||||
|
@ -79,13 +72,6 @@
|
||||||
{:db (assoc db :user nil)
|
{:db (assoc db :user nil)
|
||||||
:redirect {:path "/logout"}}))
|
:redirect {:path "/logout"}}))
|
||||||
|
|
||||||
(reg-event-fx
|
|
||||||
:load-bounties
|
|
||||||
(fn [{:keys [db]} [_]]
|
|
||||||
{:db db
|
|
||||||
:http {:method GET
|
|
||||||
:url "/api/bounties/all"
|
|
||||||
:on-success #(dispatch [:set-bounties %])}}))
|
|
||||||
|
|
||||||
(reg-event-fx
|
(reg-event-fx
|
||||||
:save-payout-hash
|
:save-payout-hash
|
||||||
|
@ -93,14 +79,10 @@
|
||||||
{:db db
|
{:db db
|
||||||
:http {:method POST
|
:http {:method POST
|
||||||
:url (str/format "/api/user/bounty/%s/payout" issue-id)
|
:url (str/format "/api/user/bounty/%s/payout" issue-id)
|
||||||
:on-success #(println %)
|
:on-success #(dispatch [:payout-confirmed issue-id])
|
||||||
|
:on-error #(dispatch [:payout-confirm-failed issue-id])
|
||||||
:params {:payout-hash payout-hash}}}))
|
:params {:payout-hash payout-hash}}}))
|
||||||
|
|
||||||
(reg-event-fx
|
|
||||||
:set-bounties
|
|
||||||
(fn [{:keys [db]} [_ bounties]]
|
|
||||||
{:db (assoc db :all-bounties bounties)
|
|
||||||
:dispatch [:init-pagination bounties]}))
|
|
||||||
|
|
||||||
(reg-event-fx
|
(reg-event-fx
|
||||||
:load-owner-bounties
|
:load-owner-bounties
|
||||||
|
@ -221,3 +203,54 @@
|
||||||
:clear-updating-address
|
:clear-updating-address
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
(dissoc db :updating-address)))
|
(dissoc db :updating-address)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn send-transaction-callback
|
||||||
|
[issue-id]
|
||||||
|
(println "send-transaction-callback")
|
||||||
|
(fn [error payout-hash]
|
||||||
|
(println "send-transaction-callback fn")
|
||||||
|
(when error
|
||||||
|
(dispatch [:set-flash-message
|
||||||
|
:error
|
||||||
|
(str "Error sending transaction: " error)]))
|
||||||
|
(when payout-hash
|
||||||
|
(dispatch [:save-payout-hash issue-id payout-hash]))))
|
||||||
|
|
||||||
|
|
||||||
|
(reg-event-fx
|
||||||
|
:confirm-payout
|
||||||
|
(fn [{:keys [db]} [_ {issue-id :issue_id
|
||||||
|
owner-address :owner_address
|
||||||
|
contract-address :contract_address
|
||||||
|
confirm-hash :confirm_hash} issue]]
|
||||||
|
(let [send-transaction-fn (aget js/web3 "eth" "sendTransaction")
|
||||||
|
payload {:from owner-address
|
||||||
|
:to contract-address
|
||||||
|
:value 1
|
||||||
|
:data (str "0x797af627" confirm-hash)}]
|
||||||
|
(println "confirm-payout" owner-address to)
|
||||||
|
(try
|
||||||
|
(apply send-transaction-fn [(clj->js payload)
|
||||||
|
(send-transaction-callback issue-id)])
|
||||||
|
{:db (assoc-in db [:owner-bounties issue-id :confirming?] true)}
|
||||||
|
(catch js/Error e
|
||||||
|
{:db (assoc-in db [:owner-bounties issue-id :confirm-failed?] true)
|
||||||
|
:dispatch [:set-flash-message
|
||||||
|
:error
|
||||||
|
(str "Failed to send transaction" e)]})))))
|
||||||
|
|
||||||
|
(reg-event-db
|
||||||
|
:payout-confirmed
|
||||||
|
(fn [db [_ issue-id]]
|
||||||
|
(-> db
|
||||||
|
(dissoc-in [:owner-bounties (:issue_id issue) :confirming?] false)
|
||||||
|
(assoc-in [:owner-bounties (:issue_id issue) :confirmed?] true))))
|
||||||
|
|
||||||
|
(reg-event-db
|
||||||
|
:payout-confirm-failed
|
||||||
|
(fn [db [_ issue-id]]
|
||||||
|
(-> db
|
||||||
|
(dissoc-in [:owner-bounties (:issue_id issue) :confirming?] false)
|
||||||
|
(assoc-in [:owner-bounties (:issue_id issue) :confirm-failed?] true))))
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
(ns commiteth.issues
|
|
||||||
(:require [reagent.core :as r]
|
|
||||||
[re-frame.core :as rf]))
|
|
||||||
|
|
||||||
(defn- page-btn
|
|
||||||
[table selected-page current-page]
|
|
||||||
^{:key current-page}
|
|
||||||
[:a {:class (when (= selected-page current-page) "current")
|
|
||||||
:on-click #(rf/dispatch [:set-page table current-page])}
|
|
||||||
(str (inc current-page))])
|
|
||||||
|
|
||||||
(defn pagination [table]
|
|
||||||
(fn []
|
|
||||||
(let [{page :page
|
|
||||||
pages :pages} @(rf/subscribe [:pagination table])
|
|
||||||
{pages-max :pages-max} @(rf/subscribe [:get-in [:pagination-props]])]
|
|
||||||
(when (> pages 1)
|
|
||||||
(let [last-page (dec pages)
|
|
||||||
start-page (max 1 (min (- pages pages-max) (max 1 (- page (quot pages-max 2)))))
|
|
||||||
end-page (min (dec pages) (+ pages-max start-page))
|
|
||||||
gap-left (> start-page 1)
|
|
||||||
gap-right (< end-page last-page)]
|
|
||||||
[:div.paginate-container
|
|
||||||
[:div.pagination
|
|
||||||
[:span.previous-page
|
|
||||||
(let [disabled (= page 0)]
|
|
||||||
{:class (when disabled "disabled")
|
|
||||||
:on-click (when-not disabled
|
|
||||||
#(rf/dispatch [:set-page table (dec page)]))})
|
|
||||||
"Previous"]
|
|
||||||
(page-btn table page 0)
|
|
||||||
(when gap-left [:span.gap "…"])
|
|
||||||
(map #(page-btn table page %) (range start-page end-page))
|
|
||||||
(when gap-right [:span.gap "…"])
|
|
||||||
(page-btn table page last-page)
|
|
||||||
[:span.next-page
|
|
||||||
(let [disabled (= page last-page)]
|
|
||||||
{:class (when disabled "disabled")
|
|
||||||
:on-click (when-not disabled
|
|
||||||
#(rf/dispatch [:set-page table (inc page)]))})
|
|
||||||
"Next"]]])))))
|
|
||||||
|
|
||||||
(defn repo-link
|
|
||||||
[owner repo]
|
|
||||||
(let [coordinates (str owner "/" repo)
|
|
||||||
url (str "https://github.com/" coordinates)]
|
|
||||||
[:span
|
|
||||||
[:svg.octicon.octicon-repo {:height "16"
|
|
||||||
:version "1.1"
|
|
||||||
:viewBox "0 0 16 16"
|
|
||||||
:width "16"}
|
|
||||||
[:path {:d "M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z"}]]
|
|
||||||
[:a.text-gray {:href url} coordinates]]))
|
|
||||||
|
|
||||||
(defn issue-url
|
|
||||||
[owner repo issue-number]
|
|
||||||
(str "https://github.com/" owner "/" repo "/issues/" issue-number))
|
|
||||||
|
|
||||||
(defn issue-row [{title :issue_title
|
|
||||||
issue-id :issue_id
|
|
||||||
issue-number :issue_number
|
|
||||||
owner :owner_name
|
|
||||||
repo :repo_name}]
|
|
||||||
^{:key issue-id}
|
|
||||||
[:li.issue
|
|
||||||
[:div.d-table.table-fixed.width-full
|
|
||||||
[:div.float-left.pt-3.pl-3
|
|
||||||
[:span.tooltipped.tooltipped-n
|
|
||||||
{:aria-label "Open issue"}
|
|
||||||
[:svg.octicon.octicon-issue-opened.open
|
|
||||||
{:aria-hidden "true",
|
|
||||||
:height "16",
|
|
||||||
:version "1.1",
|
|
||||||
:viewBox "0 0 14 16",
|
|
||||||
:width "14"}
|
|
||||||
[:path
|
|
||||||
{:d
|
|
||||||
"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}]]]]
|
|
||||||
[:div.float-left.col-9.p-3.lh-condensed
|
|
||||||
[:a.box-row-link.h4
|
|
||||||
{:href (issue-url owner repo issue-number)} title]
|
|
||||||
[:span.gh-header-number
|
|
||||||
(str " #" issue-number)]
|
|
||||||
[:div.mt-1.text-small.text-gray
|
|
||||||
(repo-link owner repo)]]]])
|
|
||||||
|
|
||||||
(defn issues-list-table
|
|
||||||
[issues-path issue-row-fn]
|
|
||||||
(fn []
|
|
||||||
(let [{page :page} @(rf/subscribe (into [:pagination] issues-path))
|
|
||||||
{page-size :page-size} @(rf/subscribe [:get-in [:pagination-props]])
|
|
||||||
issues (rf/subscribe issues-path)
|
|
||||||
issues-page (->> @issues
|
|
||||||
(drop (* page page-size))
|
|
||||||
(take page-size))]
|
|
||||||
[:div.issues-list-table
|
|
||||||
[:ul.issues-list
|
|
||||||
(map issue-row-fn issues-page)]])))
|
|
||||||
|
|
||||||
(defn issues-page []
|
|
||||||
(fn []
|
|
||||||
[:div.container
|
|
||||||
[(issues-list-table [:all-bounties] issue-row)]
|
|
||||||
[(pagination :all-bounties)]]))
|
|
|
@ -1,127 +0,0 @@
|
||||||
(ns commiteth.manage
|
|
||||||
(:require [re-frame.core :as rf]
|
|
||||||
[commiteth.common :refer [input]]
|
|
||||||
[commiteth.issues :refer [issues-list-table issue-url]]
|
|
||||||
[clojure.set :refer [rename-keys]]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn repository-row [repo]
|
|
||||||
(let [{repo-id :id
|
|
||||||
url :html_url
|
|
||||||
name :full_name
|
|
||||||
description :description} repo]
|
|
||||||
^{:key repo-id}
|
|
||||||
[:div.d-table.width-full
|
|
||||||
[:div.d-table.col-12.width-full.py-4.border-bottom.issue
|
|
||||||
#_[checkbox {:value-path [:enabled-repos repo-id]
|
|
||||||
:style {:width 32 :margin-left 10}
|
|
||||||
:on-change #(rf/dispatch [:toggle-repo repo])}]
|
|
||||||
[:div.d-table-cell.col-11.pr-3.v-align-top
|
|
||||||
[:h4.f4
|
|
||||||
[:a {:href url} name]]
|
|
||||||
[:p.text-gray.mt-1 description]]]]))
|
|
||||||
|
|
||||||
(defn repos-list []
|
|
||||||
(let [repos-loading? (rf/subscribe [:repos-loading?])
|
|
||||||
repos (rf/subscribe [:repos])]
|
|
||||||
(fn []
|
|
||||||
[:div
|
|
||||||
(if @repos-loading?
|
|
||||||
[:i.fa.fa-spinner.fa-spin]
|
|
||||||
(map repository-row @repos))])))
|
|
||||||
|
|
||||||
(defn enable-disable-button
|
|
||||||
[button-id disable]
|
|
||||||
(let [button (.getElementById js/document button-id)]
|
|
||||||
(set! (.-disabled button) disable)))
|
|
||||||
|
|
||||||
(defn lock-button
|
|
||||||
[issue-id]
|
|
||||||
(enable-disable-button (str "payout" issue-id) "true"))
|
|
||||||
|
|
||||||
(defn unlock-button
|
|
||||||
[issue-id]
|
|
||||||
(enable-disable-button (str "payout" issue-id) nil))
|
|
||||||
|
|
||||||
(defn send-transaction-callback
|
|
||||||
[issue-id]
|
|
||||||
(fn [error payout-hash]
|
|
||||||
(when error
|
|
||||||
(unlock-button issue-id)
|
|
||||||
(rf/dispatch [:set-error (str "Error sending transaction: " error)]))
|
|
||||||
(when payout-hash
|
|
||||||
(rf/dispatch [:save-payout-hash issue-id payout-hash]))))
|
|
||||||
|
|
||||||
(defn send-transaction
|
|
||||||
[issue]
|
|
||||||
(fn []
|
|
||||||
(let [{issue-id :issue_id
|
|
||||||
owner-address :owner_address
|
|
||||||
contract-address :contract_address
|
|
||||||
confirm-hash :confirm_hash} issue
|
|
||||||
send-transaction-fn (aget js/web3 "eth" "sendTransaction")
|
|
||||||
payload {:from owner-address
|
|
||||||
:to contract-address
|
|
||||||
:value 1
|
|
||||||
:data (str "0x797af627" confirm-hash)}]
|
|
||||||
(println "sending transaction" payload)
|
|
||||||
(lock-button issue-id)
|
|
||||||
(try
|
|
||||||
(apply send-transaction-fn [(clj->js payload) (send-transaction-callback issue-id)])
|
|
||||||
(catch js/Error e (do
|
|
||||||
(unlock-button issue-id)
|
|
||||||
(rf/dispatch [:set-error e])))))))
|
|
||||||
|
|
||||||
(defn issue-row [{title :issue_title
|
|
||||||
issue-id :issue_id
|
|
||||||
issue-number :issue_number
|
|
||||||
owner :owner_name
|
|
||||||
repo :repo_name
|
|
||||||
balance :balance-eth
|
|
||||||
payout-hash :payout_hash
|
|
||||||
payout-receipt :payout_receipt
|
|
||||||
:as issue}]
|
|
||||||
^{:key issue-id}
|
|
||||||
[:li.issue
|
|
||||||
[:div.d-table.table-fixed.width-full
|
|
||||||
[:div.float-left.pt-3.pl-3
|
|
||||||
[:span.tooltipped.tooltipped-n
|
|
||||||
{:aria-label "Closed issue"}
|
|
||||||
[:svg.octicon.octicon-issue-closed.closed
|
|
||||||
{:aria-hidden "true",
|
|
||||||
:height "16",
|
|
||||||
:version "1.1",
|
|
||||||
:viewBox "0 0 14 16",
|
|
||||||
:width "14"}
|
|
||||||
[:path
|
|
||||||
{:d
|
|
||||||
"M7 10h2v2H7v-2zm2-6H7v5h2V4zm1.5 1.5l-1 1L12 9l4-4.5-1-1L12 7l-1.5-1.5zM8 13.7A5.71 5.71 0 0 1 2.3 8c0-3.14 2.56-5.7 5.7-5.7 1.83 0 3.45.88 4.5 2.2l.92-.92A6.947 6.947 0 0 0 8 1C4.14 1 1 4.14 1 8s3.14 7 7 7 7-3.14 7-7l-1.52 1.52c-.66 2.41-2.86 4.19-5.48 4.19v-.01z"}]]]]
|
|
||||||
(if payout-receipt
|
|
||||||
[:span.btn-sm.float-right {:disabled true
|
|
||||||
:style {:margin-top "7px"
|
|
||||||
:margin-right "7px"}}
|
|
||||||
(str "Sent " balance " ETH")]
|
|
||||||
[:button.btn.btn-sm.btn-danger.float-right
|
|
||||||
{:id (str "payout" issue-id)
|
|
||||||
:type "submit"
|
|
||||||
:style {:margin-top "7px"
|
|
||||||
:margin-right "7px"}
|
|
||||||
:disabled (or payout-hash (not (exists? js/web3)))
|
|
||||||
:on-click (send-transaction issue)}
|
|
||||||
(str "Send " balance " ETH")])
|
|
||||||
[:div.float-left.col-9.p-3.lh-condensed
|
|
||||||
[:span.mr-2.float-right.text-gray.text-small
|
|
||||||
(str " #" issue-number)]
|
|
||||||
[:a.box-row-link.h4
|
|
||||||
{:href (issue-url owner repo issue-number)} title]]]])
|
|
||||||
|
|
||||||
(defn manage-page []
|
|
||||||
(fn []
|
|
||||||
[:div.container
|
|
||||||
[:h3 "Bounties"]
|
|
||||||
[(issues-list-table [:owner-bounties] issue-row)]
|
|
||||||
[:h3 "Repositories"]
|
|
||||||
[repos-list]]))
|
|
|
@ -23,6 +23,11 @@
|
||||||
&:active,&:focus {
|
&:active,&:focus {
|
||||||
background-color: #97ebe7;
|
background-color: #97ebe7;
|
||||||
}
|
}
|
||||||
|
&:disabled,&:disabled:active {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #2f3f44;
|
||||||
|
border: #e7e7e7 solid 0.1em!important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.ui.small.button {
|
.ui.small.button {
|
||||||
font-size: 15px!important;
|
font-size: 15px!important;
|
||||||
|
@ -59,8 +64,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.mini.circular.image {
|
.ui.mini.circular.image {
|
||||||
height: 35px;
|
height: 32px;
|
||||||
width: 35px!important;
|
width: 32px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.header {
|
.ui.header {
|
||||||
|
@ -193,15 +198,50 @@ span.dropdown.icon {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.activity-item-container {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.activity-item {
|
.activity-item {
|
||||||
|
.left-column {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
width: 100px!important;
|
||||||
|
.ui.image {
|
||||||
|
position: relative;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
border: #e7e7e7 solid 0.1em!important;
|
border: #e7e7e7 solid 0.1em!important;
|
||||||
box-shadow: none!important;
|
box-shadow: none!important;
|
||||||
border-radius: 0.3em!important;
|
border-radius: 0.3em!important;
|
||||||
padding: 0.8em 1em 1.1em!important;
|
padding: 0.8em 1em 1.1em!important;
|
||||||
|
|
||||||
flex-direction: row!important;
|
flex-direction: row!important;
|
||||||
|
margin: 1em;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: .7em 0 1em;
|
||||||
|
font-family: 'postgrotesk';
|
||||||
|
line-height: 2em;
|
||||||
|
min-width: 300px!important;
|
||||||
|
.header {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #474951;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.ui.cards>.card {
|
.ui.cards>.card {
|
||||||
border: #e7e7e7 solid 0.1em;
|
border: #e7e7e7 solid 0.1em;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
Loading…
Reference in New Issue