Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Add `activity_by_id` tauri command
Merged did:key:z6MkkfM3...sVz5 opened 1 year ago
4 files changed +95 -1 9bed71d6 a3a0850b
added crates/radicle-tauri/bindings/IssueOps.ts
@@ -0,0 +1,10 @@
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
+
import type { Author } from "./Author";
+
import type { IssueAction } from "./IssueAction";
+

+
export type IssueOps = {
+
  id: string;
+
  action: IssueAction;
+
  timestamp: number;
+
  author: Author;
+
};
modified crates/radicle-tauri/src/commands/cob.rs
@@ -1,15 +1,27 @@
use base64::{engine::general_purpose::STANDARD, Engine as _};

+
use radicle::cob;
use radicle::git;
use radicle::identity;
use radicle::storage::{ReadRepository, ReadStorage};

-
use crate::{error, AppState};
+
use crate::{error, types, AppState};

pub mod draft;
pub mod issue;
pub mod patch;

+
#[derive(serde::Serialize, ts_rs::TS)]
+
#[ts(export)]
+
pub struct IssueOps {
+
    #[ts(as = "String")]
+
    id: git::Oid,
+
    action: types::cobs::IssueAction,
+
    #[ts(type = "number")]
+
    timestamp: cob::Timestamp,
+
    author: types::cobs::Author,
+
}
+

#[tauri::command]
pub async fn get_file_by_oid(
    ctx: tauri::State<'_, AppState>,
@@ -22,6 +34,39 @@ pub async fn get_file_by_oid(
    Ok::<_, error::Error>(STANDARD.encode(blob.content()))
}

+
#[tauri::command]
+
pub fn activity_by_id(
+
    ctx: tauri::State<AppState>,
+
    rid: identity::RepoId,
+
    type_name: cob::TypeName,
+
    id: git::Oid,
+
) -> Result<Vec<serde_json::Value>, error::Error> {
+
    let aliases = ctx.profile.aliases();
+
    let repo = ctx.profile.storage.repository(rid)?;
+
    let ops = cob::store::ops(&id.into(), &type_name, &repo).unwrap();
+
    let mut actions: Vec<serde_json::Value> = Vec::new();
+

+
    for op in ops.into_iter() {
+
        actions.extend(
+
            op.actions
+
                .iter()
+
                .filter_map(|action: &Vec<u8>| -> Option<serde_json::Value> {
+
                    serde_json::from_slice(action).ok()
+
                })
+
                .map(|action| {
+
                    serde_json::json!({
+
                        "id": op.id,
+
                        "action": action,
+
                        "author": types::cobs::Author::new(op.author.into(), &aliases),
+
                        "timestamp": op.timestamp
+
                    })
+
                }),
+
        )
+
    }
+

+
    Ok::<_, error::Error>(actions)
+
}
+

mod query {
    use serde::{Deserialize, Serialize};

modified crates/radicle-tauri/src/lib.rs
@@ -77,6 +77,7 @@ pub fn run() {
            repo::repo_by_id,
            repo::diff_stats,
            cob::get_file_by_oid,
+
            cob::activity_by_id,
            cob::issue::list_issues,
            cob::issue::issue_by_id,
            cob::issue::create_issue,
modified src/views/repo/Issue.svelte
@@ -2,10 +2,12 @@
  import type { Config } from "@bindings/Config";
  import type { Issue } from "@bindings/Issue";
  import type { RepoInfo } from "@bindings/RepoInfo";
+
  import type { IssueOps } from "@bindings/IssueOps";

  import capitalize from "lodash/capitalize";

  import { formatTimestamp, formatOid, issueStatusColor } from "@app/lib/utils";
+
  import { invoke } from "@tauri-apps/api/core";

  import Border from "@app/components/Border.svelte";
  import CopyableId from "@app/components/CopyableId.svelte";
@@ -206,5 +208,41 @@
        {formatTimestamp(issue.timestamp)}
      </div>
    </div>
+
    <div>
+
      {#await invoke<IssueOps[]>( "activity_by_id", { rid: repo.rid, typeName: "xyz.radicle.issue", id: issue.id }, ) then activity}
+
        {#each activity.slice(1) as { action, timestamp, author }}
+
          {#if action.type === "lifecycle"}
+
            <div class="txt-small body">
+
              <div class="global-flex txt-small">
+
                <NodeId
+
                  nodeId={author.did.replace("did:key:", "")}
+
                  alias={author.alias} />
+
                change of status to {action.state.status}
+
                <!-- <div class="global-oid"></div> -->
+
                {formatTimestamp(timestamp)}
+
              </div>
+
            </div>
+
          {:else if action.type === "comment"}
+
            <div class="txt-small body">
+
              <Markdown rid={repo.rid} breaks content={action.body} />
+
              <div class="global-flex txt-small" style:margin-top="1.5rem">
+
                <NodeId
+
                  nodeId={author.did.replace("did:key:", "")}
+
                  alias={author.alias} />
+
                {#if action.replyTo}
+
                  replied to <div class="global-oid">
+
                    {formatOid(action.replyTo)}
+
                  </div>
+
                {:else}
+
                  commented
+
                {/if}
+
                <!-- <div class="global-oid"></div> -->
+
                {formatTimestamp(timestamp)}
+
              </div>
+
            </div>
+
          {/if}
+
        {/each}
+
      {/await}
+
    </div>
  </div>
</Layout>