mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-23 09:33:01 +03:00
allow to delete bookmarks
This commit is contained in:
parent
fd00c76f6f
commit
9fe324996d
@ -302,26 +302,26 @@ impl App {
|
|||||||
self.files_database.list_by_project_id_session_id(project_id, session_id, paths)
|
self.files_database.list_by_project_id_session_id(project_id, session_id, paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_bookmark(&self, project_id: &str, timestamp_ms: &u128, note: &str) -> Result<bookmarks::Bookmark> {
|
pub fn upsert_bookmark(&self, bookmark: &bookmarks::Bookmark) -> Result<()> {
|
||||||
let gb_repository = gb_repository::Repository::open(
|
let gb_repository = gb_repository::Repository::open(
|
||||||
self.local_data_dir.clone(),
|
self.local_data_dir.clone(),
|
||||||
project_id.to_string(),
|
bookmark.project_id.to_string(),
|
||||||
self.projects_storage.clone(),
|
self.projects_storage.clone(),
|
||||||
self.users_storage.clone(),
|
self.users_storage.clone(),
|
||||||
)
|
)
|
||||||
.context("failed to open repository")?;
|
.context("failed to open repository")?;
|
||||||
|
|
||||||
let bookmark = bookmarks::Bookmark{
|
|
||||||
id: uuid::Uuid::new_v4().to_string(),
|
|
||||||
project_id: project_id.to_string(),
|
|
||||||
timestamp_ms: *timestamp_ms,
|
|
||||||
note: note.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let session = gb_repository.get_or_create_current_session().context("failed to get or create current session")?;
|
let session = gb_repository.get_or_create_current_session().context("failed to get or create current session")?;
|
||||||
let writer = sessions::Writer::open(&gb_repository, &session).context("failed to open session writer")?;
|
let writer = sessions::Writer::open(&gb_repository, &session).context("failed to open session writer")?;
|
||||||
writer.write_bookmark(&bookmark).context("failed to write bookmark")?;
|
writer.write_bookmark(&bookmark).context("failed to write bookmark")?;
|
||||||
Ok(bookmark)
|
|
||||||
|
self.proxy_watchers.lock().unwrap().get(&bookmark.project_id).map(|proxy_watcher| {
|
||||||
|
if let Err(e) = proxy_watcher.send(watcher::Event::Bookmark(bookmark.clone())) {
|
||||||
|
log::error!("failed to send bookmark event to proxy: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_bookmarks(&self, project_id: &str, range: Option<ops::Range<u128>>) -> Result<Vec<bookmarks::Bookmark>> {
|
pub fn list_bookmarks(&self, project_id: &str, range: Option<ops::Range<u128>>) -> Result<Vec<bookmarks::Bookmark>> {
|
||||||
@ -337,6 +337,7 @@ impl App {
|
|||||||
self.deltas_database.list_by_project_id_session_id(project_id, session_id, paths)
|
self.deltas_database.list_by_project_id_session_id(project_id, session_id, paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn git_activity(
|
pub fn git_activity(
|
||||||
&self,
|
&self,
|
||||||
project_id: &str,
|
project_id: &str,
|
||||||
|
@ -16,15 +16,32 @@ impl Database {
|
|||||||
Self { database }
|
Self { database }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&self, bookmark: &Bookmark) -> Result<()> {
|
pub fn get_by_id(&self, id: &str) -> Result<Option<Bookmark>> {
|
||||||
|
self.database.transaction(|tx| {
|
||||||
|
let mut stmt = get_by_id_stmt(tx).context("Failed to prepare get_by_id statement")?;
|
||||||
|
let mut rows = stmt
|
||||||
|
.query(rusqlite::named_params! { ":id": id })
|
||||||
|
.context("Failed to execute get_by_id statement")?;
|
||||||
|
if let Some(row) = rows.next()? {
|
||||||
|
Ok(Some(parse_row(row)?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upsert(&self, bookmark: &Bookmark) -> Result<()> {
|
||||||
self.database.transaction(|tx| -> Result<()> {
|
self.database.transaction(|tx| -> Result<()> {
|
||||||
let mut stmt = insert_stmt(tx).context("Failed to prepare insert statement")?;
|
let mut stmt = insert_stmt(tx).context("Failed to prepare insert statement")?;
|
||||||
let timestamp_ms = bookmark.timestamp_ms.to_string();
|
let created_timestamp_ms = bookmark.created_timestamp_ms.to_string();
|
||||||
|
let updated_timestamp_ms = bookmark.updated_timestamp_ms.to_string();
|
||||||
stmt.execute(rusqlite::named_params! {
|
stmt.execute(rusqlite::named_params! {
|
||||||
":id": &bookmark.id,
|
":id": &bookmark.id,
|
||||||
":project_id": &bookmark.project_id,
|
":project_id": &bookmark.project_id,
|
||||||
":timestamp_ms": ×tamp_ms,
|
":created_timestamp_ms": &created_timestamp_ms,
|
||||||
|
":updated_timestamp_ms": &updated_timestamp_ms,
|
||||||
":note": &bookmark.note,
|
":note": &bookmark.note,
|
||||||
|
":deleted": &bookmark.deleted,
|
||||||
})
|
})
|
||||||
.context("Failed to execute insert statement")?;
|
.context("Failed to execute insert statement")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -87,8 +104,24 @@ fn insert_stmt<'conn>(
|
|||||||
) -> Result<rusqlite::CachedStatement<'conn>> {
|
) -> Result<rusqlite::CachedStatement<'conn>> {
|
||||||
Ok(tx.prepare_cached(
|
Ok(tx.prepare_cached(
|
||||||
"
|
"
|
||||||
INSERT INTO `bookmarks` (`id`, `project_id`, `timestamp_ms`, `note`)
|
INSERT INTO `bookmarks` (`id`, `project_id`, `created_timestamp_ms`, `updated_timestamp_ms`, `note`, `deleted`)
|
||||||
VALUES (:id, :project_id, :timestamp_ms, :note)
|
VALUES (:id, :project_id, :created_timestamp_ms, :updated_timestamp_ms, :note, :deleted)
|
||||||
|
ON CONFLICT(`id`) DO UPDATE SET
|
||||||
|
`updated_timestamp_ms` = :updated_timestamp_ms,
|
||||||
|
`note` = :note,
|
||||||
|
`deleted` = :deleted
|
||||||
|
",
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_by_id_stmt<'conn>(
|
||||||
|
tx: &'conn rusqlite::Transaction,
|
||||||
|
) -> Result<rusqlite::CachedStatement<'conn>> {
|
||||||
|
Ok(tx.prepare_cached(
|
||||||
|
"
|
||||||
|
SELECT `id`, `project_id`, `created_timestamp_ms`, `updated_timestamp_ms`, `note`, `deleted`
|
||||||
|
FROM `bookmarks`
|
||||||
|
WHERE `id` = :id
|
||||||
",
|
",
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
@ -98,12 +131,12 @@ fn list_by_project_id_range_stmt<'conn>(
|
|||||||
) -> Result<rusqlite::CachedStatement<'conn>> {
|
) -> Result<rusqlite::CachedStatement<'conn>> {
|
||||||
Ok(tx.prepare_cached(
|
Ok(tx.prepare_cached(
|
||||||
"
|
"
|
||||||
SELECT `id`, `project_id`, `timestamp_ms`, `note`
|
SELECT `id`, `project_id`, `created_timestamp_ms`, `updated_timestamp_ms`, `note`, `deleted`
|
||||||
FROM `bookmarks`
|
FROM `bookmarks`
|
||||||
WHERE `project_id` = :project_id
|
WHERE `project_id` = :project_id
|
||||||
AND `timestamp_ms` >= :start
|
AND `updated_timestamp_ms` >= :start
|
||||||
AND `timestamp_ms` < :end
|
AND `updated_timestamp_ms` < :end
|
||||||
ORDER BY `timestamp_ms` DESC
|
ORDER BY `created_timestamp_ms` DESC
|
||||||
",
|
",
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
@ -113,10 +146,10 @@ fn list_by_project_id_stmt<'conn>(
|
|||||||
) -> Result<rusqlite::CachedStatement<'conn>> {
|
) -> Result<rusqlite::CachedStatement<'conn>> {
|
||||||
Ok(tx.prepare_cached(
|
Ok(tx.prepare_cached(
|
||||||
"
|
"
|
||||||
SELECT `id`, `project_id`, `timestamp_ms`, `note`
|
SELECT `id`, `project_id`, `created_timestamp_ms`, `updated_timestamp_ms`, `note`, `deleted`
|
||||||
FROM `bookmarks`
|
FROM `bookmarks`
|
||||||
WHERE `project_id` = :project_id
|
WHERE `project_id` = :project_id
|
||||||
ORDER BY `timestamp_ms` DESC
|
ORDER BY `created_timestamp_ms` DESC
|
||||||
",
|
",
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
@ -125,12 +158,18 @@ fn parse_row(row: &rusqlite::Row) -> Result<Bookmark> {
|
|||||||
Ok(Bookmark {
|
Ok(Bookmark {
|
||||||
id: row.get(0).context("Failed to get id")?,
|
id: row.get(0).context("Failed to get id")?,
|
||||||
project_id: row.get(1).context("Failed to get project_id")?,
|
project_id: row.get(1).context("Failed to get project_id")?,
|
||||||
timestamp_ms: row
|
created_timestamp_ms: row
|
||||||
.get::<usize, String>(2)
|
.get::<usize, String>(2)
|
||||||
.context("Failed to get timestamp_ms")?
|
.context("Failed to get created_timestamp_ms")?
|
||||||
.parse()
|
.parse::<u128>()
|
||||||
.context("Failed to parse timestamp_ms")?,
|
.context("Failed to parse created_timestamp_ms")?,
|
||||||
note: row.get(3).context("Failed to get note")?,
|
updated_timestamp_ms: row
|
||||||
|
.get::<usize, String>(3)
|
||||||
|
.context("Failed to get updated_timestamp_ms")?
|
||||||
|
.parse::<u128>()
|
||||||
|
.context("Failed to parse updated_timestamp_ms")?,
|
||||||
|
note: row.get(4).context("Failed to get note")?,
|
||||||
|
deleted: row.get(5).context("Failed to get deleted")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +185,13 @@ mod tests {
|
|||||||
let bookmark = Bookmark {
|
let bookmark = Bookmark {
|
||||||
id: "id".to_string(),
|
id: "id".to_string(),
|
||||||
project_id: "project_id".to_string(),
|
project_id: "project_id".to_string(),
|
||||||
timestamp_ms: 123,
|
created_timestamp_ms: 123,
|
||||||
|
updated_timestamp_ms: 123,
|
||||||
note: "note".to_string(),
|
note: "note".to_string(),
|
||||||
|
deleted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
database.insert(&bookmark)?;
|
database.upsert(&bookmark)?;
|
||||||
|
|
||||||
let result = database.list_by_project_id_all(&bookmark.project_id)?;
|
let result = database.list_by_project_id_all(&bookmark.project_id)?;
|
||||||
|
|
||||||
@ -167,18 +208,22 @@ mod tests {
|
|||||||
let bookmark_one = Bookmark {
|
let bookmark_one = Bookmark {
|
||||||
id: "id".to_string(),
|
id: "id".to_string(),
|
||||||
project_id: "project_id".to_string(),
|
project_id: "project_id".to_string(),
|
||||||
timestamp_ms: 123,
|
created_timestamp_ms: 123,
|
||||||
|
updated_timestamp_ms: 123,
|
||||||
note: "note".to_string(),
|
note: "note".to_string(),
|
||||||
|
deleted: false,
|
||||||
};
|
};
|
||||||
database.insert(&bookmark_one)?;
|
database.upsert(&bookmark_one)?;
|
||||||
|
|
||||||
let bookmark_two = Bookmark {
|
let bookmark_two = Bookmark {
|
||||||
id: "id2".to_string(),
|
id: "id2".to_string(),
|
||||||
project_id: "project_id".to_string(),
|
project_id: "project_id".to_string(),
|
||||||
timestamp_ms: 456,
|
created_timestamp_ms: 456,
|
||||||
|
updated_timestamp_ms: 456,
|
||||||
note: "note".to_string(),
|
note: "note".to_string(),
|
||||||
|
deleted: false,
|
||||||
};
|
};
|
||||||
database.insert(&bookmark_two)?;
|
database.upsert(&bookmark_two)?;
|
||||||
|
|
||||||
let result = database.list_by_project_id_range(
|
let result = database.list_by_project_id_range(
|
||||||
&bookmark_one.project_id,
|
&bookmark_one.project_id,
|
||||||
@ -188,4 +233,34 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update() -> Result<()> {
|
||||||
|
let db = database::Database::memory()?;
|
||||||
|
let database = Database::new(db);
|
||||||
|
|
||||||
|
assert_eq!(database.get_by_id("id")?, None);
|
||||||
|
|
||||||
|
let bookmark = Bookmark {
|
||||||
|
id: "id".to_string(),
|
||||||
|
project_id: "project_id".to_string(),
|
||||||
|
created_timestamp_ms: 123,
|
||||||
|
updated_timestamp_ms: 123,
|
||||||
|
note: "note".to_string(),
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
database.upsert(&bookmark)?;
|
||||||
|
assert_eq!(database.get_by_id(&bookmark.id)?, Some(bookmark.clone()));
|
||||||
|
|
||||||
|
let updated = Bookmark {
|
||||||
|
note: "updated".to_string(),
|
||||||
|
updated_timestamp_ms: 456,
|
||||||
|
..bookmark.clone()
|
||||||
|
};
|
||||||
|
database.upsert(&updated)?;
|
||||||
|
assert_eq!(database.get_by_id(&bookmark.id.clone())?, Some(updated));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,27 @@ mod reader;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Bookmark {
|
pub struct Bookmark {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub project_id: String,
|
pub project_id: String,
|
||||||
pub timestamp_ms: u128,
|
pub created_timestamp_ms: u128,
|
||||||
|
pub updated_timestamp_ms: u128,
|
||||||
pub note: String,
|
pub note: String,
|
||||||
|
pub deleted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum Event {
|
||||||
|
Created(Bookmark),
|
||||||
|
Updated {
|
||||||
|
id: String,
|
||||||
|
note: Option<String>,
|
||||||
|
deleted: Option<bool>,
|
||||||
|
timestamp_ms: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use database::Database;
|
pub use database::Database;
|
||||||
|
16
src-tauri/src/database/migrations/V4__bookmarks_update.sql
Normal file
16
src-tauri/src/database/migrations/V4__bookmarks_update.sql
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
ALTER TABLE `bookmarks`
|
||||||
|
ADD `created_timestamp_ms` text NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
`bookmarks`
|
||||||
|
SET
|
||||||
|
`created_timestamp_ms` = `timestamp_ms`;
|
||||||
|
|
||||||
|
ALTER TABLE `bookmarks`
|
||||||
|
DROP COLUMN `timestamp_ms`;
|
||||||
|
|
||||||
|
ALTER TABLE `bookmarks`
|
||||||
|
ADD `updated_timestamp_ms` text;
|
||||||
|
|
||||||
|
ALTER TABLE `bookmarks`
|
||||||
|
ADD `deleted` boolean NOT NULL DEFAULT FALSE;
|
@ -486,10 +486,10 @@ async fn delete_all_data(handle: tauri::AppHandle) -> Result<(), Error> {
|
|||||||
|
|
||||||
#[timed(duration(printer = "debug!"))]
|
#[timed(duration(printer = "debug!"))]
|
||||||
#[tauri::command(async)]
|
#[tauri::command(async)]
|
||||||
async fn create_bookmark(handle: tauri::AppHandle, project_id: &str, timestamp_ms: u128, note: &str) -> Result<bookmarks::Bookmark, Error> {
|
async fn upsert_bookmark(handle: tauri::AppHandle, bookmark: bookmarks::Bookmark) -> Result<(), Error> {
|
||||||
let app = handle.state::<app::App>();
|
let app = handle.state::<app::App>();
|
||||||
let bookmark = app.create_bookmark(project_id, ×tamp_ms, note).context("failed to create bookmark")?;
|
app.upsert_bookmark(&bookmark).context("failed to upsert bookmark")?;
|
||||||
Ok(bookmark)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[timed(duration(printer = "debug!"))]
|
#[timed(duration(printer = "debug!"))]
|
||||||
@ -638,7 +638,7 @@ fn main() {
|
|||||||
get_logs_archive_path,
|
get_logs_archive_path,
|
||||||
get_project_archive_path,
|
get_project_archive_path,
|
||||||
get_project_data_archive_path,
|
get_project_data_archive_path,
|
||||||
create_bookmark,
|
upsert_bookmark,
|
||||||
list_bookmarks,
|
list_bookmarks,
|
||||||
])
|
])
|
||||||
.build(tauri_context)
|
.build(tauri_context)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{path, time};
|
use std::{path, time};
|
||||||
|
|
||||||
use crate::{deltas, sessions};
|
use crate::{bookmarks, deltas, sessions};
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Tick(time::SystemTime),
|
Tick(time::SystemTime),
|
||||||
@ -17,6 +17,7 @@ pub enum Event {
|
|||||||
ProjectFileChange(path::PathBuf),
|
ProjectFileChange(path::PathBuf),
|
||||||
|
|
||||||
Session(sessions::Session),
|
Session(sessions::Session),
|
||||||
|
Bookmark(bookmarks::Bookmark),
|
||||||
File((String, path::PathBuf, String)),
|
File((String, path::PathBuf, String)),
|
||||||
Deltas((String, path::PathBuf, Vec<deltas::Delta>)),
|
Deltas((String, path::PathBuf, Vec<deltas::Delta>)),
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,14 @@ impl<'handler> Handler<'handler> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn index_bookmark(&self, bookmark: &bookmarks::Bookmark) -> Result<Vec<events::Event>> {
|
pub fn index_bookmark(&self, bookmark: &bookmarks::Bookmark) -> Result<Vec<events::Event>> {
|
||||||
self.bookmarks_database.insert(&bookmark)?;
|
match self.bookmarks_database.get_by_id(&bookmark.id)? {
|
||||||
|
Some(existing) => {
|
||||||
|
if existing.updated_timestamp_ms < bookmark.updated_timestamp_ms {
|
||||||
|
self.bookmarks_database.upsert(&bookmark)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => self.bookmarks_database.upsert(&bookmark)?,
|
||||||
|
}
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,8 @@ impl<'handler> Handler<'handler> {
|
|||||||
events::Event::Fetch => self.fetch_project_handler.handle(),
|
events::Event::Fetch => self.fetch_project_handler.handle(),
|
||||||
|
|
||||||
events::Event::File((session_id, file_path, contents)) => {
|
events::Event::File((session_id, file_path, contents)) => {
|
||||||
self.index_handler
|
let file_events = self
|
||||||
|
.index_handler
|
||||||
.index_file(&session_id, file_path.to_str().unwrap(), &contents)
|
.index_file(&session_id, file_path.to_str().unwrap(), &contents)
|
||||||
.context("failed to index file")?;
|
.context("failed to index file")?;
|
||||||
self.events_sender
|
self.events_sender
|
||||||
@ -150,19 +151,21 @@ impl<'handler> Handler<'handler> {
|
|||||||
&contents,
|
&contents,
|
||||||
))
|
))
|
||||||
.context("failed to send file event")?;
|
.context("failed to send file event")?;
|
||||||
Ok(vec![])
|
Ok(file_events)
|
||||||
}
|
}
|
||||||
events::Event::Session(session) => {
|
events::Event::Session(session) => {
|
||||||
self.index_handler
|
let session_events = self
|
||||||
|
.index_handler
|
||||||
.index_session(&session)
|
.index_session(&session)
|
||||||
.context("failed to index session")?;
|
.context("failed to index session")?;
|
||||||
self.events_sender
|
self.events_sender
|
||||||
.send(app_events::Event::session(&self.project_id, &session))
|
.send(app_events::Event::session(&self.project_id, &session))
|
||||||
.context("failed to send session event")?;
|
.context("failed to send session event")?;
|
||||||
Ok(vec![])
|
Ok(session_events)
|
||||||
}
|
}
|
||||||
events::Event::Deltas((session_id, path, deltas)) => {
|
events::Event::Deltas((session_id, path, deltas)) => {
|
||||||
self.index_handler
|
let delta_events = self
|
||||||
|
.index_handler
|
||||||
.index_deltas(&session_id, path.to_str().unwrap(), &deltas)
|
.index_deltas(&session_id, path.to_str().unwrap(), &deltas)
|
||||||
.context("failed to index deltas")?;
|
.context("failed to index deltas")?;
|
||||||
self.events_sender
|
self.events_sender
|
||||||
@ -173,8 +176,12 @@ impl<'handler> Handler<'handler> {
|
|||||||
&path,
|
&path,
|
||||||
))
|
))
|
||||||
.context("failed to send deltas event")?;
|
.context("failed to send deltas event")?;
|
||||||
Ok(vec![])
|
Ok(delta_events)
|
||||||
}
|
}
|
||||||
|
events::Event::Bookmark(bookmark) => self
|
||||||
|
.index_handler
|
||||||
|
.index_bookmark(&bookmark)
|
||||||
|
.context("failed to index bookmark"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
src/lib/api/ipc/bookmarks.ts
Normal file
12
src/lib/api/ipc/bookmarks.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { invoke } from '$lib/ipc';
|
||||||
|
|
||||||
|
export type Bookmark = {
|
||||||
|
id: string;
|
||||||
|
projectId: string;
|
||||||
|
createdTimestampMs: number;
|
||||||
|
updatedTimestampMs: number;
|
||||||
|
note: string;
|
||||||
|
deleted: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const upsert = (params: { bookmark: Bookmark }) => invoke<void>('upsert_bookmark', params);
|
@ -11,6 +11,7 @@ export * as searchResults from './search';
|
|||||||
export { type SearchResult } from './search';
|
export { type SearchResult } from './search';
|
||||||
export * as files from './files';
|
export * as files from './files';
|
||||||
export * as zip from './zip';
|
export * as zip from './zip';
|
||||||
|
export * as bookmarks from './bookmarks';
|
||||||
|
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user