mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-03 10:40:30 +08:00
Improve commit history and detail view
Signed-off-by: Alexis Sellier <self@cloudhead.io>
This commit is contained in:
@@ -3,14 +3,16 @@
|
||||
"groupDate": "Thursday, March 3, 2022",
|
||||
"commits": [
|
||||
{
|
||||
"sha": "9cd3532",
|
||||
"summary": "Second commit",
|
||||
"description": "",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "Thu, 03 Mar 2022 05:51:25 GMT"
|
||||
"header": {
|
||||
"sha": "9cd3532",
|
||||
"summary": "Second commit",
|
||||
"description": "",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "06:51 GMT+1"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,24 +20,28 @@
|
||||
"groupDate": "Wednesday, March 2, 2022",
|
||||
"commits": [
|
||||
{
|
||||
"sha": "e045b92",
|
||||
"summary": "Update README",
|
||||
"description": "",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "Wed, 02 Mar 2022 16:14:45 GMT"
|
||||
"header": {
|
||||
"sha": "e045b92",
|
||||
"summary": "Update README",
|
||||
"description": "",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "17:14 GMT+1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"sha": "cbf5df4",
|
||||
"summary": "initial commit",
|
||||
"description": "this is the first commit of many",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "Wed, 02 Mar 2022 15:58:05 GMT"
|
||||
"header": {
|
||||
"sha": "cbf5df4",
|
||||
"summary": "initial commit",
|
||||
"description": "this is the first commit of many",
|
||||
"committer": {
|
||||
"name": "dabit3",
|
||||
"mail": "dabit3@gmail.com"
|
||||
},
|
||||
"committerTime": "16:58 GMT+1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"peer": {
|
||||
"id": "hyyg555wwkkutaysg6yr67qnu5d5ji54iur3n5uzzszndh8dp7ofue",
|
||||
"person": {
|
||||
"name": "sebastinez"
|
||||
"name": "dabit3"
|
||||
},
|
||||
"delegate": true
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("Project view", () => {
|
||||
cy.get("div.clone").click();
|
||||
});
|
||||
|
||||
it("Peer selector ", () => {
|
||||
it("Peer selector", () => {
|
||||
cy.get("div.selector").click();
|
||||
cy.get("div.dropdown-item").contains("dabit3 hyndc7nx9keq76p1bkw9831arcndeeu3trwsc7kxt3osmpi6j9oeke delegate").click();
|
||||
cy.location().should((location) => {
|
||||
@@ -54,7 +54,7 @@ describe("Project view", () => {
|
||||
cy.get("div.stat.peer span.badge").should("have.text", "delegate");
|
||||
});
|
||||
|
||||
it("Branch selector ", () => {
|
||||
it("Branch selector", () => {
|
||||
cy.get("div.commit div.stat.branch").click();
|
||||
cy.get("div.dropdown-item")
|
||||
.first()
|
||||
@@ -69,7 +69,7 @@ describe("Project view", () => {
|
||||
cy.get("div.hash.desktop").should("have.text", "cbf5df4");
|
||||
});
|
||||
|
||||
it("Commit button ", () => {
|
||||
it("Commits button", () => {
|
||||
cy.get("div.stat.commit-count")
|
||||
.should("not.have.class", "active")
|
||||
.click();
|
||||
@@ -79,42 +79,37 @@ describe("Project view", () => {
|
||||
cy.get("div.stat.commit-count").should("have.class", "active");
|
||||
});
|
||||
|
||||
it("Commit group & commit trailer ", () => {
|
||||
it("Commit group & commit trailer", () => {
|
||||
cy.fixture("groupedCommits.json").then((commitGroup) => {
|
||||
// This iterates over the commit groups and then over each commit.
|
||||
cy.get("div.commit-group").should("have.length", 2)
|
||||
cy.get(".commit-group").should("have.length", 2)
|
||||
.each((item, index) => {
|
||||
expect(Cypress.$(item.children(".commit-date")).text()).to.eq(commitGroup[index].groupDate);
|
||||
const $el = Cypress.$(item.find(".commit"));
|
||||
const $el = Cypress.$(item.find(".commit-teaser"));
|
||||
cy.wrap($el).each((commit, commitIndex) => {
|
||||
expect(Cypress.$(commit).find(".hash").text()).to.eq(commitGroup[index].commits[commitIndex].sha);
|
||||
expect(Cypress.$(commit).find("span.summary").text()).to.eq(commitGroup[index].commits[commitIndex].summary);
|
||||
expect(Cypress.$(commit).find(".author").text()).to.eq(commitGroup[index].commits[commitIndex].committer.name);
|
||||
expect(Cypress.$(commit).find(".time").text()).to.eq(commitGroup[index].commits[commitIndex].committerTime);
|
||||
expect(Cypress.$(commit).find(".hash").text()).to.eq(commitGroup[index].commits[commitIndex].header.sha);
|
||||
expect(Cypress.$(commit).find(".summary").text()).to.eq(commitGroup[index].commits[commitIndex].header.summary);
|
||||
expect(Cypress.$(commit).find(".committer").text()).to.eq(commitGroup[index].commits[commitIndex].header.committer.name);
|
||||
});
|
||||
});
|
||||
|
||||
// Checking that the initial commit has the Verified badge
|
||||
cy.get(".badge").last().should("have.text", "Verified");
|
||||
cy.get("div.summary").last().click();
|
||||
cy.get(".commit").last().click();
|
||||
});
|
||||
});
|
||||
|
||||
it("Commit detail view ", () => {
|
||||
it("Commit detail view", () => {
|
||||
cy.fixture("groupedCommits.json").then((commitGroup) => {
|
||||
// We get the initial commit from the fixture file to assert here
|
||||
const { committer, committerTime, summary, description } = commitGroup[1].commits[1];
|
||||
const { committer, committerTime, summary, description } = commitGroup[1].commits[1].header;
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.pathname).to.eq('/seeds/willow.radicle.garden/rad:git:hnrk8mbpirp7ua7sy66o4t9soasbq4y8uwgoy/remotes/hyndc7nx9keq76p1bkw9831arcndeeu3trwsc7kxt3osmpi6j9oeke/commits/cbf5df499ab4f4a908f1756fbe2c236a4530516a');
|
||||
});
|
||||
cy.get("header div.summary h3").should("have.text", summary);
|
||||
cy.get("header .summary h3").should("have.text", summary);
|
||||
cy.get("header pre.description").should("have.text", description);
|
||||
cy.get("header div.meta")
|
||||
.first()
|
||||
.should("have.text", `Committed by ${committer.name} <${committer.mail}> ${committerTime}`)
|
||||
.next()
|
||||
.should("have.text", `Authored by ${committer.name} <${committer.mail}>`);
|
||||
cy.get("header .committer").should("have.text", `${committer.name}`);
|
||||
cy.get("div.changeset-summary").should("have.text", "1 file(s) changed\n with\n 0 addition(s)\n and\n 0 deletion(s)");
|
||||
cy.get("header.file-header:nth-child(1) div.file-data > *")
|
||||
.first()
|
||||
|
||||
Generated
+60
-4
@@ -16,6 +16,7 @@
|
||||
"@self.id/core": "^0.1.0",
|
||||
"@stardazed/streams": "^3.1.0",
|
||||
"@types/marked": "^4.0.1",
|
||||
"@types/md5": "^2.3.2",
|
||||
"@walletconnect/client": "^1.6.0",
|
||||
"@walletconnect/signer-connection": "^1.6.0",
|
||||
"@walletconnect/types": "^1.6.0",
|
||||
@@ -27,6 +28,7 @@
|
||||
"ethers": "^5.0.31",
|
||||
"eventemitter3": "4.0.7",
|
||||
"marked": "^4.0.12",
|
||||
"md5": "^2.3.0",
|
||||
"multibase": "^4.0.4",
|
||||
"multihashes": "^4.0.2",
|
||||
"pure-svg-code": "^1.0.6",
|
||||
@@ -3515,6 +3517,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.2.tgz",
|
||||
"integrity": "sha512-auNrZ/c0w6wsM9DccwVxWHssrMDezHUAXNesdp2RQrCVCyrQbOiSq7yqdJKrUQQpw9VTm7CGYJH2A/YG7jjrjQ=="
|
||||
},
|
||||
"node_modules/@types/md5": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.2.tgz",
|
||||
"integrity": "sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "14.18.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.10.tgz",
|
||||
@@ -4999,6 +5006,14 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/check-error": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
|
||||
@@ -5444,6 +5459,14 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-browserify": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
|
||||
@@ -7997,8 +8020,7 @@
|
||||
"node_modules/is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.4",
|
||||
@@ -8953,6 +8975,16 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"dependencies": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
@@ -14795,6 +14827,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.2.tgz",
|
||||
"integrity": "sha512-auNrZ/c0w6wsM9DccwVxWHssrMDezHUAXNesdp2RQrCVCyrQbOiSq7yqdJKrUQQpw9VTm7CGYJH2A/YG7jjrjQ=="
|
||||
},
|
||||
"@types/md5": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.2.tgz",
|
||||
"integrity": "sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.18.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.10.tgz",
|
||||
@@ -15992,6 +16029,11 @@
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
|
||||
},
|
||||
"check-error": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
|
||||
@@ -16358,6 +16400,11 @@
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
|
||||
},
|
||||
"crypto-browserify": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
|
||||
@@ -18209,8 +18256,7 @@
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.2.4",
|
||||
@@ -18918,6 +18964,16 @@
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
|
||||
"integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ=="
|
||||
},
|
||||
"md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"requires": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
|
||||
+4
-1
@@ -8,7 +8,8 @@
|
||||
"coverage": "npx nyc report",
|
||||
"test:unit": "vitest run",
|
||||
"test:components": "cypress run-ct",
|
||||
"test:e2e": "cypress run"
|
||||
"test:e2e": "cypress run",
|
||||
"test:e2e:open": "cypress open"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
@@ -46,6 +47,7 @@
|
||||
"@self.id/core": "^0.1.0",
|
||||
"@stardazed/streams": "^3.1.0",
|
||||
"@types/marked": "^4.0.1",
|
||||
"@types/md5": "^2.3.2",
|
||||
"@walletconnect/client": "^1.6.0",
|
||||
"@walletconnect/signer-connection": "^1.6.0",
|
||||
"@walletconnect/types": "^1.6.0",
|
||||
@@ -57,6 +59,7 @@
|
||||
"ethers": "^5.0.31",
|
||||
"eventemitter3": "4.0.7",
|
||||
"marked": "^4.0.12",
|
||||
"md5": "^2.3.0",
|
||||
"multibase": "^4.0.4",
|
||||
"multihashes": "^4.0.2",
|
||||
"pure-svg-code": "^1.0.6",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import * as proj from "@app/project";
|
||||
import Changeset from "@app/base/projects/SourceBrowser/Changeset.svelte";
|
||||
import { formatCommitTime } from "@app/commit";
|
||||
import { formatCommit } from "@app/utils";
|
||||
|
||||
import Changeset from "@app/base/projects/SourceBrowser/Changeset.svelte";
|
||||
import CommitAuthorship from "@app/base/projects/Commit/CommitAuthorship.svelte";
|
||||
|
||||
export let project: proj.Project;
|
||||
export let commit: string;
|
||||
|
||||
@@ -19,7 +20,6 @@
|
||||
<style>
|
||||
.commit {
|
||||
padding: 0 2rem 0 8rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
h3 {
|
||||
margin: 0;
|
||||
@@ -38,21 +38,19 @@
|
||||
.description {
|
||||
margin: 0.5rem 0 1rem 0;
|
||||
}
|
||||
.meta {
|
||||
color: var(--color-foreground-80);
|
||||
}
|
||||
.email {
|
||||
font-family: var(--font-family-monospace);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.sha1 {
|
||||
color: var(--color-foreground-80);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.time {
|
||||
margin-left: 0.25rem;
|
||||
color: var(--color-foreground-faded);
|
||||
.badge {
|
||||
margin: 0;
|
||||
}
|
||||
.authorship {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.commit {
|
||||
padding-left: 2rem;
|
||||
@@ -68,19 +66,16 @@
|
||||
<div class="desktop font-mono sha1">
|
||||
<span>{commit.header.sha1}</span>
|
||||
</div>
|
||||
<div class="mobile font-mono sha1">
|
||||
<div class="mobile font-mono sha1 text-small">
|
||||
{formatCommit(commit.header.sha1)}
|
||||
</div>
|
||||
</div>
|
||||
<pre class="description">{commit.header.description}</pre>
|
||||
<div class="meta">
|
||||
<span>Committed by <strong>{commit.header.committer.name}</strong></span>
|
||||
<span class="font-mono email desktop-inline"><{commit.header.committer.email}> </span>
|
||||
<span class="time desktop-inline">{formatCommitTime(commit.header.committerTime)}</span>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<span>Authored by <strong>{commit.header.author.name}</strong> </span>
|
||||
<span class="font-mono email desktop-inline"><{commit.header.author.email}></span>
|
||||
<pre class="description text-small">{commit.header.description}</pre>
|
||||
<div class="authorship">
|
||||
<CommitAuthorship {commit} />
|
||||
{#if commit.context?.committer}
|
||||
<span class="badge tertiary">Verified</span>
|
||||
{/if}
|
||||
</div>
|
||||
</header>
|
||||
<Changeset stats={commit.stats} diff={commit.diff} on:browse={onBrowse} />
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import type { CommitMetadata } from "@app/commit";
|
||||
import { gravatarURL } from "@app/utils";
|
||||
import { formatCommitTime } from "@app/commit";
|
||||
|
||||
export let commit: CommitMetadata;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.authorship {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-foreground-faded);
|
||||
padding: 0.125rem 0;
|
||||
}
|
||||
.authorship .author, .authorship .committer {
|
||||
color: var(--color-foreground);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.authorship .avatar {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
.authorship .avatar:not(:first-child) {
|
||||
margin-left: 0.125rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<span class="authorship text-xsmall">
|
||||
<img class="avatar" alt="avatar" src="{gravatarURL(commit.header.author.email)}" />
|
||||
{#if commit.header.author.email === commit.header.committer.email}
|
||||
{#if commit.context?.committer}
|
||||
<span class="bold committer verified-committer">
|
||||
{commit.context?.committer.peer.person.name}
|
||||
</span>
|
||||
<span> committed</span>
|
||||
{:else}
|
||||
<span class="desktop-inline committer">{commit.header.committer.name}</span>
|
||||
<span> committed</span>
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="desktop-inline author">{commit.header.author.name}</span>
|
||||
<span> authored </span>
|
||||
<img class="avatar" alt="avatar" src="{gravatarURL(commit.header.committer.email)}" />
|
||||
{#if commit.context?.committer}
|
||||
<span class="bold committer verified-committer">
|
||||
{commit.context?.committer.peer.person.name}
|
||||
</span>
|
||||
<span> committed</span>
|
||||
{:else}
|
||||
<span class="desktop-inline committer">
|
||||
{commit.header.committer.name}
|
||||
</span>
|
||||
<span> committed</span>
|
||||
{/if}
|
||||
{/if}
|
||||
<span> at </span>
|
||||
<span class="desktop-inline text-xsmall time">{formatCommitTime(commit.header.committerTime)}</span>
|
||||
</span>
|
||||
@@ -1,18 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Icon from "@app/Icon.svelte";
|
||||
import type { CommitMetadata } from "@app/commit";
|
||||
import type { Project } from "@app/project";
|
||||
import { formatCommit } from "@app/utils";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { ProjectContent } from "@app/project";
|
||||
import { formatCommitTime } from "@app/commit";
|
||||
|
||||
import Icon from "@app/Icon.svelte";
|
||||
import CommitAuthorship from "./CommitAuthorship.svelte";
|
||||
|
||||
export let commit: CommitMetadata;
|
||||
export let project: Project;
|
||||
|
||||
const navigateHistory = (revision: string, content?: ProjectContent) => {
|
||||
project.navigateTo({ content, revision, path: null });
|
||||
};
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@@ -24,23 +18,38 @@
|
||||
<style>
|
||||
.hash {
|
||||
font-family: var(--font-family-monospace);
|
||||
padding: 0 1rem 0 0;
|
||||
}
|
||||
.author {
|
||||
margin-right: 0.5rem;
|
||||
white-space: nowrap;
|
||||
.commit-teaser {
|
||||
background-color: var(--color-foreground-background);
|
||||
padding: 0.5rem 0rem;
|
||||
}
|
||||
.commit {
|
||||
.commit-teaser:hover {
|
||||
background-color: var(--color-foreground-background-lighter);
|
||||
}
|
||||
.commit-teaser:first-child {
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-top-right-radius: 0.25rem;
|
||||
}
|
||||
.commit-teaser:last-child {
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
}
|
||||
.commit-teaser {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.commit .right {
|
||||
|
||||
.column-left {
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
.column-center {
|
||||
flex: min-content;
|
||||
}
|
||||
.commit-teaser .column-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
.summary {
|
||||
overflow: hidden;
|
||||
@@ -48,16 +57,15 @@
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.time {
|
||||
margin-right: 0.5rem;
|
||||
white-space: nowrap;
|
||||
.badge {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.hash {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
.time, .author, .hash {
|
||||
.hash {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.summary {
|
||||
@@ -69,17 +77,22 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="commit" on:click={() => navigateHistory(commit.header.sha1, ProjectContent.Commit)}>
|
||||
<div class="summary">
|
||||
<div class="commit-teaser">
|
||||
<div class="column-left">
|
||||
<span class="secondary hash">{formatCommit(commit.header.sha1)}</span>
|
||||
<span class="summary">{commit.header.summary}</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="column-center">
|
||||
<div class="header">
|
||||
<div class="summary">
|
||||
{commit.header.summary}
|
||||
</div>
|
||||
</div>
|
||||
<CommitAuthorship {commit} />
|
||||
</div>
|
||||
<div class="column-right">
|
||||
{#if commit.context.committer}
|
||||
<span class="badge primary">Verified</span>
|
||||
<span class="badge tertiary">Verified</span>
|
||||
{/if}
|
||||
<span class="desktop-inline bold author">{commit.header.committer.name}</span>
|
||||
<span class="desktop-inline font-mono text-small time">{formatCommitTime(commit.header.committerTime)}</span>
|
||||
<Icon name="browse" width={17} inline fill on:click={() => browseCommit(commit.header.sha1)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CommitTeaser from "./Commit/CommitTeaser.svelte";
|
||||
import { Project } from "@app/project";
|
||||
import { Project, ProjectContent } from "@app/project";
|
||||
import Loading from "@app/Loading.svelte";
|
||||
import { groupCommitHistory, GroupedCommitsHistory } from "@app/commit";
|
||||
import Message from "@app/Message.svelte";
|
||||
@@ -8,6 +8,10 @@
|
||||
export let project: Project;
|
||||
export let commit: string;
|
||||
|
||||
const navigateHistory = (revision: string, content?: ProjectContent) => {
|
||||
project.navigateTo({ content, revision, path: null });
|
||||
};
|
||||
|
||||
const fetchCommits = async (parentCommit: string): Promise<GroupedCommitsHistory> => {
|
||||
const commitsQuery = await Project.getCommits(project.urn, project.seed.api, {
|
||||
parent: parentCommit, verified: true
|
||||
@@ -25,24 +29,28 @@
|
||||
color: var(--color-foreground-faded);
|
||||
}
|
||||
.commit-group-headers {
|
||||
border-radius: 0.25rem;
|
||||
margin-bottom: 2rem;
|
||||
background: var(--color-foreground-background);
|
||||
}
|
||||
.commit-group-headers {
|
||||
|
||||
.commit {
|
||||
background-color: var(--color-foreground-background);
|
||||
}
|
||||
.commit:not(:last-child) {
|
||||
border-bottom: 1px dashed var(--color-background);
|
||||
}
|
||||
.commit:hover {
|
||||
background-color: var(--color-foreground-background-lighter);
|
||||
cursor: pointer;
|
||||
}
|
||||
.commit-group-headers:first-child {
|
||||
.commit:first-child {
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-top-right-radius: 0.25rem;
|
||||
}
|
||||
.commit-group-headers:last-child {
|
||||
.commit:last-child {
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
}
|
||||
.commit-group-headers {
|
||||
background: var(--color-foreground-background-lighter);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.history {
|
||||
padding-left: 2rem;
|
||||
@@ -61,7 +69,9 @@
|
||||
</header>
|
||||
<div class="commit-group-headers">
|
||||
{#each group.commits as commit (commit.header.sha1)}
|
||||
<CommitTeaser {project} {commit} />
|
||||
<div class="commit" on:click={() => navigateHistory(commit.header.sha1, ProjectContent.Commit)}>
|
||||
<CommitTeaser {commit} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+5
-1
@@ -69,6 +69,7 @@ export interface Commit {
|
||||
stats: CommitStats;
|
||||
diff: Diff;
|
||||
branches: string[];
|
||||
context: CommitContext;
|
||||
}
|
||||
|
||||
export function formatGroupTime(timestamp: number): string {
|
||||
@@ -129,7 +130,10 @@ export function groupCommits(commits: { header: CommitHeader; context: CommitCon
|
||||
}
|
||||
|
||||
export const formatCommitTime = (t: number): string => {
|
||||
return new Date(t * 1000).toUTCString();
|
||||
const options: any = {
|
||||
hour: "2-digit", minute: "2-digit", timeZoneName: "short", hour12: false
|
||||
};
|
||||
return new Date(t * 1000).toLocaleTimeString("en-us", options);
|
||||
};
|
||||
|
||||
export function groupCommitsByWeek(commits: CommitMetadata[]): CommitGroup[] {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ethers } from "ethers";
|
||||
import md5 from "md5";
|
||||
import { BigNumber } from "ethers";
|
||||
import multibase from 'multibase';
|
||||
import multihashes from 'multihashes';
|
||||
@@ -482,6 +483,15 @@ export function isDomain(input: string): boolean {
|
||||
|| (! import.meta.env.PROD && /^0.0.0.0$/.test(input));
|
||||
}
|
||||
|
||||
|
||||
// Get the gravatar URL of an email.
|
||||
export function gravatarURL(email: string): string {
|
||||
const address = email.trim().toLowerCase();
|
||||
const hash = md5(address);
|
||||
|
||||
return `https://www.gravatar.com/avatar/${hash}`;
|
||||
}
|
||||
|
||||
// Propose a Gnosis Safe multi-sig transaction.
|
||||
export async function proposeSafeTransaction(
|
||||
safeTx: SafeTransaction,
|
||||
|
||||
Reference in New Issue
Block a user