frontend successfully lists sessions !!

This commit is contained in:
Nikita Galaiko 2023-02-09 15:53:12 +01:00
parent e75863135f
commit ab352b0e4e
No known key found for this signature in database
GPG Key ID: EBAB54E845BA519D
12 changed files with 263 additions and 130 deletions

1
src-tauri/Cargo.lock generated
View File

@ -1021,6 +1021,7 @@ dependencies = [
"tauri-plugin-log", "tauri-plugin-log",
"tauri-plugin-window-state", "tauri-plugin-window-state",
"uuid 1.3.0", "uuid 1.3.0",
"walkdir",
"yrs", "yrs",
] ]

View File

@ -29,6 +29,7 @@ filetime = "0.2.19"
sha2 = "0.10.6" sha2 = "0.10.6"
sentry-tauri = "0.1.0" sentry-tauri = "0.1.0"
sentry = "0.27" sentry = "0.27"
walkdir = "2.3.2"
[features] [features]
# by default Tauri runs in production mode # by default Tauri runs in production mode

View File

@ -224,6 +224,10 @@ pub fn save_current_file_deltas(
pub fn list_current_deltas(project_path: &Path) -> Result<HashMap<String, Vec<Delta>>, Error> { pub fn list_current_deltas(project_path: &Path) -> Result<HashMap<String, Vec<Delta>>, Error> {
let deltas_path = project_path.join(".git/gb/session/deltas"); let deltas_path = project_path.join(".git/gb/session/deltas");
if !deltas_path.exists() {
return Ok(HashMap::new());
}
let file_paths = fs::list_files(&deltas_path).map_err(|e| Error { let file_paths = fs::list_files(&deltas_path).map_err(|e| Error {
message: format!("Could not list delta files at {}", deltas_path.display()), message: format!("Could not list delta files at {}", deltas_path.display()),
cause: e.into(), cause: e.into(),

View File

@ -1,41 +1,19 @@
use std::{fs, path::Path}; use std::path::Path;
fn list_files_abs(dir_path: &Path) -> Result<Vec<String>, std::io::Error> { use walkdir::WalkDir;
let mut files = Vec::new();
if dir_path.is_dir() { // Returns an ordered list of relative paths for files inside a directory recursively.
for entry in fs::read_dir(dir_path)? { pub fn list_files(dir_path: &Path) -> Result<Vec<String>, std::io::Error> {
let mut files = vec![];
for entry in WalkDir::new(dir_path) {
let entry = entry?; let entry = entry?;
if entry.file_type().is_file() {
let path = entry.path(); let path = entry.path();
if path.is_dir() { let path = path.strip_prefix(dir_path).unwrap();
let mut sub_files = list_files(&path)?; let path = path.to_str().unwrap().to_string();
files.append(&mut sub_files); files.push(path);
} else {
match path.to_str() {
Some(path) => files.push(path.to_string()),
None => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Invalid path",
))
}
}
}
} }
} }
files.sort(); files.sort();
Ok(files) Ok(files)
} }
// Returns an ordered list of relative paths for files inside a directory recursively.
pub fn list_files(dir_path: &Path) -> Result<Vec<String>, std::io::Error> {
list_files_abs(dir_path).map(|files| {
files
.iter()
.filter_map(|file| {
let file_path = Path::new(file);
let relative_path = file_path.strip_prefix(dir_path).ok()?;
relative_path.to_str().map(|s| s.to_string())
})
.collect()
})
}

View File

@ -75,6 +75,41 @@ fn list_project_files(state: State<'_, AppState>, project_id: &str) -> Result<Ve
} }
} }
#[tauri::command]
fn list_sessions(
state: State<'_, AppState>,
project_id: &str,
) -> Result<Vec<sessions::Session>, Error> {
match state
.projects_storage
.get_project(project_id)
.map_err(|e| {
log::error!("{}", e);
Error {
message: "Failed to get project".to_string(),
}
})? {
Some(project) => {
let repo = Repository::open(project.path).map_err(|e| {
log::error!("{}", e);
Error {
message: "Failed to open project".to_string(),
}
})?;
let sessions = sessions::list_sessions(&repo).map_err(|e| {
log::error!("{}", e);
Error {
message: "Failed to list sessions".to_string(),
}
})?;
Ok(sessions)
}
None => Err(Error {
message: "Project not found".to_string(),
}),
}
}
#[tauri::command] #[tauri::command]
fn read_project_file( fn read_project_file(
state: State<'_, AppState>, state: State<'_, AppState>,
@ -281,7 +316,8 @@ fn main() {
add_project, add_project,
list_projects, list_projects,
delete_project, delete_project,
list_deltas list_deltas,
list_sessions,
]) ])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application") .expect("error while running tauri application")

