Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions apps/web/src/lib/auth/RedirectIfLoggedIn.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { USER_SERVICE } from '$lib/user/userService';
import { inject } from '@gitbutler/shared/context';
import { WEB_ROUTES_SERVICE } from '@gitbutler/shared/routing/webRoutes.svelte';

const routesService = inject(WEB_ROUTES_SERVICE);
const userService = inject(USER_SERVICE);
const user = userService.user;
const isLoggedIn = $derived($user !== undefined);

// If there is a user, redirect to the home page
$effect(() => {
if (isLoggedIn) {
goto(routesService.homePath());
}
});
</script>
28 changes: 28 additions & 0 deletions apps/web/src/lib/auth/RedirectIfNotFinalized.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import { afterNavigate, goto } from '$app/navigation';
import { USER_SERVICE } from '$lib/user/userService';
import { inject } from '@gitbutler/shared/context';
import { WEB_ROUTES_SERVICE } from '@gitbutler/shared/routing/webRoutes.svelte';

const routesService = inject(WEB_ROUTES_SERVICE);
const userService = inject(USER_SERVICE);
const user = userService.user;
const userEmail = $derived($user?.email);
const userLogin = $derived($user?.login);
const isLoggedIn = $derived($user !== undefined);
// Logged in but missing email or login
const accountNotFinalized = $derived(isLoggedIn && (!userEmail || !userLogin));
let currentPathName = $state<string>(location.pathname);

// Keep track of the current path name to avoid redirect loops
afterNavigate((navigation) => {
currentPathName = navigation.to?.url.pathname || '';
});

// If the user account is not finalized, redirect to the finalization page
$effect(() => {
if (accountNotFinalized && currentPathName !== routesService.finalizeAccountPath()) {
goto(routesService.finalizeAccountPath());
}
});
</script>
15 changes: 7 additions & 8 deletions apps/web/src/lib/components/Navigation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import { inject } from '@gitbutler/shared/context';
import { WEB_ROUTES_SERVICE } from '@gitbutler/shared/routing/webRoutes.svelte';
import { Button, ContextMenu, ContextMenuItem, ContextMenuSection, Icon } from '@gitbutler/ui';

import { env } from '$env/dynamic/public';

const authService = inject(AUTH_SERVICE);
Expand All @@ -21,13 +20,9 @@
let ctxUserTriggerButton = $state<HTMLButtonElement | undefined>();
let isCtxMenuOpen = $state(false);

function login() {
window.location.href = `${env.PUBLIC_APP_HOST}cloud/login?callback=${window.location.href}`;
}

function logout() {
authService.clearToken();
window.location.href = `${env.PUBLIC_APP_HOST}cloud/logout?returnTo=${window.location.href}`;
window.location.href = `${env.PUBLIC_APP_HOST}cloud/logout`;
}
</script>

Expand Down Expand Up @@ -79,8 +74,12 @@
>
{:else}
<div class="login-signup-wrap">
<Button kind="outline" onclick={login}>Join GitButler</Button>
<Button style="pop" icon="signin" onclick={login}>Log in</Button>
<a href={routes.signupPath()}>
<Button kind="outline">Join GitButler</Button>
</a>
<a href={routes.loginPath()} title="Log in" aria-label="Log in">
<Button style="pop" icon="signin">Log in</Button>
</a>
</div>
{/if}
</div>
Expand Down
51 changes: 51 additions & 0 deletions apps/web/src/lib/components/login/GitHubButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
</script>

<a
class="oauth-login"
href={`${env.PUBLIC_APP_HOST}auth/github?origin=${encodeURIComponent(window.location.href)}`}
title="Sign in with GitHub"
aria-label="Sign in with GitHub"
>
<svg class="oauth-logo" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<title>Sign in with GitHub</title>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
fill="#000"
/>
</svg>
<span>Sign in with GitHub</span>
</a>

<style lang="postcss">
.oauth-login {
display: flex;
align-items: center;
padding: 8px;
gap: 8px;
border: 1px solid var(--clr-border-2);
border-radius: var(--radius-m);
background-color: var(--clr-bg-1);
color: var(--clr-scale-ntrl-0);
cursor: pointer;

&:hover {
background-color: var(--clr-bg-2);
}

span {
width: 100%;
font-weight: 500;
font-size: 14px;
text-align: center;
}
}

.oauth-logo {
width: 24px;
height: 24px;
}
</style>
61 changes: 61 additions & 0 deletions apps/web/src/lib/components/login/GoogleButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
</script>

<a
class="oauth-login"
href={`${env.PUBLIC_APP_HOST}auth/google_oauth2?origin=${encodeURIComponent(window.location.href)}`}
title="Sign in with Google"
aria-label="Sign in with Google"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="oauth-logo">
<title>Sign in with Google</title>
<path
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
fill="#4285f4"
></path>
<path
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
fill="#34a853"
></path>
<path
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
fill="#fbbc05"
></path>
<path
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
fill="#ea4335"
></path>
</svg>
<span>Sign in with Google</span>
</a>

<style lang="postcss">
.oauth-login {
display: flex;
align-items: center;
padding: 8px;
gap: 8px;
border: 1px solid var(--clr-border-2);
border-radius: var(--radius-m);
background-color: var(--clr-bg-1);
color: var(--clr-scale-ntrl-0);
cursor: pointer;

&:hover {
background-color: var(--clr-bg-2);
}

span {
width: 100%;
font-weight: 500;
font-size: 14px;
text-align: center;
}
}

.oauth-logo {
width: 24px;
height: 24px;
}
</style>
10 changes: 10 additions & 0 deletions apps/web/src/lib/user/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ export class UserService {
return user;
}

async refreshUser() {
try {
const user = await this.fetchUser();
this.user.set(user);
this.error.set(undefined);
} catch (error) {
this.error.set(error);
}
}

