mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2025-01-01 22:12:04 +03:00
Refactor project page & timeline session components
- Update project page layout to a `div` with a bottom border - Adjust display width of session timeline based on session duration - Add timeline session components to project page - Add logic to determine if project exists - Update authentication API calls and parse JSON responses - Add new methods for creating login token and getting user object [src/routes/+layout.svelte] - Change div container from `flex` to `grid` - Increase sidebar height from `10` to `12` - Change sidebar width from `1/4` to `flex` - Change main content width from `flex-grow` to `col-span-5` - Add `dark` class to sidebar and main content [src/lib/components/timeline/index.ts] - Change the exported component from `TimelineDay` to `TimelineDaySession` [src/routes/+layout.ts] - Add an `add` method to the `projects` object - Add `user` object to the `load` function - Update the `projects` object to be initialized from an external source if not building [src/routes/projects/[projectId]/+layout.svelte] - Change the layout of the project page from a `div` to a `div` with a bottom border [src/lib/components/timeline/TimelineDay.svelte] - Delete the TimelineDay component - Remove the code related to the component, including the `sessionDisplayWidth` function [src/routes/projects/[projectId]/sessions/[sessionId]/+page.svelte] - Replace the `border-y` class with `border-b` in the `+page.svelte` file [src/routes/projects/[projectId]/+page.svelte] - Add logic to adjust the display width of the session timeline based on session duration - Add logic to determine if the project exists - Add timeline session components to the project page [src/lib/users.ts] - Move imports to the top of the file - Add a check to see if a user is logged in - Set the store to the user if they are logged in - Log the user when they are set - Write the user to the file when they are set [src/lib/authentication.ts] - Change the URL for the API calls - Parse JSON responses from the API - Add a new method for creating a login token - Add a new method for getting a user object - Fix typo in error message - Update the content-type header for API calls [src/routes/projects/[projectId]/sessions/[sessionId]/+page.ts] - Change the logic for finding the current session - Make the code more precise in finding the current session - Change the logic for finding the previous session
This commit is contained in:
parent
c5c46e8a25
commit
c19e374476
@ -1,59 +1,68 @@
|
||||
import { dev } from '$app/environment'
|
||||
import { dev } from "$app/environment";
|
||||
|
||||
const apiUrl = dev ? new URL('https://test.app.gitbutler.com/api/') : new URL('https://app.gitbutler.com/api/');
|
||||
const apiUrl = dev
|
||||
? new URL("https://test.app.gitbutler.com/api/")
|
||||
: new URL("https://app.gitbutler.com/api/");
|
||||
|
||||
const getUrl = (path: string) => new URL(path, apiUrl).toString();
|
||||
|
||||
export type LoginToken = {
|
||||
token: string,
|
||||
expires: string,
|
||||
url: string
|
||||
}
|
||||
token: string;
|
||||
expires: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type User = {
|
||||
id: number,
|
||||
name: string,
|
||||
email: string,
|
||||
picture: string,
|
||||
locale: string,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
access_token: string,
|
||||
}
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
picture: string;
|
||||
locale: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
access_token: string;
|
||||
};
|
||||
|
||||
const parseJSON = async (response: Response) => {
|
||||
if (response.status === 204 || response.status === 205) {
|
||||
return null;
|
||||
}
|
||||
if (response.status >= 400) {
|
||||
throw new Error(`HTTP Error ${response.statusText}: ${await response.text()}`);
|
||||
throw new Error(
|
||||
`HTTP Error ${response.statusText}: ${await response.text()}`
|
||||
);
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
};
|
||||
|
||||
export default ({ fetch }: { fetch: typeof window.fetch } = { fetch: window.fetch }) => ({
|
||||
export default (
|
||||
{ fetch }: { fetch: typeof window.fetch } = { fetch: window.fetch }
|
||||
) => ({
|
||||
login: {
|
||||
token: {
|
||||
create: (params: {} = {}): Promise<LoginToken> => fetch(getUrl('login/token.json'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
}).then(parseJSON).then(token => {
|
||||
const url = new URL(token.url);
|
||||
url.host = apiUrl.host;
|
||||
return {
|
||||
...token,
|
||||
url: url.toString(),
|
||||
}
|
||||
|
||||
}),
|
||||
create: (params: {} = {}): Promise<LoginToken> =>
|
||||
fetch(getUrl("login/token.json"), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
})
|
||||
.then(parseJSON)
|
||||
.then((token) => {
|
||||
const url = new URL(token.url);
|
||||
url.host = apiUrl.host;
|
||||
return {
|
||||
...token,
|
||||
url: url.toString(),
|
||||
};
|
||||
}),
|
||||
},
|
||||
user: {
|
||||
get: (token: string): Promise<User> => fetch(getUrl(`login/user/${token}.json`), {
|
||||
method: 'GET',
|
||||
}).then(parseJSON),
|
||||
}
|
||||
}
|
||||
})
|
||||
get: (token: string): Promise<User> =>
|
||||
fetch(getUrl(`login/user/${token}.json`), {
|
||||
method: "GET",
|
||||
}).then(parseJSON),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,28 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { Session } from "$lib/sessions";
|
||||
import TimelineDaySession from "./TimelineDaySession.svelte";
|
||||
|
||||
export let sessions: Session[];
|
||||
export let projectId: string;
|
||||
|
||||
const sessionDisplayWidth = (session: Session) => {
|
||||
let sessionDurationHours =
|
||||
(session.meta.lastTs - session.meta.startTs) / 1000 / 60 / 60;
|
||||
if (sessionDurationHours <= 1) {
|
||||
return "w-40";
|
||||
} else {
|
||||
return "w-60";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="mt-12">
|
||||
<div class="-mb-5 border border-slate-400 h-1.5 bg-slate-200 z-0" />
|
||||
<div class="flex flex-row space-x-2 z-10">
|
||||
{#each sessions as session}
|
||||
<div class={sessionDisplayWidth(session)}>
|
||||
<TimelineDaySession {projectId} {session} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
@ -1 +1 @@
|
||||
export { default as TimelineDay } from "./TimelineDay.svelte";
|
||||
export { default as TimelineDaySession } from "./TimelineDaySession.svelte";
|
||||
|
@ -1,20 +1,28 @@
|
||||
import { BaseDirectory, exists, readTextFile, writeTextFile } from '@tauri-apps/api/fs';
|
||||
import type { User } from '$lib/authentication';
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
BaseDirectory,
|
||||
exists,
|
||||
readTextFile,
|
||||
writeTextFile,
|
||||
} from "@tauri-apps/api/fs";
|
||||
import type { User } from "$lib/authentication";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
const userFile = 'user.json';
|
||||
const userFile = "user.json";
|
||||
|
||||
const isLoggedIn = () => exists(userFile, {
|
||||
dir: BaseDirectory.AppLocalData
|
||||
})
|
||||
const isLoggedIn = () =>
|
||||
exists(userFile, {
|
||||
dir: BaseDirectory.AppLocalData,
|
||||
});
|
||||
|
||||
export default async () => {
|
||||
const store = writable<User | undefined>(undefined);
|
||||
|
||||
if (await isLoggedIn()) {
|
||||
const user = JSON.parse(await readTextFile(userFile, {
|
||||
dir: BaseDirectory.AppLocalData
|
||||
})) as User;
|
||||
const user = JSON.parse(
|
||||
await readTextFile(userFile, {
|
||||
dir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
) as User;
|
||||
store.set(user);
|
||||
}
|
||||
|
||||
@ -22,11 +30,10 @@ export default async () => {
|
||||
if (user) {
|
||||
console.log({ user });
|
||||
await writeTextFile(userFile, JSON.stringify(user), {
|
||||
dir: BaseDirectory.AppLocalData
|
||||
dir: BaseDirectory.AppLocalData,
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -67,19 +67,19 @@
|
||||
<a href="/users/" class="mr-4 cursor-default font-bold">{$user ? $user.name : 'User'}</a>
|
||||
</header>
|
||||
|
||||
<div class="flex h-screen flex-grow flex-row text-zinc-400 overflow-hidden">
|
||||
<div class="grid grid-cols-6 h-screen flex-grow flex-row text-zinc-400 overflow-hidden">
|
||||
<div
|
||||
id="sidebar"
|
||||
class="
|
||||
overflow-auto
|
||||
flex
|
||||
w-1/4 flex-col bg-zinc-50
|
||||
flex-col bg-zinc-50
|
||||
border-r
|
||||
border-zinc-700
|
||||
dark:bg-zinc-900"
|
||||
>
|
||||
<div
|
||||
class=" flex h-10 items-center border-b border-zinc-700 hover:bg-zinc-800"
|
||||
class=" flex h-12 items-center border-b border-zinc-700 hover:bg-zinc-800"
|
||||
>
|
||||
<div class="flex-grow">
|
||||
<DropDown projects={$projects} />
|
||||
@ -108,7 +108,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex-grow h-full border-ldark:border-zinc-700 dark:bg-zinc-800 overflow-hidden"
|
||||
class="h-full col-span-5 border-ldark:border-zinc-700 dark:bg-zinc-800 overflow-hidden"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -8,12 +8,16 @@ export const prerender = true;
|
||||
export const csr = true;
|
||||
|
||||
export const load: LayoutLoad = async () => {
|
||||
const projects = building ? ({
|
||||
...readable<Project[]>([]),
|
||||
add: () => {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
}) : await (await import("$lib/projects")).default();
|
||||
const user = building ? writable<undefined>(undefined) : await (await import("$lib/users")).default();
|
||||
return { projects, user }
|
||||
const projects = building
|
||||
? {
|
||||
...readable<Project[]>([]),
|
||||
add: () => {
|
||||
throw new Error("not implemented");
|
||||
},
|
||||
}
|
||||
: await (await import("$lib/projects")).default();
|
||||
const user = building
|
||||
? writable<undefined>(undefined)
|
||||
: await (await import("$lib/users")).default();
|
||||
return { projects, user };
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
$: lastSessionId = $sessions[$sessions.length - 1]?.id;
|
||||
</script>
|
||||
|
||||
<div class="p-3 flex flex-row space-x-3 text-zinc-500 text-lg select-none">
|
||||
<div class="h-12 p-3 flex flex-row space-x-3 text-zinc-500 text-lg select-none border-b border-zinc-700">
|
||||
<div>Week</div>
|
||||
<a href="/projects/{$project?.id}" class="hover:text-zinc-300">Day</a>
|
||||
{#if lastSessionId}
|
||||
|
@ -1,14 +1,35 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from "./$types";
|
||||
import { TimelineDay } from "$lib/components/timeline";
|
||||
import type { Session } from "$lib/sessions";
|
||||
import { TimelineDaySession } from "$lib/components/timeline";
|
||||
|
||||
export let data: PageData;
|
||||
const { project, sessions } = data;
|
||||
|
||||
const sessionDisplayWidth = (session: Session) => {
|
||||
let sessionDurationHours =
|
||||
(session.meta.lastTs - session.meta.startTs) / 1000 / 60 / 60;
|
||||
if (sessionDurationHours <= 1) {
|
||||
return "w-40";
|
||||
} else {
|
||||
return "w-60";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="w-full h-full mx-2 flex">
|
||||
{#if $project}
|
||||
<TimelineDay projectId={$project?.id} sessions={$sessions} />
|
||||
<div class="flex-grow items-center justify-center mt-4">
|
||||
<div
|
||||
class="justify-center overflow-auto flex flex-row space-x-2 pt-2"
|
||||
>
|
||||
{#each $sessions as session}
|
||||
<div class={sessionDisplayWidth(session)}>
|
||||
<TimelineDaySession projectId={$project.id} {session} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<p>Project not found</p>
|
||||
{/if}
|
||||
|
@ -56,7 +56,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full h-full overflow-hidden space-y-2">
|
||||
<div class="flex justify-center border-y border-zinc-700 p-2">
|
||||
<div class="flex justify-center border-b border-zinc-700 p-2">
|
||||
<SessionNav
|
||||
project={$project}
|
||||
session={$session}
|
||||
|
@ -20,10 +20,11 @@ export const load: PageLoad = async ({ parent, params }) => {
|
||||
});
|
||||
return {
|
||||
session: derived(sessions, (sessions) => {
|
||||
const result = sessions.find((session) => session.id === params.sessionId)
|
||||
const result = sessions.find(
|
||||
(session) => session.id === params.sessionId
|
||||
);
|
||||
return result ? result : sessions[0];
|
||||
}
|
||||
),
|
||||
}),
|
||||
previousSesssion: derived(sessions, (sessions) => {
|
||||
const currentSessionIndex = sessions.findIndex(
|
||||
(session) => session.id === params.sessionId
|
||||
|
Loading…
Reference in New Issue
Block a user