View File

@ -1,5 +1,9 @@
use std::path::Path; use std::path::Path;
use serde::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Meta { pub struct Meta {
// timestamp of when the session was created // timestamp of when the session was created
pub start_ts: u64, pub start_ts: u64,
@ -11,10 +15,47 @@ pub struct Meta {
pub commit: String, pub commit: String,
} }
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Session { pub struct Session {
pub meta: Meta, pub meta: Meta,
} }
impl Session {
pub fn from_commit(repo: &git2::Repository, commit: &git2::Commit) -> Result<Self, Error> {
let tree = commit.tree().map_err(|err| Error {
cause: err.into(),
message: "Error while getting commit tree".to_string(),
})?;
let start = read_as_string(repo, &tree, Path::new("session/meta/start"))?
.parse::<u64>()
.map_err(|err| Error {
cause: ErrorCause::ParseIntError(err),
message: "Error while parsing start file".to_string(),
})?;
let last = read_as_string(repo, &tree, Path::new("session/meta/last"))?
.parse::<u64>()
.map_err(|err| Error {
cause: ErrorCause::ParseIntError(err),
message: "Error while parsing last file".to_string(),
})?;
let branch = read_as_string(repo, &tree, Path::new("session/meta/branch"))?;
let commit = read_as_string(repo, &tree, Path::new("session/meta/commit"))?;
Ok(Session {
meta: Meta {
start_ts: start,
last_ts: last,
branch,
commit,
},
})
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Error { pub struct Error {
pub cause: ErrorCause, pub cause: ErrorCause,
@ -28,6 +69,8 @@ impl std::error::Error for Error {
ErrorCause::ParseIntError(err) => Some(err), ErrorCause::ParseIntError(err) => Some(err),
ErrorCause::SessionExistsError => Some(self), ErrorCause::SessionExistsError => Some(self),
ErrorCause::SessionDoesNotExistError => Some(self), ErrorCause::SessionDoesNotExistError => Some(self),
ErrorCause::GitError(err) => Some(err),
ErrorCause::ParseUtf8Error(err) => Some(err),
} }
} }
} }
@ -39,6 +82,8 @@ impl std::fmt::Display for Error {
ErrorCause::ParseIntError(ref e) => write!(f, "{}: {}", self.message, e), ErrorCause::ParseIntError(ref e) => write!(f, "{}: {}", self.message, e),
ErrorCause::SessionExistsError => write!(f, "{}", self.message), ErrorCause::SessionExistsError => write!(f, "{}", self.message),
ErrorCause::SessionDoesNotExistError => write!(f, "{}", self.message), ErrorCause::SessionDoesNotExistError => write!(f, "{}", self.message),
ErrorCause::GitError(ref e) => write!(f, "{}: {}", self.message, e),
ErrorCause::ParseUtf8Error(ref e) => write!(f, "{}: {}", self.message, e),
} }
} }
} }
@ -47,8 +92,22 @@ impl std::fmt::Display for Error {
pub enum ErrorCause { pub enum ErrorCause {
IOError(std::io::Error), IOError(std::io::Error),
ParseIntError(std::num::ParseIntError), ParseIntError(std::num::ParseIntError),
GitError(git2::Error),
SessionExistsError, SessionExistsError,
SessionDoesNotExistError, SessionDoesNotExistError,
ParseUtf8Error(std::string::FromUtf8Error),
}
impl From<std::string::FromUtf8Error> for ErrorCause {
fn from(err: std::string::FromUtf8Error) -> Self {
ErrorCause::ParseUtf8Error(err)
}
}
impl From<git2::Error> for ErrorCause {
fn from(err: git2::Error) -> Self {
ErrorCause::GitError(err)
}
} }
impl From<std::io::Error> for ErrorCause { impl From<std::io::Error> for ErrorCause {
@ -98,8 +157,9 @@ fn write_current_session(session_path: &Path, session: &Session) -> Result<(), E
Ok(()) Ok(())
} }
pub fn update_current_session(project_path: &Path, session: &Session) -> Result<(), Error> { pub fn update_current_session(repo: &git2::Repository, session: &Session) -> Result<(), Error> {
let session_path = project_path.join(".git/gb/session"); log::debug!("{}: Updating current session", repo.path().display());
let session_path = repo.path().join("gb/session");
if session_path.exists() { if session_path.exists() {
write_current_session(&session_path, session) write_current_session(&session_path, session)
} else { } else {
@ -110,9 +170,9 @@ pub fn update_current_session(project_path: &Path, session: &Session) -> Result<
} }
} }
pub fn create_current_session(project_path: &Path, session: &Session) -> Result<(), Error> { pub fn create_current_session(repo: &git2::Repository, session: &Session) -> Result<(), Error> {
log::debug!("{}: Creating current session", project_path.display()); log::debug!("{}: Creating current session", repo.path().display());
let session_path = project_path.join(".git/gb/session"); let session_path = repo.path().join("gb/session");
if session_path.exists() { if session_path.exists() {
Err(Error { Err(Error {
cause: ErrorCause::SessionExistsError, cause: ErrorCause::SessionExistsError,
@ -123,17 +183,17 @@ pub fn create_current_session(project_path: &Path, session: &Session) -> Result<
} }
} }
pub fn delete_current_session(project_path: &Path) -> Result<(), std::io::Error> { pub fn delete_current_session(repo: &git2::Repository) -> Result<(), std::io::Error> {
log::debug!("{}: Deleting current session", project_path.display()); log::debug!("{}: Deleting current session", repo.path().display());
let session_path = project_path.join(".git/gb/session"); let session_path = repo.path().join("gb/session");
if session_path.exists() { if session_path.exists() {
std::fs::remove_dir_all(session_path)?; std::fs::remove_dir_all(session_path)?;
} }
Ok(()) Ok(())
} }
pub fn get_current_session(project_path: &Path) -> Result<Option<Session>, Error> { pub fn get_current_session(repo: &git2::Repository) -> Result<Option<Session>, Error> {
let session_path = project_path.join(".git/gb/session"); let session_path = repo.path().join("gb/session");
if !session_path.exists() { if !session_path.exists() {
return Ok(None); return Ok(None);
} }
@ -185,3 +245,72 @@ pub fn get_current_session(project_path: &Path) -> Result<Option<Session>, Error
}, },
})) }))
} }
pub fn list_sessions(repo: &git2::Repository) -> Result<Vec<Session>, Error> {
match repo.revparse_single("refs/gitbutler/current") {
Err(_) => Ok(vec![]),
Ok(object) => {
let gitbutler_head = repo.find_commit(object.id()).map_err(|err| Error {
cause: err.into(),
message: "Failed to find gitbutler head".to_string(),
})?;
// list all commits from gitbutler head to the first commit
let mut walker = repo.revwalk().map_err(|err| Error {
cause: err.into(),
message: "Failed to create revwalk".to_string(),
})?;
walker.push(gitbutler_head.id()).map_err(|err| Error {
cause: err.into(),
message: "Failed to push gitbutler head".to_string(),
})?;
walker.set_sorting(git2::Sort::TIME).map_err(|err| Error {
cause: err.into(),
message: "Failed to set sorting".to_string(),
})?;
let mut sessions: Vec<Session> = vec![];
for id in walker {
let id = id.map_err(|err| Error {
cause: err.into(),
message: "Failed to get commit id".to_string(),
})?;
let commit = repo.find_commit(id).map_err(|err| Error {
cause: err.into(),
message: "Failed to find commit".to_string(),
})?;
sessions.push(Session::from_commit(repo, &commit)?);
}
Ok(sessions)
}
}
}
fn read_as_string(
repo: &git2::Repository,
tree: &git2::Tree,
path: &Path,
) -> Result<String, Error> {
match tree.get_path(path) {
Ok(tree_entry) => {
let blob = tree_entry
.to_object(repo)
.map_err(|err| Error {
cause: err.into(),
message: "Error while getting tree entry object".to_string(),
})?
.into_blob()
.unwrap();
let contents = String::from_utf8(blob.content().to_vec()).map_err(|err| Error {
cause: err.into(),
message: "Error while parsing blob as utf8".to_string(),
})?;
Ok(contents)
}
Err(err) => {
return Err(Error {
cause: err.into(),
message: "Error while getting tree entry".to_string(),
})
}
}
}