clearUser() {
this.user.set(undefined);
}
Expand Down
12 changes: 11 additions & 1 deletion apps/web/src/routes/(app)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import '$lib/styles/global.css';
import { page } from '$app/state';
import { ButlerAIClient, BUTLER_AI_CLIENT } from '$lib/ai/service';
import RedirectIfNotFinalized from '$lib/auth/RedirectIfNotFinalized.svelte';
import { AUTH_SERVICE } from '$lib/auth/authService.svelte';
import Footer from '$lib/components/Footer.svelte';
import Navigation from '$lib/components/Navigation.svelte';
Expand All @@ -20,6 +21,7 @@
} from '@gitbutler/shared/chat/chatChannelsService';
import { inject, provide } from '@gitbutler/shared/context';
import { FeedService, FEED_SERVICE } from '@gitbutler/shared/feeds/service';
import LoginService, { LOGIN_SERVICE } from '@gitbutler/shared/login/loginService';
import { HttpClient, HTTP_CLIENT } from '@gitbutler/shared/network/httpClient';
import {
OrganizationService,
Expand Down Expand Up @@ -71,6 +73,9 @@
const httpClient = new HttpClient(window.fetch, env.PUBLIC_APP_HOST, authService.tokenReadable);
provide(HTTP_CLIENT, httpClient);

const loginService = new LoginService(httpClient);
provide(LOGIN_SERVICE, loginService);

const aiService = new ButlerAIClient(httpClient);
provide(BUTLER_AI_CLIENT, aiService);

Expand Down Expand Up @@ -142,10 +147,15 @@
provide(RULES_SERVICE, rulesService);

const isCommitPage = $derived(page.url.pathname.includes('/commit/'));
const isLoginPage = $derived(page.url.pathname.includes('/login'));
const isSignupPage = $derived(page.url.pathname.includes('/signup'));
const hasNavigation = $derived(!isCommitPage && !isLoginPage && !isSignupPage);
</script>

<RedirectIfNotFinalized />

<div class="app">
{#if !isCommitPage}
{#if hasNavigation}
<Navigation />
{/if}

Expand Down
20 changes: 19 additions & 1 deletion apps/web/src/routes/(app)/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { AUTH_SERVICE } from '$lib/auth/authService.svelte';
import DashboardLayout from '$lib/components/dashboard/DashboardLayout.svelte';
import { USER_SERVICE } from '$lib/user/userService';
import { inject } from '@gitbutler/shared/context';
import { isFound } from '@gitbutler/shared/network/loadable';
import { getRecentlyPushedProjects } from '@gitbutler/shared/organizations/projectsPreview.svelte';
import { WEB_ROUTES_SERVICE } from '@gitbutler/shared/routing/webRoutes.svelte';
import { Button } from '@gitbutler/ui';

const authService = inject(AUTH_SERVICE);
const persistedToken = authService.token;

const routes = inject(WEB_ROUTES_SERVICE);
const userService = inject(USER_SERVICE);
const user = userService.user;

const loggedIn = $derived($user !== undefined);
const recentProjects = getRecentlyPushedProjects();
let hasRecentProjects = $state(false);

Expand All @@ -25,9 +34,18 @@
}
}
});

$effect(() => {
if (!loggedIn && persistedToken.current) {
// Clear any stale tokens if the user is not logged in
authService.clearToken();
}
});
</script>

{#if hasRecentProjects}
{#if !loggedIn}
<p>Loading...</p>
{:else if hasRecentProjects}
<DashboardLayout>
<p>You have no recent projects!</p>
</DashboardLayout>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { AUTH_SERVICE } from '$lib/auth/authService.svelte';
import BranchIndexCard from '$lib/components/branches/BranchIndexCard.svelte';
import DashboardLayout from '$lib/components/dashboard/DashboardLayout.svelte';
import Table from '$lib/components/table/Table.svelte';
import { USER_SERVICE } from '$lib/user/userService';
import { getBranchReviewsForRepository } from '@gitbutler/shared/branches/branchesPreview.svelte';
import { BranchStatus } from '@gitbutler/shared/branches/types';
import { inject } from '@gitbutler/shared/context';
Expand All @@ -14,12 +14,13 @@
import { Button, Select, SelectItem } from '@gitbutler/ui';

// Get authentication service and check if user is logged in
const authService = inject(AUTH_SERVICE);
const routes = inject(WEB_ROUTES_SERVICE);
const userService = inject(USER_SERVICE);
const user = userService.user;

// If there is no token (user not logged in), redirect to home
// If there is no user (user not logged in), redirect to home
$effect(() => {
if (!authService.token.current) {
if ($user === undefined) {
goto(routes.homePath());
}
});
Expand Down
9 changes: 5 additions & 4 deletions apps/web/src/routes/(app)/[ownerSlug]/rules/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { AUTH_SERVICE } from '$lib/auth/authService.svelte';
import { USER_SERVICE } from '$lib/user/userService';
import { eventTimeStamp } from '@gitbutler/shared/branches/utils';
import { inject } from '@gitbutler/shared/context';
import Loading from '@gitbutler/shared/network/Loading.svelte';
Expand All @@ -11,12 +11,13 @@
import type { Rule } from '@gitbutler/shared/rules/types';

// Get authentication service and check if user is logged in
const authService = inject(AUTH_SERVICE);
const routes = inject(WEB_ROUTES_SERVICE);
const userService = inject(USER_SERVICE);
const user = userService.user;

// If there is no token (user not logged in), redirect to home
// If there is no user (user not logged in), redirect to home
$effect(() => {
if (!authService.token.current) {
if ($user === undefined) {
goto(routes.homePath());
}
});
Expand Down
Loading
Loading