mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-25 10:33:21 +03:00
merge upstream
This commit is contained in:
commit
f760857e8b
@ -85,11 +85,11 @@ const withLog: FetchMiddleware = (fetch) => async (url, options) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (
|
export function getCloudApiClient(
|
||||||
{ fetch: realFetch }: { fetch: typeof window.fetch } = {
|
{ fetch: realFetch }: { fetch: typeof window.fetch } = {
|
||||||
fetch: window.fetch
|
fetch: window.fetch
|
||||||
}
|
}
|
||||||
) => {
|
) {
|
||||||
const fetch = fetchWith(realFetch, withRequestId, withLog);
|
const fetch = fetchWith(realFetch, withRequestId, withLog);
|
||||||
return {
|
return {
|
||||||
login: {
|
login: {
|
||||||
@ -278,4 +278,4 @@ export default (
|
|||||||
}).then(parseResponseJSON)
|
}).then(parseResponseJSON)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
@ -1,2 +1 @@
|
|||||||
export { default as Api } from './api';
|
|
||||||
export type { User, LoginToken, Project } from './api';
|
export type { User, LoginToken, Project } from './api';
|
||||||
|
@ -20,7 +20,7 @@ export function subscribe(
|
|||||||
|
|
||||||
const stores: Record<string, WritableLoadable<Activity[]>> = {};
|
const stores: Record<string, WritableLoadable<Activity[]>> = {};
|
||||||
|
|
||||||
export function Activities(params: { projectId: string }) {
|
export function getActivitiesStore(params: { projectId: string }) {
|
||||||
if (stores[params.projectId]) return stores[params.projectId];
|
if (stores[params.projectId]) return stores[params.projectId];
|
||||||
|
|
||||||
const store = asyncWritable([], () => list(params));
|
const store = asyncWritable([], () => list(params));
|
@ -1,6 +1,7 @@
|
|||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
import { asyncWritable, type WritableLoadable } from '@square/svelte-store';
|
import { asyncWritable, type WritableLoadable } from '@square/svelte-store';
|
||||||
import { sessions, git } from '$lib/api';
|
import * as activities from './activities';
|
||||||
|
import * as sessions from '../ipc/sessions';
|
||||||
|
|
||||||
const list = (params: { projectId: string; contextLines?: number }) =>
|
const list = (params: { projectId: string; contextLines?: number }) =>
|
||||||
invoke<Record<string, string>>('git_wd_diff', {
|
invoke<Record<string, string>>('git_wd_diff', {
|
||||||
@ -10,10 +11,10 @@ const list = (params: { projectId: string; contextLines?: number }) =>
|
|||||||
|
|
||||||
const stores: Record<string, WritableLoadable<Record<string, string>>> = {};
|
const stores: Record<string, WritableLoadable<Record<string, string>>> = {};
|
||||||
|
|
||||||
export function Diffs(params: { projectId: string }) {
|
export function getDiffsStore(params: { projectId: string }) {
|
||||||
if (stores[params.projectId]) return stores[params.projectId];
|
if (stores[params.projectId]) return stores[params.projectId];
|
||||||
const store = asyncWritable([], () => list(params));
|
const store = asyncWritable([], () => list(params));
|
||||||
git.activities.subscribe(params, ({ projectId }) => list({ projectId }).then(store.set));
|
activities.subscribe(params, ({ projectId }) => list({ projectId }).then(store.set));
|
||||||
sessions.subscribe(params, () => list(params).then(store.set));
|
sessions.subscribe(params, () => list(params).then(store.set));
|
||||||
stores[params.projectId] = store;
|
stores[params.projectId] = store;
|
||||||
return store;
|
return store;
|
@ -16,7 +16,7 @@ export function subscribe(
|
|||||||
|
|
||||||
const stores: Record<string, WritableLoadable<string>> = {};
|
const stores: Record<string, WritableLoadable<string>> = {};
|
||||||
|
|
||||||
export function Head(params: { projectId: string }) {
|
export function getHeadStore(params: { projectId: string }) {
|
||||||
if (stores[params.projectId]) return stores[params.projectId];
|
if (stores[params.projectId]) return stores[params.projectId];
|
||||||
const store = asyncWritable([], () =>
|
const store = asyncWritable([], () =>
|
||||||
get(params).then((head) => head.replace('refs/heads/', ''))
|
get(params).then((head) => head.replace('refs/heads/', ''))
|
@ -1,11 +1,4 @@
|
|||||||
export * as statuses from './statuses';
|
|
||||||
export { Status } from './statuses';
|
|
||||||
export * as activities from './activities';
|
|
||||||
export type { Activity } from './activities';
|
export type { Activity } from './activities';
|
||||||
export * as heads from './heads';
|
|
||||||
export * as diffs from './diffs';
|
|
||||||
export * as indexes from './indexes';
|
|
||||||
export * as fetches from './fetches';
|
|
||||||
|
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
|
|
@ -2,7 +2,7 @@ import { invoke } from '$lib/ipc';
|
|||||||
import { asyncWritable, type WritableLoadable } from '@square/svelte-store';
|
import { asyncWritable, type WritableLoadable } from '@square/svelte-store';
|
||||||
import * as indexes from './indexes';
|
import * as indexes from './indexes';
|
||||||
import * as activities from './activities';
|
import * as activities from './activities';
|
||||||
import * as sessions from '../sessions';
|
import * as sessions from '../ipc/sessions';
|
||||||
|
|
||||||
type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'typeChange' | 'other';
|
type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'typeChange' | 'other';
|
||||||
|
|
||||||
@ -11,13 +11,11 @@ export type Status =
|
|||||||
| { unstaged: FileStatus }
|
| { unstaged: FileStatus }
|
||||||
| { staged: FileStatus; unstaged: FileStatus };
|
| { staged: FileStatus; unstaged: FileStatus };
|
||||||
|
|
||||||
export namespace Status {
|
export function isStaged(status: Status): status is { staged: FileStatus } {
|
||||||
export function isStaged(status: Status): status is { staged: FileStatus } {
|
|
||||||
return 'staged' in status && status.staged !== null;
|
return 'staged' in status && status.staged !== null;
|
||||||
}
|
}
|
||||||
export function isUnstaged(status: Status): status is { unstaged: FileStatus } {
|
export function isUnstaged(status: Status): status is { unstaged: FileStatus } {
|
||||||
return 'unstaged' in status && status.unstaged !== null;
|
return 'unstaged' in status && status.unstaged !== null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function list(params: { projectId: string }) {
|
export function list(params: { projectId: string }) {
|
||||||
@ -26,7 +24,7 @@ export function list(params: { projectId: string }) {
|
|||||||
|
|
||||||
const stores: Record<string, WritableLoadable<Record<string, Status>>> = {};
|
const stores: Record<string, WritableLoadable<Record<string, Status>>> = {};
|
||||||
|
|
||||||
export function Statuses(params: { projectId: string }) {
|
export function getStatusStore(params: { projectId: string }) {
|
||||||
if (stores[params.projectId]) return stores[params.projectId];
|
if (stores[params.projectId]) return stores[params.projectId];
|
||||||
const store = asyncWritable([], () => list(params));
|
const store = asyncWritable([], () => list(params));
|
||||||
sessions.subscribe(params, () => list(params).then(store.set));
|
sessions.subscribe(params, () => list(params).then(store.set));
|
@ -1,2 +0,0 @@
|
|||||||
export * from './ipc';
|
|
||||||
export { Api as CloudApi, type User, type LoginToken } from './cloud';
|
|
@ -5,14 +5,12 @@ export type OperationInsert = { insert: [number, string] };
|
|||||||
|
|
||||||
export type Operation = OperationDelete | OperationInsert;
|
export type Operation = OperationDelete | OperationInsert;
|
||||||
|
|
||||||
export namespace Operation {
|
export function isDelete(operation: Operation): operation is OperationDelete {
|
||||||
export function isDelete(operation: Operation): operation is OperationDelete {
|
|
||||||
return 'delete' in operation;
|
return 'delete' in operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInsert(operation: Operation): operation is OperationInsert {
|
export function isInsert(operation: Operation): operation is OperationInsert {
|
||||||
return 'insert' in operation;
|
return 'insert' in operation;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Delta = { timestampMs: number; operations: Operation[] };
|
export type Delta = { timestampMs: number; operations: Operation[] };
|
||||||
|
@ -1,19 +1,3 @@
|
|||||||
export * as git from './git';
|
|
||||||
export { Status, type Activity } from './git';
|
|
||||||
export * as deltas from './deltas';
|
|
||||||
export { type Delta, Operation } from './deltas';
|
|
||||||
export * as sessions from './sessions';
|
|
||||||
export { Session } from './sessions';
|
|
||||||
export * as users from './users';
|
|
||||||
export * as projects from './projects';
|
|
||||||
export type { Project } from './projects';
|
|
||||||
export * as searchResults from './search';
|
|
||||||
export { type SearchResult } from './search';
|
|
||||||
export * as files from './files';
|
|
||||||
export * as zip from './zip';
|
|
||||||
export * as bookmarks from './bookmarks';
|
|
||||||
export type { Bookmark } from './bookmarks';
|
|
||||||
|
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
|
|
||||||
export function deleteAllData() {
|
export function deleteAllData() {
|
||||||
|
@ -38,7 +38,7 @@ export function del(params: { id: string }) {
|
|||||||
|
|
||||||
const store = asyncWritable([], list);
|
const store = asyncWritable([], list);
|
||||||
|
|
||||||
export function Project({ id }: { id: string }) {
|
export function getProjectStore({ id }: { id: string }) {
|
||||||
return {
|
return {
|
||||||
...derived(store, (projects) => projects?.find((p) => p.id === id)),
|
...derived(store, (projects) => projects?.find((p) => p.id === id)),
|
||||||
update: (params: Partial<Pick<Project, 'title' | 'description' | 'api'>>) =>
|
update: (params: Partial<Pick<Project, 'title' | 'description' | 'api'>>) =>
|
||||||
@ -56,13 +56,11 @@ export function Project({ id }: { id: string }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Projects() {
|
export const projectsStore = {
|
||||||
return {
|
|
||||||
...store,
|
...store,
|
||||||
add: (params: { path: string }) =>
|
add: (params: { path: string }) =>
|
||||||
add(params).then((project) => {
|
add(params).then((project) => {
|
||||||
store.update((projects) => [...projects, project]);
|
store.update((projects) => [...projects, project]);
|
||||||
return project;
|
return project;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
@ -42,7 +42,8 @@ export function subscribe(
|
|||||||
|
|
||||||
const stores: Record<string, WritableLoadable<Session[]>> = {};
|
const stores: Record<string, WritableLoadable<Session[]>> = {};
|
||||||
|
|
||||||
export function Sessions(params: { projectId: string }) {
|
// TODO: Figure out why this extra store exists.
|
||||||
|
export function getSessionStore(params: { projectId: string }) {
|
||||||
if (params.projectId in stores) return stores[params.projectId];
|
if (params.projectId in stores) return stores[params.projectId];
|
||||||
const store = asyncWritable([], () => list(params));
|
const store = asyncWritable([], () => list(params));
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import type { User } from '$lib/api';
|
import type { User } from '../cloud/api';
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
|
|
||||||
export async function get() {
|
export async function get() {
|
||||||
return invoke<User | null>('get_user');
|
return invoke<User | null>('get_user');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set(params: { user: User }) {
|
export async function set(params: { user: User }) {
|
||||||
invoke<void>('set_user', params);
|
invoke<void>('set_user', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import tinykeys from 'tinykeys';
|
import tinykeys from 'tinykeys';
|
||||||
import type { Project } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { derived, readable, writable, type Readable } from '@square/svelte-store';
|
import { derived, readable, writable, type Readable } from '@square/svelte-store';
|
||||||
import { Overlay } from '$lib/components';
|
import { Overlay } from '$lib/components';
|
||||||
import listAvailableCommands, { Action, type Group } from './commands';
|
import listAvailableCommands, { Action, type Group } from './commands';
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { type Project, git } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
|
import { matchFiles } from '$lib/api/git';
|
||||||
import { events } from '$lib';
|
import { events } from '$lib';
|
||||||
import {
|
import {
|
||||||
IconGitCommit,
|
IconGitCommit,
|
||||||
@ -180,7 +181,7 @@ const fileGroup = ({
|
|||||||
description: 'type part of a file name',
|
description: 'type part of a file name',
|
||||||
commands: []
|
commands: []
|
||||||
}
|
}
|
||||||
: git.matchFiles({ projectId: project.id, matchPattern: input }).then((files) => ({
|
: matchFiles({ projectId: project.id, matchPattern: input }).then((files) => ({
|
||||||
title: 'Files',
|
title: 'Files',
|
||||||
description: files.length === 0 ? `no files containing '${input}'` : '',
|
description: files.length === 0 ? `no files containing '${input}'` : '',
|
||||||
commands: files.map((file) => ({
|
commands: files.map((file) => ({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type Delta, Operation } from '$lib/api';
|
import { isInsert, type Delta, isDelete } from '$lib/api/ipc/deltas';
|
||||||
import { Differ } from '$lib/components';
|
import Differ from './Differ';
|
||||||
import { line } from '$lib/diff';
|
import { line } from '$lib/diff';
|
||||||
|
|
||||||
export let doc: string;
|
export let doc: string;
|
||||||
@ -13,12 +13,12 @@
|
|||||||
const operations = deltas.flatMap((delta) => delta.operations);
|
const operations = deltas.flatMap((delta) => delta.operations);
|
||||||
|
|
||||||
operations.forEach((operation) => {
|
operations.forEach((operation) => {
|
||||||
if (Operation.isInsert(operation)) {
|
if (isInsert(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.insert[0]) +
|
text.slice(0, operation.insert[0]) +
|
||||||
operation.insert[1] +
|
operation.insert[1] +
|
||||||
text.slice(operation.insert[0]);
|
text.slice(operation.insert[0]);
|
||||||
} else if (Operation.isDelete(operation)) {
|
} else if (isDelete(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.delete[0]) +
|
text.slice(0, operation.delete[0]) +
|
||||||
text.slice(operation.delete[0] + operation.delete[1]);
|
text.slice(operation.delete[0] + operation.delete[1]);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type LoginToken, CloudApi } from '$lib/api';
|
import { getCloudApiClient, type LoginToken } from '$lib/api/cloud/api';
|
||||||
import { toasts, stores } from '$lib';
|
import { toasts } from '$lib';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
import { derived, writable } from '@square/svelte-store';
|
import { derived, writable } from '@square/svelte-store';
|
||||||
import { open } from '@tauri-apps/api/shell';
|
import { open } from '@tauri-apps/api/shell';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
const cloud = CloudApi();
|
const cloud = getCloudApiClient();
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
export let width: 'basic' | 'full-width' = 'basic';
|
export let width: 'basic' | 'full-width' = 'basic';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { collapse } from '$lib/paths';
|
import { collapse } from '$lib/paths';
|
||||||
import { Status } from '$lib/api';
|
import { isStaged, isUnstaged, type Status } from '$lib/api/git/statuses';
|
||||||
|
|
||||||
export let statuses: Record<string, Status>;
|
export let statuses: Record<string, Status>;
|
||||||
</script>
|
</script>
|
||||||
@ -27,12 +27,12 @@
|
|||||||
<li class="flex w-full gap-2">
|
<li class="flex w-full gap-2">
|
||||||
<div class="flex w-[3ch] justify-between font-semibold">
|
<div class="flex w-[3ch] justify-between font-semibold">
|
||||||
<span>
|
<span>
|
||||||
{#if Status.isStaged(status)}
|
{#if isStaged(status)}
|
||||||
{status.staged.slice(0, 1).toUpperCase()}
|
{status.staged.slice(0, 1).toUpperCase()}
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{#if Status.isUnstaged(status)}
|
{#if isUnstaged(status)}
|
||||||
{status.unstaged.slice(0, 1).toUpperCase()}
|
{status.unstaged.slice(0, 1).toUpperCase()}
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
export * as api from './api';
|
|
||||||
export * as toasts from './toasts';
|
export * as toasts from './toasts';
|
||||||
export { Toaster } from './toasts';
|
export { Toaster } from './toasts';
|
||||||
export * as week from './week';
|
export * as week from './week';
|
||||||
@ -6,4 +5,3 @@ export * as uisessions from './uisessions';
|
|||||||
export * as events from './events';
|
export * as events from './events';
|
||||||
export * as hotkeys from './hotkeys';
|
export * as hotkeys from './hotkeys';
|
||||||
export * as diff from './diff';
|
export * as diff from './diff';
|
||||||
export * as stores from './stores';
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import posthog from 'posthog-js';
|
import posthog from 'posthog-js';
|
||||||
import { PUBLIC_POSTHOG_API_KEY } from '$env/static/public';
|
import { PUBLIC_POSTHOG_API_KEY } from '$env/static/public';
|
||||||
import type { User } from '$lib/api';
|
import type { User } from './api/cloud/api';
|
||||||
import { getVersion, getName } from '@tauri-apps/api/app';
|
import { getVersion, getName } from '@tauri-apps/api/app';
|
||||||
|
|
||||||
interface PostHogClient {
|
interface PostHogClient {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { setUser } from '@sentry/sveltekit';
|
import { setUser } from '@sentry/sveltekit';
|
||||||
import type { User } from '$lib/api';
|
import type { User } from './api/cloud/api';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return {
|
return {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { writable, type Loadable, derived, Loaded } from 'svelte-loadable-store';
|
import { writable, type Loadable, derived, Loaded } from 'svelte-loadable-store';
|
||||||
import { bookmarks, type Bookmark } from '$lib/api';
|
import * as bookmarks from '$lib/api/ipc/bookmarks';
|
||||||
import { get as getValue, type Readable } from '@square/svelte-store';
|
import { get as getValue, type Readable } from '@square/svelte-store';
|
||||||
|
|
||||||
const stores: Record<string, Readable<Loadable<Bookmark[]>>> = {};
|
const stores: Record<string, Readable<Loadable<bookmarks.Bookmark[]>>> = {};
|
||||||
|
|
||||||
export function list(params: { projectId: string }) {
|
export function getBookmarksStore(params: { projectId: string }) {
|
||||||
if (params.projectId in stores) return stores[params.projectId];
|
if (params.projectId in stores) return stores[params.projectId];
|
||||||
|
|
||||||
const store = writable(bookmarks.list(params), (set) => {
|
const store = writable(bookmarks.list(params), (set) => {
|
||||||
@ -23,11 +23,11 @@ export function list(params: { projectId: string }) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
stores[params.projectId] = store;
|
stores[params.projectId] = store;
|
||||||
return store as Readable<Loadable<Bookmark[]>>;
|
return store as Readable<Loadable<bookmarks.Bookmark[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get(params: { projectId: string; timestampMs: number }) {
|
export function getBookmark(params: { projectId: string; timestampMs: number }) {
|
||||||
return derived(list({ projectId: params.projectId }), (bookmarks) =>
|
return derived(getBookmarksStore({ projectId: params.projectId }), (bookmarks) =>
|
||||||
bookmarks.find((b) => b.timestampMs === params.timestampMs)
|
bookmarks.find((b) => b.timestampMs === params.timestampMs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
||||||
import { deltas, type Delta } from '$lib/api';
|
import * as deltas from '$lib/api/ipc/deltas';
|
||||||
import { get, type Readable } from '@square/svelte-store';
|
import { get, type Readable } from '@square/svelte-store';
|
||||||
|
|
||||||
const stores: Record<string, Readable<Loadable<Record<string, Delta[]>>>> = {};
|
const stores: Record<string, Readable<Loadable<Record<string, deltas.Delta[]>>>> = {};
|
||||||
|
|
||||||
export default (params: { projectId: string; sessionId: string }) => {
|
export function getDeltasStore(params: { projectId: string; sessionId: string }) {
|
||||||
const key = `${params.projectId}/${params.sessionId}`;
|
const key = `${params.projectId}/${params.sessionId}`;
|
||||||
if (key in stores) return stores[key];
|
if (key in stores) return stores[key];
|
||||||
|
|
||||||
@ -29,5 +29,5 @@ export default (params: { projectId: string; sessionId: string }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
stores[key] = store;
|
stores[key] = store;
|
||||||
return store as Readable<Loadable<Record<string, Delta[]>>>;
|
return store as Readable<Loadable<Record<string, deltas.Delta[]>>>;
|
||||||
};
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
||||||
import { files } from '$lib/api';
|
import * as files from '$lib/api/ipc/files';
|
||||||
import { get, type Readable } from '@square/svelte-store';
|
import { get, type Readable } from '@square/svelte-store';
|
||||||
|
|
||||||
const stores: Record<string, Readable<Loadable<Record<string, string>>>> = {};
|
const stores: Record<string, Readable<Loadable<Record<string, string>>>> = {};
|
||||||
|
|
||||||
export default (params: { projectId: string; sessionId: string }) => {
|
export function getFilesStore(params: { projectId: string; sessionId: string }) {
|
||||||
const key = `${params.projectId}/${params.sessionId}`;
|
const key = `${params.projectId}/${params.sessionId}`;
|
||||||
if (key in stores) return stores[key];
|
if (key in stores) return stores[key];
|
||||||
|
|
||||||
@ -28,4 +28,4 @@ export default (params: { projectId: string; sessionId: string }) => {
|
|||||||
});
|
});
|
||||||
stores[key] = store;
|
stores[key] = store;
|
||||||
return store as Readable<Loadable<Record<string, string>>>;
|
return store as Readable<Loadable<Record<string, string>>>;
|
||||||
};
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
export { default as user } from './user';
|
|
||||||
export * as bookmarks from './bookmarks';
|
|
||||||
export { default as deltas } from './deltas';
|
|
||||||
export { default as sessions } from './sessions';
|
|
||||||
export { default as files } from './files';
|
|
@ -1,10 +1,10 @@
|
|||||||
import { derived, writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
import { derived, writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
||||||
import { sessions, type Session } from '$lib/api';
|
import * as sessions from '$lib/api/ipc/sessions';
|
||||||
import { get, type Readable } from '@square/svelte-store';
|
import { get, type Readable } from '@square/svelte-store';
|
||||||
|
|
||||||
const stores: Record<string, Readable<Loadable<Session[]>>> = {};
|
const stores: Record<string, Readable<Loadable<sessions.Session[]>>> = {};
|
||||||
|
|
||||||
export default (params: { projectId: string }) => {
|
export function getSessionStore(params: { projectId: string }) {
|
||||||
if (params.projectId in stores) return stores[params.projectId];
|
if (params.projectId in stores) return stores[params.projectId];
|
||||||
|
|
||||||
const store = derived(
|
const store = derived(
|
||||||
@ -12,7 +12,7 @@ export default (params: { projectId: string }) => {
|
|||||||
const unsubscribe = sessions.subscribe(params, ({ session }) => {
|
const unsubscribe = sessions.subscribe(params, ({ session }) => {
|
||||||
const oldValue = get(store);
|
const oldValue = get(store);
|
||||||
if (oldValue.isLoading) {
|
if (oldValue.isLoading) {
|
||||||
sessions.list(params).then(set);
|
sessions.list(params).then((x) => set(x));
|
||||||
} else if (Loaded.isError(oldValue)) {
|
} else if (Loaded.isError(oldValue)) {
|
||||||
sessions.list(params).then(set);
|
sessions.list(params).then(set);
|
||||||
} else {
|
} else {
|
||||||
@ -33,5 +33,5 @@ export default (params: { projectId: string }) => {
|
|||||||
(sessions) => sessions.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs)
|
(sessions) => sessions.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs)
|
||||||
);
|
);
|
||||||
stores[params.projectId] = store;
|
stores[params.projectId] = store;
|
||||||
return store as Readable<Loadable<Session[]>>;
|
return store;
|
||||||
};
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { users } from '$lib/api';
|
import * as users from '$lib/api/ipc/users';
|
||||||
import { asyncWritable } from '@square/svelte-store';
|
import { asyncWritable } from '@square/svelte-store';
|
||||||
|
|
||||||
const store = asyncWritable([], users.get, async (user) => {
|
export const userStore = asyncWritable([], users.get, async (user) => {
|
||||||
if (user === null) {
|
if (user === null) {
|
||||||
await users.delete();
|
await users.delete();
|
||||||
} else {
|
} else {
|
||||||
@ -9,5 +9,3 @@ const store = asyncWritable([], users.get, async (user) => {
|
|||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default store;
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CloudApi } from '$lib/api';
|
import { getCloudApiClient } from './api/cloud/api';
|
||||||
import lscache from 'lscache';
|
import lscache from 'lscache';
|
||||||
const cloud = CloudApi();
|
|
||||||
|
const cloud = getCloudApiClient();
|
||||||
|
|
||||||
export async function summarizeHunk(diff: string): Promise<string> {
|
export async function summarizeHunk(diff: string): Promise<string> {
|
||||||
const diffHash = hash(diff);
|
const diffHash = hash(diff);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { Session, Delta } from '$lib/api';
|
import type { Delta } from './api/ipc/deltas';
|
||||||
|
import type { Session } from './api/ipc/sessions';
|
||||||
|
|
||||||
export type UISession = {
|
export type UISession = {
|
||||||
session: Session;
|
session: Session;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
|
||||||
import type { Session, Delta } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
import { Operation } from '$lib/api';
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
import type { Readable } from '@square/svelte-store';
|
import type { Readable } from '@square/svelte-store';
|
||||||
import { deltas, git } from '$lib/api/ipc';
|
import * as fetches from '$lib/api/git/fetches';
|
||||||
import { stores } from '$lib';
|
import * as deltas from '$lib/api/ipc/deltas';
|
||||||
import { BaseBranch, Branch, BranchData } from './types';
|
import { BaseBranch, Branch, BranchData } from './types';
|
||||||
import { plainToInstance } from 'class-transformer';
|
import { plainToInstance } from 'class-transformer';
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
|
import { isDelete, isInsert } from '$lib/api/ipc/deltas';
|
||||||
|
|
||||||
export interface Refreshable {
|
export interface Refreshable {
|
||||||
refresh(): Promise<void | object>;
|
refresh(): Promise<void | object>;
|
||||||
@ -24,7 +25,7 @@ export class BranchStoresCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const writableStore = writable(listVirtualBranches({ projectId }), (set) => {
|
const writableStore = writable(listVirtualBranches({ projectId }), (set) => {
|
||||||
return stores.sessions({ projectId }).subscribe((sessions) => {
|
return getSessionStore({ projectId }).subscribe((sessions) => {
|
||||||
if (sessions.isLoading) return;
|
if (sessions.isLoading) return;
|
||||||
if (Loaded.isError(sessions)) return;
|
if (Loaded.isError(sessions)) return;
|
||||||
const lastSession = sessions.value.at(-1);
|
const lastSession = sessions.value.at(-1);
|
||||||
@ -70,7 +71,7 @@ export class BranchStoresCache {
|
|||||||
return cachedStore;
|
return cachedStore;
|
||||||
}
|
}
|
||||||
const writableStore = writable(getRemoteBranchesData({ projectId }), (set) => {
|
const writableStore = writable(getRemoteBranchesData({ projectId }), (set) => {
|
||||||
git.fetches.subscribe({ projectId }, () => {
|
fetches.subscribe({ projectId }, () => {
|
||||||
getRemoteBranchesData({ projectId }).then(set);
|
getRemoteBranchesData({ projectId }).then(set);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -91,7 +92,7 @@ export class BranchStoresCache {
|
|||||||
return cachedStore;
|
return cachedStore;
|
||||||
}
|
}
|
||||||
const writableStore = writable(getBaseBranchData({ projectId }), (set) => {
|
const writableStore = writable(getBaseBranchData({ projectId }), (set) => {
|
||||||
git.fetches.subscribe({ projectId }, () => {
|
fetches.subscribe({ projectId }, () => {
|
||||||
getBaseBranchData({ projectId }).then(set);
|
getBaseBranchData({ projectId }).then(set);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -133,7 +134,7 @@ async function branchesWithFileContent(projectId: string, sessionId: string, bra
|
|||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
paths: filePaths
|
paths: filePaths
|
||||||
});
|
});
|
||||||
const sessionDeltas = await invoke<Record<string, Delta[]>>('list_deltas', {
|
const sessionDeltas = await invoke<Record<string, deltas.Delta[]>>('list_deltas', {
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
paths: filePaths
|
paths: filePaths
|
||||||
@ -141,22 +142,22 @@ async function branchesWithFileContent(projectId: string, sessionId: string, bra
|
|||||||
const branchesWithContnent = branches.map((branch) => {
|
const branchesWithContnent = branches.map((branch) => {
|
||||||
branch.files.map((file) => {
|
branch.files.map((file) => {
|
||||||
const contentAtSessionStart = sessionFiles[file.path];
|
const contentAtSessionStart = sessionFiles[file.path];
|
||||||
const deltas = sessionDeltas[file.path];
|
const ds = sessionDeltas[file.path];
|
||||||
file.content = applyDeltas(contentAtSessionStart, deltas);
|
file.content = applyDeltas(contentAtSessionStart, ds);
|
||||||
});
|
});
|
||||||
return branch;
|
return branch;
|
||||||
});
|
});
|
||||||
return branchesWithContnent;
|
return branchesWithContnent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDeltas(text: string, deltas: Delta[]) {
|
function applyDeltas(text: string, ds: deltas.Delta[]) {
|
||||||
if (!deltas) return text;
|
if (!ds) return text;
|
||||||
const operations = deltas.flatMap((delta) => delta.operations);
|
const operations = ds.flatMap((delta) => delta.operations);
|
||||||
operations.forEach((operation) => {
|
operations.forEach((operation) => {
|
||||||
if (Operation.isInsert(operation)) {
|
if (isInsert(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.insert[0]) + operation.insert[1] + text.slice(operation.insert[0]);
|
text.slice(0, operation.insert[0]) + operation.insert[1] + text.slice(operation.insert[0]);
|
||||||
} else if (Operation.isDelete(operation)) {
|
} else if (isDelete(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.delete[0]) + text.slice(operation.delete[0] + operation.delete[1]);
|
text.slice(0, operation.delete[0]) + text.slice(operation.delete[0] + operation.delete[1]);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* Virtual Branch feature package (experiment)
|
|
||||||
*
|
|
||||||
* There are three interesting data types coming from the rust IPC api:
|
|
||||||
* - Branch, representing a virtual branch
|
|
||||||
* - BranchData, representing a remote branch
|
|
||||||
* - BaseBranch, representing a target base remote branch
|
|
||||||
*
|
|
||||||
* The three types are obtained as reactive stores from the BranchStoresCache's methods:
|
|
||||||
* - getVirtualBranchStore - List of Branch (virtual branches)
|
|
||||||
* - getRemoteBranchStore - List of BranchData (remote branches)
|
|
||||||
* - getBaseBranchStore - BaseBranch (single target branch)
|
|
||||||
*
|
|
||||||
* BranchController is a class where all virtual branch operations are performed
|
|
||||||
* This class gets the three stores injected at construction so that any related updates can be peformed
|
|
||||||
*
|
|
||||||
* Note to self:
|
|
||||||
*
|
|
||||||
* - Create the BranchStoresCacheat the top level (where projects are listed),
|
|
||||||
* so that it can take advantage of caching, making project navigation quicker.
|
|
||||||
* - Create the BranchController at the level of a specific project and inject it to components that need it.
|
|
||||||
*/
|
|
||||||
export { Branch, File, Hunk, Commit, BranchData, BaseBranch } from './types';
|
|
||||||
export { BranchStoresCache } from './branchStoresCache';
|
|
||||||
export { BranchController } from './branchController';
|
|
@ -2,7 +2,8 @@
|
|||||||
import '../styles/main.postcss';
|
import '../styles/main.postcss';
|
||||||
|
|
||||||
import { open } from '@tauri-apps/api/dialog';
|
import { open } from '@tauri-apps/api/dialog';
|
||||||
import { toasts, Toaster, events, hotkeys, stores } from '$lib';
|
import { toasts, Toaster, events, hotkeys } from '$lib';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
import type { LayoutData } from './$types';
|
import type { LayoutData } from './$types';
|
||||||
import { Link, Tooltip } from '$lib/components';
|
import { Link, Tooltip } from '$lib/components';
|
||||||
import { IconEmail } from '$lib/icons';
|
import { IconEmail } from '$lib/icons';
|
||||||
@ -20,7 +21,7 @@
|
|||||||
export let data: LayoutData;
|
export let data: LayoutData;
|
||||||
const { posthog, projects, sentry, cloud } = data;
|
const { posthog, projects, sentry, cloud } = data;
|
||||||
|
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
const userSettings = loadUserSettings();
|
const userSettings = loadUserSettings();
|
||||||
initTheme(userSettings);
|
initTheme(userSettings);
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import type { LayoutLoad } from './$types';
|
import type { LayoutLoad } from './$types';
|
||||||
import { api } from '$lib';
|
import { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
|
import { projectsStore } from '$lib/api/ipc/projects';
|
||||||
import Posthog from '$lib/posthog';
|
import Posthog from '$lib/posthog';
|
||||||
import Sentry from '$lib/sentry';
|
import Sentry from '$lib/sentry';
|
||||||
import { BranchStoresCache } from '$lib/vbranches';
|
import { BranchStoresCache } from '$lib/vbranches/branchStoresCache';
|
||||||
|
|
||||||
export const ssr = false;
|
export const ssr = false;
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
export const csr = true;
|
export const csr = true;
|
||||||
|
|
||||||
export const load: LayoutLoad = ({ fetch: realFetch }: { fetch: typeof fetch }) => ({
|
export const load: LayoutLoad = ({ fetch: realFetch }: { fetch: typeof fetch }) => ({
|
||||||
projects: api.projects.Projects(),
|
projects: projectsStore,
|
||||||
cloud: api.CloudApi({ fetch: realFetch }),
|
cloud: getCloudApiClient({ fetch: realFetch }),
|
||||||
branchStoresCache: new BranchStoresCache(),
|
branchStoresCache: new BranchStoresCache(),
|
||||||
posthog: Posthog(),
|
posthog: Posthog(),
|
||||||
sentry: Sentry()
|
sentry: Sentry()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Project } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { IconHome } from '$lib/icons';
|
import { IconHome } from '$lib/icons';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
|
@ -4,28 +4,29 @@
|
|||||||
import { asyncDerived } from '@square/svelte-store';
|
import { asyncDerived } from '@square/svelte-store';
|
||||||
import { compareDesc, formatDistanceToNow } from 'date-fns';
|
import { compareDesc, formatDistanceToNow } from 'date-fns';
|
||||||
import { IconFolder, IconLoading } from '$lib/icons';
|
import { IconFolder, IconLoading } from '$lib/icons';
|
||||||
import { toasts, api, stores } from '$lib';
|
import type { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
|
import { getProjectStore, projectsStore } from '$lib/api/ipc/projects';
|
||||||
|
import * as toasts from '$lib/toasts';
|
||||||
import IconFolderPlus from '$lib/icons/IconFolderPlus.svelte';
|
import IconFolderPlus from '$lib/icons/IconFolderPlus.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
export let projects: ReturnType<typeof api.projects.Projects>;
|
export let projects: typeof projectsStore;
|
||||||
export let cloud: ReturnType<typeof api.CloudApi>;
|
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||||
|
|
||||||
const user = stores.user;
|
const cloudProjects = asyncDerived(userStore, async (user) =>
|
||||||
|
|
||||||
const cloudProjects = asyncDerived(user, async (user) =>
|
|
||||||
user ? await cloud.projects.list(user.access_token) : []
|
user ? await cloud.projects.list(user.access_token) : []
|
||||||
);
|
);
|
||||||
|
|
||||||
let selectedRepositoryId: string | null = null;
|
let selectedRepositoryId: string | null = null;
|
||||||
|
|
||||||
let project: ReturnType<typeof api.projects.Project> | undefined;
|
let project: ReturnType<typeof getProjectStore> | undefined;
|
||||||
|
|
||||||
export async function show(id: string) {
|
export async function show(id: string) {
|
||||||
await user.load();
|
await userStore.load();
|
||||||
await cloudProjects.load();
|
await cloudProjects.load();
|
||||||
if ($user === null) return;
|
if ($userStore === null) return;
|
||||||
project = api.projects.Project({ id });
|
project = getProjectStore({ id });
|
||||||
modal.show();
|
modal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +43,8 @@
|
|||||||
await project
|
await project
|
||||||
.update({ api: { ...existingCloudProject, sync: true } })
|
.update({ api: { ...existingCloudProject, sync: true } })
|
||||||
.then(() => toasts.success(`Project linked`));
|
.then(() => toasts.success(`Project linked`));
|
||||||
} else if (selectedRepositoryId === null && $user && project && $project) {
|
} else if (selectedRepositoryId === null && $userStore && project && $project) {
|
||||||
const cloudProject = await cloud.projects.create($user?.access_token, {
|
const cloudProject = await cloud.projects.create($userStore?.access_token, {
|
||||||
name: $project.title,
|
name: $project.title,
|
||||||
description: $project.description,
|
description: $project.description,
|
||||||
uid: $project.id
|
uid: $project.id
|
||||||
@ -112,7 +113,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{#each $cloudProjects
|
{#each $cloudProjects
|
||||||
// filter out projects that are already linked
|
// filter out projects that are already linked
|
||||||
.map( (project) => ({ ...project, disabled: $projects?.some((p) => p?.api?.repository_id === project.repository_id) }) )
|
.map( (project) => ({ ...project, disabled: $projectsStore?.some((p) => p?.api?.repository_id === project.repository_id) }) )
|
||||||
// sort by last updated
|
// sort by last updated
|
||||||
.sort((a, b) => compareDesc(new Date(a.updated_at), new Date(b.updated_at)))
|
.sort((a, b) => compareDesc(new Date(a.updated_at), new Date(b.updated_at)))
|
||||||
// sort by name
|
// sort by name
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toasts, api } from '$lib';
|
import { toasts } from '$lib';
|
||||||
|
import * as zip from '$lib/api/ipc/zip';
|
||||||
import { Button, Checkbox, Modal } from '$lib/components';
|
import { Button, Checkbox, Modal } from '$lib/components';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import type { User } from '$lib/api';
|
import type { User, getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
|
|
||||||
export let user: User | null;
|
export let user: User | null;
|
||||||
export let cloud: ReturnType<typeof api.CloudApi>;
|
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||||
|
|
||||||
export function show() {
|
export function show() {
|
||||||
modal.show();
|
modal.show();
|
||||||
@ -42,12 +43,12 @@
|
|||||||
const email = user?.email ?? emailInputValue;
|
const email = user?.email ?? emailInputValue;
|
||||||
toasts.promise(
|
toasts.promise(
|
||||||
Promise.all([
|
Promise.all([
|
||||||
sendLogs ? api.zip.logs().then((path) => readZipFile(path, 'logs.zip')) : undefined,
|
sendLogs ? zip.logs().then((path) => readZipFile(path, 'logs.zip')) : undefined,
|
||||||
sendProjectData
|
sendProjectData
|
||||||
? api.zip.gitbutlerData({ projectId }).then((path) => readZipFile(path, 'data.zip'))
|
? zip.gitbutlerData({ projectId }).then((path) => readZipFile(path, 'data.zip'))
|
||||||
: undefined,
|
: undefined,
|
||||||
sendProjectRepository
|
sendProjectRepository
|
||||||
? api.zip.projectData({ projectId }).then((path) => readZipFile(path, 'project.zip'))
|
? zip.projectData({ projectId }).then((path) => readZipFile(path, 'project.zip'))
|
||||||
: undefined
|
: undefined
|
||||||
]).then(async ([logs, data, repo]) =>
|
]).then(async ([logs, data, repo]) =>
|
||||||
cloud.feedback.create(user?.access_token, {
|
cloud.feedback.create(user?.access_token, {
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import { api } from '$lib';
|
import { getHeadStore } from '$lib/api/git/heads';
|
||||||
|
import { getStatusStore } from '$lib/api/git/statuses';
|
||||||
|
import { getSessionStore } from '$lib/api/ipc/sessions';
|
||||||
|
import { getDiffsStore } from '$lib/api/git/diffs';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import type { LayoutLoad } from './$types';
|
import type { LayoutLoad } from './$types';
|
||||||
import type { Loadable } from '@square/svelte-store';
|
import type { Loadable } from '@square/svelte-store';
|
||||||
import type { Project } from '$lib/api';
|
import { getProjectStore, type Project } from '$lib/api/ipc/projects';
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
export const load: LayoutLoad = async ({ params }) => {
|
export const load: LayoutLoad = async ({ params }) => {
|
||||||
const project = api.projects.Project({ id: params.projectId });
|
const project = getProjectStore({ id: params.projectId });
|
||||||
if ((await project.load()) === undefined) throw error(404, new Error('Project not found'));
|
if ((await project.load()) === undefined) throw error(404, new Error('Project not found'));
|
||||||
return {
|
return {
|
||||||
head: api.git.heads.Head({ projectId: params.projectId }),
|
head: getHeadStore({ projectId: params.projectId }),
|
||||||
statuses: api.git.statuses.Statuses({ projectId: params.projectId }),
|
statuses: getStatusStore({ projectId: params.projectId }),
|
||||||
sessions: api.sessions.Sessions({ projectId: params.projectId }),
|
sessions: getSessionStore({ projectId: params.projectId }),
|
||||||
diffs: api.git.diffs.Diffs({ projectId: params.projectId }),
|
diffs: getDiffsStore({ projectId: params.projectId }),
|
||||||
project: project as Loadable<Project> & Pick<typeof project, 'update' | 'delete'>
|
project: project as Loadable<Project> & Pick<typeof project, 'update' | 'delete'>
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -7,23 +7,24 @@
|
|||||||
import { Button, Statuses, Tooltip } from '$lib/components';
|
import { Button, Statuses, Tooltip } from '$lib/components';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import Chat from './Chat.svelte';
|
import Chat from './Chat.svelte';
|
||||||
|
import { Loaded } from 'svelte-loadable-store';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
$: project = derived(data.project, (project) => project);
|
const { project, statuses, sessions, head } = data;
|
||||||
$: statuses = derived(data.statuses, (statuses) => statuses);
|
|
||||||
$: sessions = derived(data.sessions, (sessions) => sessions);
|
|
||||||
$: head = derived(data.head, (head) => head);
|
|
||||||
|
|
||||||
$: recentSessions = derived(
|
$: recentSessions = derived(
|
||||||
sessions,
|
sessions,
|
||||||
(sessions) => {
|
(item) => {
|
||||||
const lastFourDaysOfSessions = sessions?.filter(
|
if (Loaded.isValue(item)) {
|
||||||
(session) => session.meta.startTimestampMs >= getTime(subDays(new Date(), 4))
|
const lastFourDaysOfSessions = item.value?.filter(
|
||||||
|
(result) => result.meta.startTimestampMs >= getTime(subDays(new Date(), 4))
|
||||||
);
|
);
|
||||||
if (lastFourDaysOfSessions?.length >= 4) return lastFourDaysOfSessions;
|
if (lastFourDaysOfSessions?.length >= 4) return lastFourDaysOfSessions;
|
||||||
return sessions
|
return item.value
|
||||||
?.slice(0, 4)
|
?.slice(0, 4)
|
||||||
.sort((a, b) => b.meta.startTimestampMs - a.meta.startTimestampMs);
|
.sort((a, b) => b.meta.startTimestampMs - a.meta.startTimestampMs);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
import { git } from '$lib/api';
|
import { getActivitiesStore } from '$lib/api/git/activities';
|
||||||
|
|
||||||
export const load: PageLoad = async ({ params }) => ({
|
export const load: PageLoad = async ({ params }) => ({
|
||||||
activity: git.activities.Activities({ projectId: params.projectId })
|
activity: getActivitiesStore({ projectId: params.projectId })
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button } from '$lib/components';
|
import { Button } from '$lib/components';
|
||||||
import { CloudApi, type Project } from '$lib/api';
|
import { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
import { stores } from '$lib';
|
import { userStore } from '$lib/stores/user';
|
||||||
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import { IconAISparkles } from '$lib/icons';
|
import { IconAISparkles } from '$lib/icons';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
const cloud = CloudApi();
|
const cloud = getCloudApiClient();
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
export let project: Project;
|
export let project: Project;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import { fillBuckets, type Bucket } from './histogram';
|
import { fillBuckets, type Bucket } from './histogram';
|
||||||
|
|
||||||
export let deltas: Delta[];
|
export let deltas: Delta[];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { format, startOfDay } from 'date-fns';
|
import { format, startOfDay } from 'date-fns';
|
||||||
import type { Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import { generateBuckets } from './histogram';
|
import { generateBuckets } from './histogram';
|
||||||
import { derived, Loaded } from 'svelte-loadable-store';
|
import { derived, Loaded } from 'svelte-loadable-store';
|
||||||
import FileActivity from './FileActivity.svelte';
|
import FileActivity from './FileActivity.svelte';
|
||||||
@ -8,13 +8,13 @@
|
|||||||
import { Link } from '$lib/components';
|
import { Link } from '$lib/components';
|
||||||
import { IconRewind, IconPlayerPlayFilled, IconLoading, IconSparkle } from '$lib/icons';
|
import { IconRewind, IconPlayerPlayFilled, IconLoading, IconSparkle } from '$lib/icons';
|
||||||
import { collapse } from '$lib/paths';
|
import { collapse } from '$lib/paths';
|
||||||
import type { Session } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
import { stores } from '$lib';
|
import { getDeltasStore } from '$lib/stores/deltas';
|
||||||
|
|
||||||
export let sessions: Session[];
|
export let sessions: Session[];
|
||||||
|
|
||||||
$: sessionDeltas = (sessions ?? []).map(({ id, projectId }) =>
|
$: sessionDeltas = (sessions ?? []).map(({ id, projectId }) =>
|
||||||
stores.deltas({ sessionId: id, projectId })
|
getDeltasStore({ sessionId: id, projectId })
|
||||||
);
|
);
|
||||||
|
|
||||||
$: deltasByDate = derived(sessionDeltas, (sessionDeltas) =>
|
$: deltasByDate = derived(sessionDeltas, (sessionDeltas) =>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toasts } from '$lib';
|
import { toasts } from '$lib';
|
||||||
import { Status, type Project, git, type CloudApi, type User } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
|
import type { User, getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
|
import { isUnstaged, type Status } from '$lib/api/git/statuses';
|
||||||
|
import { commit, stage } from '$lib/api/git';
|
||||||
import { Button, Overlay, Link } from '$lib/components';
|
import { Button, Overlay, Link } from '$lib/components';
|
||||||
import { IconGitBranch, IconSparkle } from '$lib/icons';
|
import { IconGitBranch, IconSparkle } from '$lib/icons';
|
||||||
import { Stats } from '$lib/components';
|
import { Stats } from '$lib/components';
|
||||||
@ -14,7 +17,7 @@
|
|||||||
export let statuses: Record<string, Status>;
|
export let statuses: Record<string, Status>;
|
||||||
export let diffs: Record<string, string>;
|
export let diffs: Record<string, string>;
|
||||||
export let user: User;
|
export let user: User;
|
||||||
export let cloud: ReturnType<typeof CloudApi>;
|
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||||
|
|
||||||
let summary = '';
|
let summary = '';
|
||||||
let description = '';
|
let description = '';
|
||||||
@ -23,10 +26,10 @@
|
|||||||
|
|
||||||
const stageAll = async () => {
|
const stageAll = async () => {
|
||||||
const paths = Object.entries(statuses)
|
const paths = Object.entries(statuses)
|
||||||
.filter((entry) => Status.isUnstaged(entry[1]))
|
.filter((entry) => isUnstaged(entry[1]))
|
||||||
.map(([path]) => path);
|
.map(([path]) => path);
|
||||||
if (paths.length === 0) return;
|
if (paths.length === 0) return;
|
||||||
await git.stage({
|
await stage({
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
paths
|
paths
|
||||||
});
|
});
|
||||||
@ -66,8 +69,7 @@
|
|||||||
|
|
||||||
isCommitting = true;
|
isCommitting = true;
|
||||||
await stageAll();
|
await stageAll();
|
||||||
git
|
commit({
|
||||||
.commit({
|
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
message: description.length > 0 ? `${summary}\n\n${description}` : summary,
|
message: description.length > 0 ? `${summary}\n\n${description}` : summary,
|
||||||
push: false
|
push: false
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
import { Button, Checkbox, DiffContext } from '$lib/components';
|
import { Button, Checkbox, DiffContext } from '$lib/components';
|
||||||
import { collapse } from '$lib/paths';
|
import { collapse } from '$lib/paths';
|
||||||
import { derived, writable } from '@square/svelte-store';
|
import { derived, writable } from '@square/svelte-store';
|
||||||
import { git, Status } from '$lib/api';
|
import { isStaged, isUnstaged } from '$lib/api/git/statuses';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
|
import { commit, stage, unstage } from '$lib/api/git';
|
||||||
import DiffViewer from './DiffViewer.svelte';
|
import DiffViewer from './DiffViewer.svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { error, success } from '$lib/toasts';
|
import { error, success } from '$lib/toasts';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { Modal } from '$lib/components';
|
import { Modal } from '$lib/components';
|
||||||
import { hotkeys, stores } from '$lib';
|
import { hotkeys } from '$lib';
|
||||||
import { IconChevronDown, IconChevronUp } from '$lib/icons';
|
import { IconChevronDown, IconChevronUp } from '$lib/icons';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { unsubscribe } from '$lib/utils';
|
import { unsubscribe } from '$lib/utils';
|
||||||
@ -17,19 +19,19 @@
|
|||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
let { statuses, diffs, cloud, project } = data;
|
let { statuses, diffs, cloud, project } = data;
|
||||||
|
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
let fullContext = false;
|
let fullContext = false;
|
||||||
let context = 3;
|
let context = 3;
|
||||||
|
|
||||||
const stagedFiles = derived(statuses, (statuses) =>
|
const stagedFiles = derived(statuses, (statuses) =>
|
||||||
Object.entries(statuses ?? {})
|
Object.entries(statuses ?? {})
|
||||||
.filter((status) => Status.isStaged(status[1]))
|
.filter((status) => isStaged(status[1]))
|
||||||
.map(([path]) => path)
|
.map(([path]) => path)
|
||||||
);
|
);
|
||||||
const unstagedFiles = derived(statuses, (statuses) =>
|
const unstagedFiles = derived(statuses, (statuses) =>
|
||||||
Object.entries(statuses ?? {})
|
Object.entries(statuses ?? {})
|
||||||
.filter((status) => Status.isUnstaged(status[1]))
|
.filter((status) => isUnstaged(status[1]))
|
||||||
.map(([path]) => path)
|
.map(([path]) => path)
|
||||||
);
|
);
|
||||||
const allFiles = derived(statuses, (statuses) =>
|
const allFiles = derived(statuses, (statuses) =>
|
||||||
@ -97,8 +99,7 @@
|
|||||||
const description = formData.get('description') as string;
|
const description = formData.get('description') as string;
|
||||||
|
|
||||||
isCommitting = true;
|
isCommitting = true;
|
||||||
git
|
commit({
|
||||||
.commit({
|
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
message: description.length > 0 ? `${summary}\n\n${description}` : summary,
|
message: description.length > 0 ? `${summary}\n\n${description}` : summary,
|
||||||
push: false
|
push: false
|
||||||
@ -123,9 +124,7 @@
|
|||||||
if ($user === null) return;
|
if ($user === null) return;
|
||||||
|
|
||||||
const partialDiff = Object.fromEntries(
|
const partialDiff = Object.fromEntries(
|
||||||
Object.entries($diffs ?? {}).filter(
|
Object.entries($diffs ?? {}).filter(([key]) => $statuses[key] && isStaged($statuses[key]))
|
||||||
([key]) => $statuses[key] && Status.isStaged($statuses[key])
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
const diff = Object.values(partialDiff).join('\n').slice(0, 5000);
|
const diff = Object.values(partialDiff).join('\n').slice(0, 5000);
|
||||||
|
|
||||||
@ -158,21 +157,17 @@
|
|||||||
const onGroupCheckboxClick = (e: Event) => {
|
const onGroupCheckboxClick = (e: Event) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
if (target.checked) {
|
if (target.checked) {
|
||||||
git
|
stage({
|
||||||
.stage({
|
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
paths: $unstagedFiles
|
paths: $unstagedFiles
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
error('Failed to stage files');
|
error('Failed to stage files');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
git
|
unstage({
|
||||||
.unstage({
|
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
paths: $stagedFiles
|
paths: $stagedFiles
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
error('Failed to unstage files');
|
error('Failed to unstage files');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -210,10 +205,10 @@
|
|||||||
// an git
|
// an git
|
||||||
statuses.subscribe((statuses) =>
|
statuses.subscribe((statuses) =>
|
||||||
Object.entries(statuses ?? {}).forEach(([file, status]) => {
|
Object.entries(statuses ?? {}).forEach(([file, status]) => {
|
||||||
const isStagedAdded = Status.isStaged(status) && status.staged === 'added';
|
const isStagedAdded = isStaged(status) && status.staged === 'added';
|
||||||
const isUnstagedDeleted = Status.isUnstaged(status) && status.unstaged === 'deleted';
|
const isUnstagedDeleted = isUnstaged(status) && status.unstaged === 'deleted';
|
||||||
if (isStagedAdded && isUnstagedDeleted)
|
if (isStagedAdded && isUnstagedDeleted)
|
||||||
git.stage({ projectId: $page.params.projectId, paths: [file] });
|
stage({ projectId: $page.params.projectId, paths: [file] });
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -288,20 +283,18 @@
|
|||||||
class="file-changed-item mx-1 mt-1 flex select-text items-center gap-2 rounded bg-card-default px-1 py-1"
|
class="file-changed-item mx-1 mt-1 flex select-text items-center gap-2 rounded bg-card-default px-1 py-1"
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={Status.isStaged(status)}
|
checked={isStaged(status)}
|
||||||
name="path"
|
name="path"
|
||||||
disabled={isCommitting || isGeneratingCommitMessage}
|
disabled={isCommitting || isGeneratingCommitMessage}
|
||||||
value={path}
|
value={path}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
Status.isStaged(status)
|
isStaged(status)
|
||||||
? git
|
? unstage({ projectId: $page.params.projectId, paths: [path] }).catch(
|
||||||
.unstage({ projectId: $page.params.projectId, paths: [path] })
|
() => {
|
||||||
.catch(() => {
|
|
||||||
error('Failed to unstage file');
|
error('Failed to unstage file');
|
||||||
})
|
}
|
||||||
: git
|
)
|
||||||
.stage({ projectId: $page.params.projectId, paths: [path] })
|
: stage({ projectId: $page.params.projectId, paths: [path] }).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
error('Failed to stage file');
|
error('Failed to stage file');
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { stores, api } from '$lib';
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
|
import * as deltas from '$lib/api/ipc/deltas';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { derived, Loaded } from 'svelte-loadable-store';
|
import { derived, Loaded } from 'svelte-loadable-store';
|
||||||
|
|
||||||
const sessions = stores.sessions({ projectId: $page.params.projectId });
|
const sessions = getSessionStore({ projectId: $page.params.projectId });
|
||||||
|
|
||||||
$: fileFilter = $page.url.searchParams.get('file');
|
$: fileFilter = $page.url.searchParams.get('file');
|
||||||
|
|
||||||
const dates = derived(sessions, async (sessions) => {
|
const dates = derived(sessions, async (sessions) => {
|
||||||
const sessionDeltas = await Promise.all(
|
const sessionDeltas = await Promise.all(
|
||||||
sessions.map((session) =>
|
sessions.map((session) =>
|
||||||
api.deltas.list({
|
deltas.list({
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
sessionId: session.id,
|
sessionId: session.id,
|
||||||
paths: fileFilter ? [fileFilter] : undefined
|
paths: fileFilter ? [fileFilter] : undefined
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { error, redirect } from '@sveltejs/kit';
|
import { error, redirect } from '@sveltejs/kit';
|
||||||
import { format, compareDesc } from 'date-fns';
|
import { format, compareDesc } from 'date-fns';
|
||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
import { stores } from '$lib';
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
import { promisify } from 'svelte-loadable-store';
|
import { promisify } from 'svelte-loadable-store';
|
||||||
|
|
||||||
export const load: PageLoad = async ({ url, params }) => {
|
export const load: PageLoad = async ({ url, params }) => {
|
||||||
const sessions = await promisify(stores.sessions({ projectId: params.projectId }));
|
const sessions = await promisify(getSessionStore({ projectId: params.projectId }));
|
||||||
const latestDate = sessions
|
const latestDate = sessions
|
||||||
.map((session) => session.meta.startTimestampMs)
|
.map((session) => session.meta.startTimestampMs)
|
||||||
.sort(compareDesc)
|
.sort(compareDesc)
|
||||||
|
@ -4,12 +4,16 @@
|
|||||||
import { derived, Loaded } from 'svelte-loadable-store';
|
import { derived, Loaded } from 'svelte-loadable-store';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { api, events, hotkeys, stores } from '$lib';
|
import { events, hotkeys } from '$lib';
|
||||||
import BookmarkModal from './BookmarkModal.svelte';
|
import BookmarkModal from './BookmarkModal.svelte';
|
||||||
import { unsubscribe } from '$lib/utils';
|
import { unsubscribe } from '$lib/utils';
|
||||||
import SessionsList from './SessionsList.svelte';
|
import SessionsList from './SessionsList.svelte';
|
||||||
import SessionNavigations from './SessionNavigations.svelte';
|
import SessionNavigations from './SessionNavigations.svelte';
|
||||||
import { IconLoading } from '$lib/icons';
|
import { IconLoading } from '$lib/icons';
|
||||||
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
|
import { getDeltasStore } from '$lib/stores/deltas';
|
||||||
|
import { getFilesStore } from '$lib/stores/files';
|
||||||
|
import * as bookmarks from '$lib/api/ipc/bookmarks';
|
||||||
|
|
||||||
export let data: LayoutData;
|
export let data: LayoutData;
|
||||||
const { currentFilepath, currentTimestamp } = data;
|
const { currentFilepath, currentTimestamp } = data;
|
||||||
@ -17,7 +21,7 @@
|
|||||||
const filter = derived(page, (page) => page.url.searchParams.get('file'));
|
const filter = derived(page, (page) => page.url.searchParams.get('file'));
|
||||||
const projectId = derived(page, (page) => page.params.projectId);
|
const projectId = derived(page, (page) => page.params.projectId);
|
||||||
|
|
||||||
$: sessions = stores.sessions({ projectId: $page.params.projectId });
|
$: sessions = getSessionStore({ projectId: $page.params.projectId });
|
||||||
$: dateSessions = derived([sessions, page], ([sessions, page]) =>
|
$: dateSessions = derived([sessions, page], ([sessions, page]) =>
|
||||||
sessions
|
sessions
|
||||||
.filter((session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date)
|
.filter((session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date)
|
||||||
@ -27,12 +31,12 @@
|
|||||||
$: richSessions = derived([dateSessions, projectId, filter], ([sessions, projectId, filter]) =>
|
$: richSessions = derived([dateSessions, projectId, filter], ([sessions, projectId, filter]) =>
|
||||||
sessions.map((session) => ({
|
sessions.map((session) => ({
|
||||||
...session,
|
...session,
|
||||||
deltas: derived(stores.deltas({ projectId: projectId, sessionId: session.id }), (deltas) =>
|
deltas: derived(getDeltasStore({ projectId: projectId, sessionId: session.id }), (deltas) =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
Object.entries(deltas).filter(([path]) => (filter ? path === filter : true))
|
Object.entries(deltas).filter(([path]) => (filter ? path === filter : true))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
files: derived(stores.files({ projectId, sessionId: session.id }), (files) =>
|
files: derived(getFilesStore({ projectId, sessionId: session.id }), (files) =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
Object.entries(files).filter(([path]) => (filter ? path === filter : true))
|
Object.entries(files).filter(([path]) => (filter ? path === filter : true))
|
||||||
)
|
)
|
||||||
@ -54,7 +58,7 @@
|
|||||||
events.on('openBookmarkModal', () => bookmarkModal?.show($currentTimestamp)),
|
events.on('openBookmarkModal', () => bookmarkModal?.show($currentTimestamp)),
|
||||||
hotkeys.on('Meta+Shift+D', () => bookmarkModal?.show($currentTimestamp)),
|
hotkeys.on('Meta+Shift+D', () => bookmarkModal?.show($currentTimestamp)),
|
||||||
hotkeys.on('D', async () => {
|
hotkeys.on('D', async () => {
|
||||||
const existing = await api.bookmarks.list({
|
const existing = await bookmarks.list({
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
range: {
|
range: {
|
||||||
start: $currentTimestamp,
|
start: $currentTimestamp,
|
||||||
@ -73,7 +77,7 @@
|
|||||||
...existing[0],
|
...existing[0],
|
||||||
deleted: !existing[0].deleted
|
deleted: !existing[0].deleted
|
||||||
};
|
};
|
||||||
api.bookmarks.upsert(newBookmark);
|
bookmarks.upsert(newBookmark);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { redirect, error } from '@sveltejs/kit';
|
import { redirect, error } from '@sveltejs/kit';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
import { stores } from '$lib';
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
import { promisify } from 'svelte-loadable-store';
|
import { promisify } from 'svelte-loadable-store';
|
||||||
|
|
||||||
export const load: PageLoad = async ({ params, url }) => {
|
export const load: PageLoad = async ({ params, url }) => {
|
||||||
const sessions = await promisify(stores.sessions({ projectId: params.projectId }));
|
const sessions = await promisify(getSessionStore({ projectId: params.projectId }));
|
||||||
const dateSessions = sessions.filter(
|
const dateSessions = sessions.filter(
|
||||||
(session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === params.date
|
(session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === params.date
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toasts, api } from '$lib';
|
import { toasts } from '$lib';
|
||||||
|
import * as bookmarks from '$lib/api/ipc/bookmarks';
|
||||||
import { Button, Modal } from '$lib/components';
|
import { Button, Modal } from '$lib/components';
|
||||||
import { IconBookmarkFilled } from '$lib/icons';
|
import { IconBookmarkFilled } from '$lib/icons';
|
||||||
|
|
||||||
@ -16,7 +17,7 @@
|
|||||||
export async function show(ts: number) {
|
export async function show(ts: number) {
|
||||||
reset();
|
reset();
|
||||||
timestampMs = ts;
|
timestampMs = ts;
|
||||||
const existing = await api.bookmarks.list({
|
const existing = await bookmarks.list({
|
||||||
projectId,
|
projectId,
|
||||||
range: {
|
range: {
|
||||||
start: ts,
|
start: ts,
|
||||||
@ -35,7 +36,7 @@
|
|||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(() => (isCreating = true))
|
.then(() => (isCreating = true))
|
||||||
.then(() =>
|
.then(() =>
|
||||||
api.bookmarks.upsert({
|
bookmarks.upsert({
|
||||||
projectId,
|
projectId,
|
||||||
note,
|
note,
|
||||||
timestampMs: timestampMs ?? Date.now(),
|
timestampMs: timestampMs ?? Date.now(),
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Operation, type Delta, type Session } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
|
import { isInsert, type Delta, isDelete } from '$lib/api/ipc/deltas';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { collapse } from '$lib/paths';
|
import { collapse } from '$lib/paths';
|
||||||
import { derived } from '@square/svelte-store';
|
import { derived } from '@square/svelte-store';
|
||||||
import { stores } from '$lib';
|
import { getBookmarksStore } from '$lib/stores/bookmarks';
|
||||||
import { IconBookmarkFilled } from '$lib/icons';
|
import { IconBookmarkFilled } from '$lib/icons';
|
||||||
import { line } from '$lib/diff';
|
import { line } from '$lib/diff';
|
||||||
import { Stats } from '$lib/components';
|
import { Stats } from '$lib/components';
|
||||||
@ -19,12 +20,12 @@
|
|||||||
const operations = deltas.flatMap((delta) => delta.operations);
|
const operations = deltas.flatMap((delta) => delta.operations);
|
||||||
|
|
||||||
operations.forEach((operation) => {
|
operations.forEach((operation) => {
|
||||||
if (Operation.isInsert(operation)) {
|
if (isInsert(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.insert[0]) +
|
text.slice(0, operation.insert[0]) +
|
||||||
operation.insert[1] +
|
operation.insert[1] +
|
||||||
text.slice(operation.insert[0]);
|
text.slice(operation.insert[0]);
|
||||||
} else if (Operation.isDelete(operation)) {
|
} else if (isDelete(operation)) {
|
||||||
text =
|
text =
|
||||||
text.slice(0, operation.delete[0]) +
|
text.slice(0, operation.delete[0]) +
|
||||||
text.slice(operation.delete[0] + operation.delete[1]);
|
text.slice(operation.delete[0] + operation.delete[1]);
|
||||||
@ -51,7 +52,7 @@
|
|||||||
})
|
})
|
||||||
.reduce((a, b) => [a[0] + b[0], a[1] + b[1]], [0, 0]);
|
.reduce((a, b) => [a[0] + b[0], a[1] + b[1]], [0, 0]);
|
||||||
|
|
||||||
$: bookmarks = derived(stores.bookmarks.list({ projectId: session.projectId }), (bookmarks) => {
|
$: bookmarksStore = derived(getBookmarksStore({ projectId: session.projectId }), (bookmarks) => {
|
||||||
if (bookmarks.isLoading) return [];
|
if (bookmarks.isLoading) return [];
|
||||||
if (Loaded.isError(bookmarks)) return [];
|
if (Loaded.isError(bookmarks)) return [];
|
||||||
const timestamps = Object.values(deltas ?? {}).flatMap((deltas) =>
|
const timestamps = Object.values(deltas ?? {}).flatMap((deltas) =>
|
||||||
@ -110,8 +111,8 @@
|
|||||||
class:bg-card-active={isCurrent}
|
class:bg-card-active={isCurrent}
|
||||||
class="session-card relative rounded border-[0.5px] border-gb-700 text-zinc-300 shadow-md transition-colors duration-200 ease-in-out hover:bg-card-active"
|
class="session-card relative rounded border-[0.5px] border-gb-700 text-zinc-300 shadow-md transition-colors duration-200 ease-in-out hover:bg-card-active"
|
||||||
>
|
>
|
||||||
{#await bookmarks.load() then}
|
{#await bookmarksStore.load() then}
|
||||||
{#if $bookmarks?.length > 0}
|
{#if $bookmarksStore?.length > 0}
|
||||||
<div class="absolute right-5 top-0 flex gap-2 overflow-hidden text-bookmark-selected">
|
<div class="absolute right-5 top-0 flex gap-2 overflow-hidden text-bookmark-selected">
|
||||||
<IconBookmarkFilled class="-mt-1 h-4 w-4" />
|
<IconBookmarkFilled class="-mt-1 h-4 w-4" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { hotkeys } from '$lib';
|
import { hotkeys } from '$lib';
|
||||||
|
|
||||||
import type { Delta, Session } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import { unsubscribe } from '$lib/utils';
|
import { unsubscribe } from '$lib/utils';
|
||||||
import type { Readable } from '@square/svelte-store';
|
import type { Readable } from '@square/svelte-store';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Delta, Session } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import type { Readable } from '@square/svelte-store';
|
import type { Readable } from '@square/svelte-store';
|
||||||
import { Loaded, type Loadable } from 'svelte-loadable-store';
|
import { Loaded, type Loadable } from 'svelte-loadable-store';
|
||||||
import { derived } from 'svelte-loadable-store';
|
import { derived } from 'svelte-loadable-store';
|
||||||
|
@ -5,12 +5,15 @@
|
|||||||
import { get, writable } from '@square/svelte-store';
|
import { get, writable } from '@square/svelte-store';
|
||||||
import { derived, Loaded } from 'svelte-loadable-store';
|
import { derived, Loaded } from 'svelte-loadable-store';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { stores } from '$lib';
|
|
||||||
import Playback from './Playback.svelte';
|
import Playback from './Playback.svelte';
|
||||||
import type { Frame as FrameType } from './frame';
|
import type { Frame as FrameType } from './frame';
|
||||||
import Frame from './Frame.svelte';
|
import Frame from './Frame.svelte';
|
||||||
import Info from './Info.svelte';
|
import Info from './Info.svelte';
|
||||||
import type { Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
|
import { getSessionStore } from '$lib/stores/sessions';
|
||||||
|
import { getDeltasStore } from '$lib/stores/deltas';
|
||||||
|
import { getFilesStore } from '$lib/stores/files';
|
||||||
|
import { getBookmarksStore } from '$lib/stores/bookmarks';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
const { currentFilepath, currentTimestamp, currentSessionId } = data;
|
const { currentFilepath, currentTimestamp, currentSessionId } = data;
|
||||||
@ -26,24 +29,23 @@
|
|||||||
const filter = derived(page, (page) => page.url.searchParams.get('file'));
|
const filter = derived(page, (page) => page.url.searchParams.get('file'));
|
||||||
const projectId = derived(page, (page) => page.params.projectId);
|
const projectId = derived(page, (page) => page.params.projectId);
|
||||||
|
|
||||||
$: bookmarks = stores.bookmarks.list({ projectId: $page.params.projectId });
|
$: bookmarks = getBookmarksStore({ projectId: $page.params.projectId });
|
||||||
$: sessions = stores.sessions({ projectId: $page.params.projectId });
|
$: sessions = getSessionStore({ projectId: $page.params.projectId });
|
||||||
$: dateSessions = derived([sessions, page], ([sessions, page]) =>
|
$: dateSessions = derived([sessions, page], async ([sessions, page]) =>
|
||||||
sessions?.filter(
|
sessions?.filter(
|
||||||
(session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date
|
(session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$: richSessions = derived([dateSessions, filter, projectId], ([sessions, filter, projectId]) =>
|
$: richSessions = derived([dateSessions, filter, projectId], ([sessions, filter, projectId]) =>
|
||||||
sessions.map((session) => ({
|
sessions.map((session) => ({
|
||||||
...session,
|
...session,
|
||||||
deltas: derived(stores.deltas({ projectId: projectId, sessionId: session.id }), (deltas) =>
|
deltas: derived(getDeltasStore({ projectId: projectId, sessionId: session.id }), (deltas) =>
|
||||||
Object.entries(deltas)
|
Object.entries(deltas)
|
||||||
.filter(([path]) => (filter ? path === filter : true))
|
.filter(([path]) => (filter ? path === filter : true))
|
||||||
.flatMap(([path, deltas]) => deltas.map((delta) => [path, delta] as [string, Delta]))
|
.flatMap(([path, deltas]) => deltas.map((delta) => [path, delta] as [string, Delta]))
|
||||||
.sort((a, b) => a[1].timestampMs - b[1].timestampMs)
|
.sort((a, b) => a[1].timestampMs - b[1].timestampMs)
|
||||||
),
|
),
|
||||||
files: derived(stores.files({ projectId, sessionId: session.id }), (files) =>
|
files: derived(getFilesStore({ projectId, sessionId: session.id }), (files) =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
Object.entries(files).filter(([path]) => (filter ? path === filter : true))
|
Object.entries(files).filter(([path]) => (filter ? path === filter : true))
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Delta, Session } from '$lib/api';
|
import type { Session } from '$lib/api/ipc/sessions';
|
||||||
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import type { Frame } from './frame';
|
import type { Frame } from './frame';
|
||||||
import { DeltasViewer } from '$lib/components';
|
import { DeltasViewer } from '$lib/components';
|
||||||
import type { Readable } from '@square/svelte-store';
|
import type { Readable } from '@square/svelte-store';
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { stores, api, events } from '$lib';
|
import { events } from '$lib';
|
||||||
import { collapse } from '$lib/paths';
|
import { collapse } from '$lib/paths';
|
||||||
import { IconBookmark, IconBookmarkFilled } from '$lib/icons';
|
import { IconBookmark, IconBookmarkFilled } from '$lib/icons';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { Loaded } from 'svelte-loadable-store';
|
import { Loaded } from 'svelte-loadable-store';
|
||||||
|
import * as bookmarks from '$lib/api/ipc/bookmarks';
|
||||||
|
import { getBookmark } from '$lib/stores/bookmarks';
|
||||||
|
|
||||||
export let timestampMs: number;
|
export let timestampMs: number;
|
||||||
export let filename: string;
|
export let filename: string;
|
||||||
|
|
||||||
$: bookmark = stores.bookmarks.get({ projectId: $page.params.projectId, timestampMs });
|
$: bookmark = getBookmark({ projectId: $page.params.projectId, timestampMs });
|
||||||
|
|
||||||
const toggleBookmark = () => {
|
const toggleBookmark = () => {
|
||||||
if ($bookmark.isLoading) return;
|
if ($bookmark.isLoading) return;
|
||||||
if (Loaded.isError($bookmark)) return;
|
if (Loaded.isError($bookmark)) return;
|
||||||
api.bookmarks.upsert(
|
bookmarks.upsert(
|
||||||
!$bookmark.value
|
!$bookmark.value
|
||||||
? {
|
? {
|
||||||
projectId: $page.params.projectId,
|
projectId: $page.params.projectId,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
import { IconPlayerPauseFilled, IconPlayerPlayFilled } from '$lib/icons';
|
import { IconPlayerPauseFilled, IconPlayerPlayFilled } from '$lib/icons';
|
||||||
import { DiffContext } from '$lib/components';
|
import { DiffContext } from '$lib/components';
|
||||||
import { unsubscribe } from '$lib/utils';
|
import { unsubscribe } from '$lib/utils';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Bookmark, Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
|
import type { Bookmark } from '$lib/api/ipc/bookmarks';
|
||||||
import { derived, Loaded, type Loadable } from 'svelte-loadable-store';
|
import { derived, Loaded, type Loadable } from 'svelte-loadable-store';
|
||||||
import type { Readable } from '@square/svelte-store';
|
import type { Readable } from '@square/svelte-store';
|
||||||
import { ModuleChapters, ModuleMarkers, type Marker } from './slider';
|
import { ModuleChapters, ModuleMarkers, type Marker } from './slider';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Delta } from '$lib/api';
|
import type { Delta } from '$lib/api/ipc/deltas';
|
||||||
|
|
||||||
export type Frame = {
|
export type Frame = {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { IconChevronLeft, IconChevronRight, IconLoading } from '$lib/icons';
|
import { IconChevronLeft, IconChevronRight, IconLoading } from '$lib/icons';
|
||||||
import { files, deltas, searchResults, type SearchResult } from '$lib/api';
|
|
||||||
import { asyncDerived } from '@square/svelte-store';
|
import { asyncDerived } from '@square/svelte-store';
|
||||||
import { format, formatDistanceToNow } from 'date-fns';
|
import { format, formatDistanceToNow } from 'date-fns';
|
||||||
import { DeltasViewer } from '$lib/components';
|
import { DeltasViewer } from '$lib/components';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { derived } from '@square/svelte-store';
|
import { derived } from '@square/svelte-store';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import * as search from '$lib/api/ipc/search';
|
||||||
|
import * as files from '$lib/api/ipc/files';
|
||||||
|
import * as deltas from '$lib/api/ipc/deltas';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
const { project } = data;
|
const { project } = data;
|
||||||
@ -19,7 +21,12 @@
|
|||||||
const openNextPage = () => goto(`?q=${$query}&offset=${$offset + limit}`);
|
const openNextPage = () => goto(`?q=${$query}&offset=${$offset + limit}`);
|
||||||
const openPrevPage = () => goto(`?q=${$query}&offset=${$offset - limit}`);
|
const openPrevPage = () => goto(`?q=${$query}&offset=${$offset - limit}`);
|
||||||
|
|
||||||
const fetchResultData = async ({ sessionId, projectId, filePath, index }: SearchResult) => {
|
const fetchResultData = async ({
|
||||||
|
sessionId,
|
||||||
|
projectId,
|
||||||
|
filePath,
|
||||||
|
index
|
||||||
|
}: search.SearchResult) => {
|
||||||
const [doc, dd] = await Promise.all([
|
const [doc, dd] = await Promise.all([
|
||||||
files.list({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? ''),
|
files.list({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? ''),
|
||||||
deltas
|
deltas
|
||||||
@ -42,7 +49,7 @@
|
|||||||
[query, project, offset],
|
[query, project, offset],
|
||||||
async ([query, project, offset]) => {
|
async ([query, project, offset]) => {
|
||||||
if (!query || !project) return { page: [], total: 0, haveNext: false, havePrev: false };
|
if (!query || !project) return { page: [], total: 0, haveNext: false, havePrev: false };
|
||||||
const results = await searchResults.list({ projectId: project.id, query, limit, offset });
|
const results = await search.list({ projectId: project.id, query, limit, offset });
|
||||||
return {
|
return {
|
||||||
page: await Promise.all(results.page.map(fetchResultData)),
|
page: await Promise.all(results.page.map(fetchResultData)),
|
||||||
haveNext: offset + limit < results.total,
|
haveNext: offset + limit < results.total,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import ResizeObserver from 'svelte-resize-observer';
|
import ResizeObserver from 'svelte-resize-observer';
|
||||||
import setupTerminal from './terminal';
|
import setupTerminal from './terminal';
|
||||||
import 'xterm/css/xterm.css';
|
import 'xterm/css/xterm.css';
|
||||||
import type { Project } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { debounce } from '$lib/utils';
|
import { debounce } from '$lib/utils';
|
||||||
import { Button, Statuses } from '$lib/components';
|
import { Button, Statuses } from '$lib/components';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Project } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
import { CanvasAddon } from 'xterm-addon-canvas';
|
import { CanvasAddon } from 'xterm-addon-canvas';
|
||||||
import { WebglAddon } from 'xterm-addon-webgl';
|
import { WebglAddon } from 'xterm-addon-webgl';
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
import Tray from './Tray.svelte';
|
import Tray from './Tray.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { Button } from '$lib/components';
|
import { Button } from '$lib/components';
|
||||||
import { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { Loaded } from 'svelte-loadable-store';
|
import { Loaded } from 'svelte-loadable-store';
|
||||||
import { getContext, setContext } from 'svelte';
|
import { getContext, setContext } from 'svelte';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
|
||||||
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
||||||
import BottomPanel from './BottomPanel.svelte';
|
import BottomPanel from './BottomPanel.svelte';
|
||||||
import UpstreamBranchLane from './UpstreamBranchLane.svelte';
|
import UpstreamBranchLane from './UpstreamBranchLane.svelte';
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { PageLoadEvent } from './$types';
|
import type { PageLoadEvent } from './$types';
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
import { api } from '$lib';
|
import { getProjectStore, type Project } from '$lib/api/ipc/projects';
|
||||||
import type { Project } from '$lib/api';
|
|
||||||
import type { Loadable } from '@square/svelte-store';
|
import type { Loadable } from '@square/svelte-store';
|
||||||
|
|
||||||
async function getRemoteBranches(params: { projectId: string }) {
|
async function getRemoteBranches(params: { projectId: string }) {
|
||||||
@ -11,7 +10,7 @@ async function getRemoteBranches(params: { projectId: string }) {
|
|||||||
export async function load({ parent, params }: PageLoadEvent) {
|
export async function load({ parent, params }: PageLoadEvent) {
|
||||||
const projectId = params.projectId;
|
const projectId = params.projectId;
|
||||||
const remoteBranchNames = await getRemoteBranches({ projectId });
|
const remoteBranchNames = await getRemoteBranches({ projectId });
|
||||||
const project = api.projects.Project({ id: params.projectId });
|
const project = getProjectStore({ id: params.projectId });
|
||||||
|
|
||||||
const { branchStoresCache } = await parent();
|
const { branchStoresCache } = await parent();
|
||||||
const vbranchStore = branchStoresCache.getVirtualBranchStore(projectId);
|
const vbranchStore = branchStoresCache.getVirtualBranchStore(projectId);
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
<script lang="ts" async="true">
|
<script lang="ts" async="true">
|
||||||
import Lane from './BranchLane.svelte';
|
import Lane from './BranchLane.svelte';
|
||||||
import NewBranchDropZone from './NewBranchDropZone.svelte';
|
import NewBranchDropZone from './NewBranchDropZone.svelte';
|
||||||
import type { Branch, BaseBranch } from '$lib/vbranches';
|
import type { BaseBranch, Branch } from '$lib/vbranches/types';
|
||||||
import { dzHighlight } from './dropZone';
|
import { dzHighlight } from './dropZone';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
import type { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
import type { CloudApi } from '$lib/api';
|
|
||||||
import { Link } from '$lib/components';
|
import { Link } from '$lib/components';
|
||||||
|
|
||||||
export let projectId: string;
|
export let projectId: string;
|
||||||
export let projectPath: string;
|
export let projectPath: string;
|
||||||
export let branches: Branch[];
|
export let branches: Branch[];
|
||||||
export let base: BaseBranch | undefined;
|
export let base: BaseBranch | undefined;
|
||||||
export let cloudEnabled: boolean;
|
export let cloudEnabled: boolean;
|
||||||
export let cloud: ReturnType<typeof CloudApi>;
|
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||||
|
|
||||||
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { IconTriangleUp, IconTriangleDown } from '$lib/icons';
|
import { IconTriangleUp, IconTriangleDown } from '$lib/icons';
|
||||||
import type { BaseBranch } from '$lib/vbranches';
|
import type { BaseBranch } from '$lib/vbranches/types';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import type { SettingsStore } from '$lib/userSettings';
|
import type { SettingsStore } from '$lib/userSettings';
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toasts, stores } from '$lib';
|
import { toasts } from '$lib';
|
||||||
import type { Commit, File, BaseBranch } from '$lib/vbranches';
|
import { userStore } from '$lib/stores/user';
|
||||||
|
import type { BaseBranch, Commit, File } from '$lib/vbranches/types';
|
||||||
import { getContext, onMount } from 'svelte';
|
import { getContext, onMount } from 'svelte';
|
||||||
import { IconAISparkles } from '$lib/icons';
|
import { IconAISparkles } from '$lib/icons';
|
||||||
import { Button, Link, Tooltip } from '$lib/components';
|
import { Button, Link, Tooltip } from '$lib/components';
|
||||||
@ -10,15 +11,14 @@
|
|||||||
import PopupMenu from '../../../lib/components/PopupMenu/PopupMenu.svelte';
|
import PopupMenu from '../../../lib/components/PopupMenu/PopupMenu.svelte';
|
||||||
import PopupMenuItem from '../../../lib/components/PopupMenu/PopupMenuItem.svelte';
|
import PopupMenuItem from '../../../lib/components/PopupMenu/PopupMenuItem.svelte';
|
||||||
import { dzHighlight } from './dropZone';
|
import { dzHighlight } from './dropZone';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
|
||||||
import FileCardNext from './FileCardNext.svelte';
|
import FileCardNext from './FileCardNext.svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { crossfade, fade } from 'svelte/transition';
|
import { crossfade, fade } from 'svelte/transition';
|
||||||
import { flip } from 'svelte/animate';
|
import { flip } from 'svelte/animate';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import type { CloudApi } from '$lib/api';
|
import type { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
||||||
import IconNewBadge from '$lib/icons/IconNewBadge.svelte';
|
import IconNewBadge from '$lib/icons/IconNewBadge.svelte';
|
||||||
|
|
||||||
@ -50,11 +50,11 @@
|
|||||||
export let conflicted: boolean;
|
export let conflicted: boolean;
|
||||||
export let base: BaseBranch | undefined;
|
export let base: BaseBranch | undefined;
|
||||||
export let cloudEnabled: boolean;
|
export let cloudEnabled: boolean;
|
||||||
export let cloud: ReturnType<typeof CloudApi>;
|
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||||
export let upstream: string | undefined;
|
export let upstream: string | undefined;
|
||||||
|
|
||||||
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
let commitMessage: string;
|
let commitMessage: string;
|
||||||
|
|
||||||
$: remoteCommits = commits.filter((c) => c.isRemote);
|
$: remoteCommits = commits.filter((c) => c.isRemote);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import type { Commit } from '$lib/vbranches';
|
import type { Commit } from '$lib/vbranches/types';
|
||||||
|
|
||||||
export let commit: Commit;
|
export let commit: Commit;
|
||||||
export let url: string | undefined = undefined;
|
export let url: string | undefined = undefined;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import type { BranchController, Hunk } from '$lib/vbranches';
|
import type { Hunk } from '$lib/vbranches/types';
|
||||||
import HunkDiffViewer from './HunkDiffViewer.svelte';
|
import HunkDiffViewer from './HunkDiffViewer.svelte';
|
||||||
import { summarizeHunk } from '$lib/summaries';
|
import { summarizeHunk } from '$lib/summaries';
|
||||||
import { IconTriangleUp, IconTriangleDown } from '$lib/icons';
|
import { IconTriangleUp, IconTriangleDown } from '$lib/icons';
|
||||||
@ -11,7 +11,7 @@
|
|||||||
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { dzTrigger } from './dropZone';
|
import { dzTrigger } from './dropZone';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
|
|
||||||
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
||||||
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { ContentSection, HunkSection, parseFileSections } from './fileSections';
|
import { ContentSection, HunkSection, parseFileSections } from './fileSections';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { open } from '@tauri-apps/api/shell';
|
import { open } from '@tauri-apps/api/shell';
|
||||||
import type { File } from '$lib/vbranches';
|
import type { File } from '$lib/vbranches/types';
|
||||||
import RenderedLine from './RenderedLine.svelte';
|
import RenderedLine from './RenderedLine.svelte';
|
||||||
import {
|
import {
|
||||||
IconTriangleUp,
|
IconTriangleUp,
|
||||||
@ -11,8 +11,7 @@
|
|||||||
IconExpandUp,
|
IconExpandUp,
|
||||||
IconExpandDown
|
IconExpandDown
|
||||||
} from '$lib/icons';
|
} from '$lib/icons';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { dzTrigger } from './dropZone';
|
import { dzTrigger } from './dropZone';
|
||||||
import IconExpandUpDownSlim from '$lib/icons/IconExpandUpDownSlim.svelte';
|
import IconExpandUpDownSlim from '$lib/icons/IconExpandUpDownSlim.svelte';
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button } from '$lib/components';
|
import { Button } from '$lib/components';
|
||||||
import { dzHighlight } from './dropZone';
|
import { dzHighlight } from './dropZone';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
|
||||||
|
|
||||||
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
const branchController = getContext<BranchController>(BRANCH_CONTROLLER_KEY);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, Checkbox, Link, Modal } from '$lib/components';
|
import { Button, Checkbox, Link, Modal } from '$lib/components';
|
||||||
import type { Branch, BranchData } from '$lib/vbranches';
|
import type { Branch, BranchData } from '$lib/vbranches/types';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { IconGitBranch, IconRemote } from '$lib/icons';
|
import { IconGitBranch, IconRemote } from '$lib/icons';
|
||||||
import { IconTriangleDown, IconTriangleUp } from '$lib/icons';
|
import { IconTriangleDown, IconTriangleUp } from '$lib/icons';
|
||||||
@ -8,9 +8,8 @@
|
|||||||
import PopupMenu from '$lib/components/PopupMenu/PopupMenu.svelte';
|
import PopupMenu from '$lib/components/PopupMenu/PopupMenu.svelte';
|
||||||
import PopupMenuItem from '$lib/components/PopupMenu/PopupMenuItem.svelte';
|
import PopupMenuItem from '$lib/components/PopupMenu/PopupMenuItem.svelte';
|
||||||
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
|
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
|
||||||
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
||||||
import IconMeatballMenu from '$lib/icons/IconMeatballMenu.svelte';
|
import IconMeatballMenu from '$lib/icons/IconMeatballMenu.svelte';
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { IconBranch, IconRefresh, IconGithub } from '$lib/icons';
|
import { IconBranch, IconRefresh, IconGithub } from '$lib/icons';
|
||||||
import { Button, Modal, Tooltip } from '$lib/components';
|
import { Button, Modal, Tooltip } from '$lib/components';
|
||||||
import type { BaseBranch } from '$lib/vbranches';
|
import type { BaseBranch } from '$lib/vbranches/types';
|
||||||
import CommitCard from './CommitCard.svelte';
|
import CommitCard from './CommitCard.svelte';
|
||||||
import type { BranchController } from '$lib/vbranches';
|
import { BRANCH_CONTROLLER_KEY, BranchController } from '$lib/vbranches/branchController';
|
||||||
import { BRANCH_CONTROLLER_KEY } from '$lib/vbranches/branchController';
|
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
import Scrollbar from '$lib/components/Scrollbar.svelte';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { File } from '$lib/vbranches';
|
import type { File } from '$lib/vbranches/types';
|
||||||
|
|
||||||
const TRUE_KEY = '1';
|
const TRUE_KEY = '1';
|
||||||
const FALSE_KEY = '0';
|
const FALSE_KEY = '0';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { expect, test } from 'vitest';
|
import { expect, test } from 'vitest';
|
||||||
import type { File, Hunk } from '$lib/vbranches';
|
import type { File, Hunk } from '$lib/vbranches/types';
|
||||||
import { parseHunkSection, parseFileSections, SectionType } from './fileSections';
|
import { parseHunkSection, parseFileSections, SectionType } from './fileSections';
|
||||||
import type { ContentSection, HunkSection } from './fileSections';
|
import type { ContentSection, HunkSection } from './fileSections';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { File, Hunk } from '$lib/vbranches';
|
import type { File, Hunk } from '$lib/vbranches/types';
|
||||||
import { plainToInstance } from 'class-transformer';
|
import { plainToInstance } from 'class-transformer';
|
||||||
|
|
||||||
export type Line = {
|
export type Line = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Branch, File, type Hunk } from '$lib/vbranches';
|
import { Branch, File, type Hunk } from '$lib/vbranches/types';
|
||||||
import { plainToInstance } from 'class-transformer';
|
import { plainToInstance } from 'class-transformer';
|
||||||
|
|
||||||
let branchCounter = 0;
|
let branchCounter = 0;
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, Modal } from '$lib/components';
|
import { Button, Modal } from '$lib/components';
|
||||||
import { toasts, api, stores } from '$lib';
|
import { toasts } from '$lib';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import CloudForm from './CloudForm.svelte';
|
import CloudForm from './CloudForm.svelte';
|
||||||
import DetailsForm from './DetailsForm.svelte';
|
import DetailsForm from './DetailsForm.svelte';
|
||||||
import type { Project } from '$lib/api';
|
import * as projects from '$lib/api/ipc/projects';
|
||||||
|
import { projectsStore } from '$lib/api/ipc/projects';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
const { projects, project, cloud } = data;
|
const { project, cloud } = data;
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
let deleteConfirmationModal: Modal;
|
let deleteConfirmationModal: Modal;
|
||||||
let isDeleting = false;
|
let isDeleting = false;
|
||||||
@ -17,19 +19,19 @@
|
|||||||
const onDeleteClicked = () =>
|
const onDeleteClicked = () =>
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(() => (isDeleting = true))
|
.then(() => (isDeleting = true))
|
||||||
.then(() => api.projects.del({ id: $project?.id }))
|
.then(() => projects.del({ id: $project?.id }))
|
||||||
.then(() => deleteConfirmationModal.close())
|
.then(() => deleteConfirmationModal.close())
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
toasts.error('Failed to delete project');
|
toasts.error('Failed to delete project');
|
||||||
})
|
})
|
||||||
.then(() => goto('/'))
|
.then(() => goto('/'))
|
||||||
.then(() => projects.update((projects) => projects.filter((p) => p.id !== $project?.id)))
|
.then(() => projectsStore.update((projects) => projects.filter((p) => p.id !== $project?.id)))
|
||||||
.then(() => toasts.success('Project deleted'))
|
.then(() => toasts.success('Project deleted'))
|
||||||
.finally(() => (isDeleting = false));
|
.finally(() => (isDeleting = false));
|
||||||
|
|
||||||
const onCloudUpdated = (e: { detail: Project }) => project.update({ ...e.detail });
|
const onCloudUpdated = (e: { detail: projects.Project }) => project.update({ ...e.detail });
|
||||||
const onDetailsUpdated = async (e: { detail: Project }) => {
|
const onDetailsUpdated = async (e: { detail: projects.Project }) => {
|
||||||
const api =
|
const api =
|
||||||
$user && e.detail.api
|
$user && e.detail.api
|
||||||
? await cloud.projects.update($user?.access_token, e.detail.api.repository_id, {
|
? await cloud.projects.update($user?.access_token, e.detail.api.repository_id, {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { PageLoadEvent } from './$types';
|
import type { PageLoadEvent } from './$types';
|
||||||
import { invoke } from '$lib/ipc';
|
import { invoke } from '$lib/ipc';
|
||||||
import { api } from '$lib';
|
import { getProjectStore, type Project } from '$lib/api/ipc/projects';
|
||||||
import type { Project } from '$lib/api';
|
|
||||||
import type { Loadable } from '@square/svelte-store';
|
import type { Loadable } from '@square/svelte-store';
|
||||||
|
|
||||||
async function getRemoteBranches(params: { projectId: string }) {
|
async function getRemoteBranches(params: { projectId: string }) {
|
||||||
@ -11,7 +10,7 @@ async function getRemoteBranches(params: { projectId: string }) {
|
|||||||
export async function load({ parent, params }: PageLoadEvent) {
|
export async function load({ parent, params }: PageLoadEvent) {
|
||||||
const projectId = params.projectId;
|
const projectId = params.projectId;
|
||||||
const remoteBranchNames = await getRemoteBranches({ projectId });
|
const remoteBranchNames = await getRemoteBranches({ projectId });
|
||||||
const project = api.projects.Project({ id: params.projectId });
|
const project = getProjectStore({ id: params.projectId });
|
||||||
|
|
||||||
const { branchStoresCache } = await parent();
|
const { branchStoresCache } = await parent();
|
||||||
const vbranchStore = branchStoresCache.getVirtualBranchStore(projectId);
|
const vbranchStore = branchStoresCache.getVirtualBranchStore(projectId);
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { stores, toasts } from '$lib';
|
import { toasts } from '$lib';
|
||||||
import { CloudApi, type Project } from '$lib/api';
|
import { getCloudApiClient } from '$lib/api/cloud/api';
|
||||||
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
import { Login, Checkbox } from '$lib/components';
|
import { Login, Checkbox } from '$lib/components';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
|
|
||||||
export let project: Project;
|
export let project: Project;
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
const cloud = CloudApi();
|
const cloud = getCloudApiClient();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
updated: Project;
|
updated: Project;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Project } from '$lib/api';
|
import type { Project } from '$lib/api/ipc/projects';
|
||||||
import { debounce } from '$lib/utils';
|
import { debounce } from '$lib/utils';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, Modal, Login, Link } from '$lib/components';
|
import { Button, Modal, Login, Link } from '$lib/components';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { stores, toasts } from '$lib';
|
import { toasts } from '$lib';
|
||||||
import { deleteAllData } from '$lib/api';
|
import { deleteAllData } from '$lib/api/ipc';
|
||||||
|
import { userStore } from '$lib/stores/user';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ThemeSelector from '../ThemeSelector.svelte';
|
import ThemeSelector from '../ThemeSelector.svelte';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
@ -13,7 +14,7 @@
|
|||||||
const { cloud } = data;
|
const { cloud } = data;
|
||||||
|
|
||||||
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
||||||
const user = stores.user;
|
const user = userStore;
|
||||||
|
|
||||||
$: saving = false;
|
$: saving = false;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ const config = {
|
|||||||
600: '#C19206',
|
600: '#C19206',
|
||||||
700: '#987105',
|
700: '#987105',
|
||||||
800: '#6F5004',
|
800: '#6F5004',
|
||||||
900: '#713F12',
|
900: '#713F12'
|
||||||
},
|
},
|
||||||
red: {
|
red: {
|
||||||
400: '#F87171',
|
400: '#F87171',
|
||||||
@ -142,7 +142,7 @@ const config = {
|
|||||||
600: '#5852A0',
|
600: '#5852A0',
|
||||||
700: '#443D7A',
|
700: '#443D7A',
|
||||||
800: '#302854',
|
800: '#302854',
|
||||||
900: '#1C142E',
|
900: '#1C142E'
|
||||||
},
|
},
|
||||||
orange: {
|
orange: {
|
||||||
50: '#FEF6E4',
|
50: '#FEF6E4',
|
||||||
@ -154,7 +154,7 @@ const config = {
|
|||||||
600: '#FA8E4B',
|
600: '#FA8E4B',
|
||||||
700: '#CD6E02',
|
700: '#CD6E02',
|
||||||
800: '#A55602',
|
800: '#A55602',
|
||||||
900: '#7D3F02',
|
900: '#7D3F02'
|
||||||
},
|
},
|
||||||
zinc: {
|
zinc: {
|
||||||
50: '#fafafa',
|
50: '#fafafa',
|
||||||
|
Loading…
Reference in New Issue
Block a user