View File

@ -232,17 +232,16 @@ pub fn get_latest_file_contents(
// this function is called when the user modifies a file, it writes starting metadata if not there // this function is called when the user modifies a file, it writes starting metadata if not there
// and also touches the last activity timestamp, so we can tell when we are idle // and also touches the last activity timestamp, so we can tell when we are idle
fn write_beginning_meta_files(repo: &Repository) -> Result<(), Box<dyn std::error::Error>> { fn write_beginning_meta_files(repo: &Repository) -> Result<(), Box<dyn std::error::Error>> {
let project_path = repo.workdir().unwrap();
let now_ts = SystemTime::now() let now_ts = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs(); .as_secs();
match sessions::get_current_session(project_path) match sessions::get_current_session(repo)
.map_err(|e| format!("Error while getting current session: {}", e.to_string()))? .map_err(|e| format!("Error while getting current session: {}", e.to_string()))?
{ {
Some(mut session) => { Some(mut session) => {
session.meta.last_ts = now_ts; session.meta.last_ts = now_ts;
sessions::update_current_session(project_path, &session) sessions::update_current_session(repo, &session)
.map_err(|e| format!("Error while updating current session: {}", e.to_string()))?; .map_err(|e| format!("Error while updating current session: {}", e.to_string()))?;
Ok(()) Ok(())
} }
@ -256,7 +255,7 @@ fn write_beginning_meta_files(repo: &Repository) -> Result<(), Box<dyn std::erro
commit: head.peel_to_commit()?.id().to_string(), commit: head.peel_to_commit()?.id().to_string(),
}, },
}; };
sessions::create_current_session(project_path, &session) sessions::create_current_session(repo, &session)
.map_err(|e| format!("Error while creating current session: {}", e.to_string()))?; .map_err(|e| format!("Error while creating current session: {}", e.to_string()))?;
Ok(()) Ok(())
} }

View File

@ -77,7 +77,7 @@ fn check_for_changes(repo: &Repository) -> Result<(), Box<dyn std::error::Error>
commit_oid commit_oid
); );
sessions::delete_current_session(repo.workdir().unwrap())?; sessions::delete_current_session(repo)?;
} }
Ok(()) Ok(())
@ -89,7 +89,7 @@ fn check_for_changes(repo: &Repository) -> Result<(), Box<dyn std::error::Error>
// and that there has been no activity in the last 5 minutes (the session appears to be over) // and that there has been no activity in the last 5 minutes (the session appears to be over)
// and the start was at most an hour ago // and the start was at most an hour ago
fn ready_to_commit(repo: &Repository) -> Result<bool, Box<dyn std::error::Error>> { fn ready_to_commit(repo: &Repository) -> Result<bool, Box<dyn std::error::Error>> {
if let Some(current_session) = sessions::get_current_session(repo.workdir().unwrap())? { if let Some(current_session) = sessions::get_current_session(repo)? {
let now = SystemTime::now() let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
@ -98,6 +98,7 @@ fn ready_to_commit(repo: &Repository) -> Result<bool, Box<dyn std::error::Error>
let elapsed_last = now - current_session.meta.last_ts; let elapsed_last = now - current_session.meta.last_ts;
let elapsed_start = now - current_session.meta.start_ts; let elapsed_start = now - current_session.meta.start_ts;
// TODO: uncomment
if (elapsed_last > FIVE_MINUTES) || (elapsed_start > ONE_HOUR) { if (elapsed_last > FIVE_MINUTES) || (elapsed_start > ONE_HOUR) {
Ok(true) Ok(true)
} else { } else {
@ -178,7 +179,7 @@ fn add_path(
// something is different, or not found, so we need to create a new entry // something is different, or not found, so we need to create a new entry
log::debug!("Adding path: {}", file_path.display()); log::debug!("Adding wd path: {}", file_path.display());
// look for files that are bigger than 4GB, which are not supported by git // look for files that are bigger than 4GB, which are not supported by git
// insert a pointer as the blob content instead // insert a pointer as the blob content instead
@ -216,28 +217,21 @@ fn add_path(
}; };
// create a new IndexEntry from the file metadata // create a new IndexEntry from the file metadata
let new_entry = git2::IndexEntry { index.add(&git2::IndexEntry {
ctime: IndexTime::new( ctime: IndexTime::new(ctime.seconds().try_into()?, ctime.nanoseconds().try_into()?),
ctime.seconds().try_into().unwrap(), mtime: IndexTime::new(mtime.seconds().try_into()?, mtime.nanoseconds().try_into()?),
ctime.nanoseconds().try_into().unwrap(), dev: metadata.dev().try_into()?,
), ino: metadata.ino().try_into()?,
mtime: IndexTime::new(
mtime.seconds().try_into().unwrap(),
mtime.nanoseconds().try_into().unwrap(),
),
dev: metadata.dev().try_into().unwrap(),
ino: metadata.ino().try_into().unwrap(),
mode: metadata.mode(), mode: metadata.mode(),
uid: metadata.uid().try_into().unwrap(), uid: metadata.uid().try_into()?,
gid: metadata.gid().try_into().unwrap(), gid: metadata.gid().try_into()?,
file_size: metadata.len().try_into().unwrap(), file_size: metadata.len().try_into()?,
flags: 10, // normal flags for normal file (for the curious: https://git-scm.com/docs/index-format) flags: 10, // normal flags for normal file (for the curious: https://git-scm.com/docs/index-format)
flags_extended: 0, // no extended flags flags_extended: 0, // no extended flags
path: rel_file_path.to_str().unwrap().to_string().into(), path: rel_file_path.to_str().unwrap().to_string().into(),
id: blob, id: blob,
}; })?;
index.add(&new_entry)?;
Ok(()) Ok(())
} }
@ -283,18 +277,16 @@ fn build_gb_tree(
// add all files in the working directory to the in-memory index, skipping for matching entries in the repo index // add all files in the working directory to the in-memory index, skipping for matching entries in the repo index
let session_dir = repo.path().join("gb/session"); let session_dir = repo.path().join("gb/session");
for path in fs::list_files(&session_dir)? { for session_file in fs::list_files(&session_dir)? {
let file_path = Path::new(&path); let file_path = Path::new(&session_file);
add_simple_path(&repo, session_index, &file_path)?; add_session_path(&repo, session_index, &file_path)?;
} }
// write the in-memory index to the repo // write the in-memory index to the repo
let session_tree = session_index.write_tree_to(&repo).unwrap(); let session_tree = session_index.write_tree_to(&repo)?;
// insert the session tree oid as a subdirectory under the name 'session' // insert the session tree oid as a subdirectory under the name 'session'
tree_builder tree_builder.insert("session", session_tree, 0o040000)?;
.insert("session", session_tree, 0o040000)
.unwrap();
// write the new tree and return the Oid // write the new tree and return the Oid
let tree = tree_builder.write().unwrap(); let tree = tree_builder.write().unwrap();
@ -302,56 +294,35 @@ fn build_gb_tree(
} }
// this is a helper function for build_gb_tree that takes paths under .git/gb/session and adds them to the in-memory index // this is a helper function for build_gb_tree that takes paths under .git/gb/session and adds them to the in-memory index
fn add_simple_path( fn add_session_path(
repo: &Repository, repo: &Repository,
index: &mut git2::Index, index: &mut git2::Index,
rel_file_path: &Path, rel_file_path: &Path,
) -> Result<(), git2::Error> { ) -> Result<(), Box<dyn std::error::Error>> {
let abs_file_path = repo.workdir().unwrap().join(rel_file_path); let file_path = repo.path().join("gb/session").join(rel_file_path);
let file_path = Path::new(&abs_file_path);
log::debug!("Adding path: {}", file_path.display()); log::debug!("Adding session path: {}", file_path.display());
let blob = repo.blob_path(file_path).unwrap(); let blob = repo.blob_path(&file_path)?;
let metadata = file_path.metadata().unwrap(); let metadata = file_path.metadata().unwrap();
let mtime = FileTime::from_last_modification_time(&metadata); let mtime = FileTime::from_last_modification_time(&metadata);
let ctime = FileTime::from_creation_time(&metadata).unwrap(); let ctime = FileTime::from_creation_time(&metadata).unwrap();
// create a new IndexEntry from the file metadata // create a new IndexEntry from the file metadata
let new_entry = git2::IndexEntry { index.add(&git2::IndexEntry {
ctime: IndexTime::new( ctime: IndexTime::new(ctime.seconds().try_into()?, ctime.nanoseconds().try_into()?),
ctime mtime: IndexTime::new(mtime.seconds().try_into()?, mtime.nanoseconds().try_into()?),
.seconds() dev: metadata.dev().try_into()?,
.try_into() ino: metadata.ino().try_into()?,
.map_err(|_| git2::Error::from_str("ctime seconds out of range"))?,
ctime
.nanoseconds()
.try_into()
.map_err(|_| git2::Error::from_str("ctime nanoseconds out of range"))?,
),
mtime: IndexTime::new(
mtime
.seconds()
.try_into()
.map_err(|_| git2::Error::from_str("mtime seconds out of range"))?,
mtime
.nanoseconds()
.try_into()
.map_err(|_| git2::Error::from_str("mtime nanoseconds out of range"))?,
),
dev: metadata.dev().try_into().unwrap(),
ino: metadata.ino().try_into().unwrap(),
mode: metadata.mode(), mode: metadata.mode(),
uid: metadata.uid().try_into().unwrap(), uid: metadata.uid().try_into()?,
gid: metadata.gid().try_into().unwrap(), gid: metadata.gid().try_into()?,
file_size: metadata.len().try_into().unwrap(), file_size: metadata.len().try_into()?,
flags: 10, // normal flags for normal file (for the curious: https://git-scm.com/docs/index-format) flags: 10, // normal flags for normal file (for the curious: https://git-scm.com/docs/index-format)
flags_extended: 0, // no extended flags flags_extended: 0, // no extended flags
path: rel_file_path.to_str().unwrap().into(), path: rel_file_path.to_str().unwrap().into(),
id: blob, id: blob,
}; })?;
index.add(&new_entry)?;
Ok(()) Ok(())
} }

View File

@ -2,4 +2,4 @@ export * as crdt from "./crdt";
export * as database from "./database"; export * as database from "./database";
export * as projects from "./projects"; export * as projects from "./projects";
export * as log from "./log"; export * as log from "./log";
export * as session from "./session"; export * as session from "./sessions";

View File

@ -1,3 +1,5 @@
import { invoke } from "@tauri-apps/api";
import { writable } from "svelte/store";
import type { Delta } from "./crdt"; import type { Delta } from "./crdt";
export type SessionFile = { export type SessionFile = {
@ -95,3 +97,14 @@ export let dummySessions: Session[] = [
], ],
}, },
]; ];
const list = (params: { projectId: string }) =>
invoke<Record<string, Delta[]>>("list_sessions", params);
export default async (params: { projectId: string }) => {
const init = await list(params);
const store = writable(init);
return {
subscribe: store.subscribe,
};
};

View File

@ -4,7 +4,7 @@ import { derived, readable } from "svelte/store";
import type { LayoutLoad } from "./$types"; import type { LayoutLoad } from "./$types";
// import crdt from "$lib/crdt"; // import crdt from "$lib/crdt";
import { building } from "$app/environment"; import { building } from "$app/environment";
import type { Session } from "$lib/session"; import type { Session } from "$lib/sessions";
export const prerender = false; export const prerender = false;
@ -12,33 +12,35 @@ export const load: LayoutLoad = async ({ parent, params }) => {
const { projects } = await parent(); const { projects } = await parent();
const deltas = building const deltas = building
? readable<Record<string, Delta[]>>({}) ? readable<Record<string, Delta[]>>({})
: await (await import("$lib/crdt")).default({ projectId: params.id }) : await (await import("$lib/crdt")).default({ projectId: params.id });
const sessions = building
? readable<Session[]>([])
: await (await import("$lib/sessions")).default({ projectId: params.id });
return { return {
testSessions: sessions,
project: derived(projects, (projects) => project: derived(projects, (projects) =>
projects.find((project) => project.id === params.id) projects.find((project) => project.id === params.id)
), ),
deltas, deltas,
sessions: derived(deltas, (deltas) => { sessions: derived(deltas, (deltas) => {
const files = Object.entries(deltas).map(([key, value]) => ( const files = Object.entries(deltas).map(([key, value]) => ({
{
name: key, name: key,
path: key, // TODO path: key, // TODO
linesTouched: 0, // TODO linesTouched: 0, // TODO
numberOfEdits: 0, // TODO numberOfEdits: 0, // TODO
deltas: value, deltas: value,
} }));
))
const infiniteSession: Session = { const infiniteSession: Session = {
hash: "1-a1b2c3d4e5f6g7h8i9j0", // TODO: set this when we have a snapshot hash: "1-a1b2c3d4e5f6g7h8i9j0", // TODO: set this when we have a snapshot
startTime: 0, // TODO: set this when we have a snapshot startTime: 0, // TODO: set this when we have a snapshot
endTime: 0, // TODO: set this when we have a snapshot endTime: 0, // TODO: set this when we have a snapshot
branchName: "infinite-session-x", // TODO: set this when we have a snapshot branchName: "infinite-session-x", // TODO: set this when we have a snapshot
files: files, files: files,
activities: [] // TODO: set this when we have activities (e.g. push, commit, etc.) activities: [], // TODO: set this when we have activities (e.g. push, commit, etc.)
} };
// TODO: until we have multiple snapshots, putting all crdt changes into one session // TODO: until we have multiple snapshots, putting all crdt changes into one session
return [infiniteSession] return [infiniteSession];
}), }),
}; };
}; };

View File

@ -3,14 +3,13 @@
import { TimelineDay } from "$lib/components/timeline"; import { TimelineDay } from "$lib/components/timeline";
export let data: PageData; export let data: PageData;
const { project, sessions } = data; const { project, sessions, testSessions } = data;
$: console.log($testSessions);
</script> </script>
<div> <div>
{#if $project} {#if $project}
<TimelineDay <TimelineDay projectId={$project?.id} sessions={$sessions} />
projectId={$project?.id}
sessions={$sessions}
/>
{/if} {/if}
</div> </div>