Update db and db-schema packages to export from dist/ #1
77
.claude/skills/gitea/SKILL.md
Normal file
77
.claude/skills/gitea/SKILL.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
name: gitea
|
||||||
|
description: Create pull requests on Gitea using the tea CLI. Use when the user asks to "create a PR", "open a pull request", "make a PR", "submit PR", or any variation involving pull requests for this repository.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Gitea Pull Requests
|
||||||
|
|
||||||
|
This project uses Gitea (git.rev.iq) for hosting and the `tea` CLI for creating pull requests.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- The `tea` CLI is installed via devenv (pinned to 0.10.1 to avoid TTY bugs in 0.11.x)
|
||||||
|
- Login is configured via `~/.config/tea/config.yml`
|
||||||
|
|
||||||
|
## Creating a Pull Request
|
||||||
|
|
||||||
|
When asked to create a PR, follow these steps:
|
||||||
|
|
||||||
|
### 1. Check current state
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status
|
||||||
|
git log --oneline -5
|
||||||
|
git diff master...HEAD --stat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Ensure changes are committed and pushed
|
||||||
|
|
||||||
|
If there are uncommitted changes, commit them first. Then push:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push -u origin <branch-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Create the PR using tea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tea pr create \
|
||||||
|
-r igm/publisher-dashboard \
|
||||||
|
--title "PR title here" \
|
||||||
|
--description "## Summary
|
||||||
|
- Change 1
|
||||||
|
- Change 2
|
||||||
|
|
||||||
|
🤖 Generated with [Claude Code](https://claude.ai/code)" \
|
||||||
|
--head <source-branch> \
|
||||||
|
--base master
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important flags:**
|
||||||
|
- `-r igm/publisher-dashboard` - Always specify the repo explicitly (required due to SSH remote detection issues)
|
||||||
|
- `--head` - The source branch (your feature branch)
|
||||||
|
- `--base` - The target branch (usually `master`)
|
||||||
|
|
||||||
|
### 4. Return the PR URL
|
||||||
|
|
||||||
|
The command outputs the PR URL. Always share this with the user.
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
```
|
||||||
|
# #1 Update packages to export from dist/ (open)
|
||||||
|
|
||||||
|
@igm created 2024-01-11 **master** <- **fix-exports**
|
||||||
|
|
||||||
|
--------
|
||||||
|
|
||||||
|
• No Conflicts
|
||||||
|
• Maintainers are allowed to edit
|
||||||
|
|
||||||
|
https://git.rev.iq/igm/publisher-dashboard/pulls/1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- If tea fails with TTY errors, ensure you're using tea 0.10.1 (configured in `nix/tea.nix`)
|
||||||
|
- The repo flag `-r igm/publisher-dashboard` is required because the SSH remote isn't auto-detected
|
||||||
@@ -7,6 +7,13 @@ Before starting the dev server, check if it's already running:
|
|||||||
- The dev server runs on port 6827 (may fall back to 6828 if port is in use)
|
- The dev server runs on port 6827 (may fall back to 6828 if port is in use)
|
||||||
- Start with `bun run --cwd apps/publisher-dashboard dev` or `devenv up`
|
- Start with `bun run --cwd apps/publisher-dashboard dev` or `devenv up`
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
This repo uses Gitea (git.rev.iq) with the `tea` CLI for pull requests:
|
||||||
|
- Use the `/gitea` skill when creating PRs
|
||||||
|
- tea 0.10.1 is pinned in `nix/tea.nix` (0.11.x has TTY bugs)
|
||||||
|
- Always specify `-r igm/publisher-dashboard` flag (SSH remote auto-detection doesn't work)
|
||||||
|
|
||||||
## macOS sed Syntax
|
## macOS sed Syntax
|
||||||
|
|
||||||
macOS uses BSD sed which differs from GNU sed:
|
macOS uses BSD sed which differs from GNU sed:
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ function isActive(href: string, pathname: string): boolean {
|
|||||||
{#each navItems as item (item.href)}
|
{#each navItems as item (item.href)}
|
||||||
{@const active = isActive(item.href, $page.url.pathname)}
|
{@const active = isActive(item.href, $page.url.pathname)}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"inline-flex h-[calc(100%-1px)] items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow]",
|
"inline-flex h-[calc(100%-1px)] items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow]",
|
||||||
active
|
active
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ const userQuery = createQuery(() => ({
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!isAuthPage && userQuery.error) {
|
if (!isAuthPage && userQuery.error) {
|
||||||
goto(
|
goto(
|
||||||
resolve(`/auth/login?redirect=${encodeURIComponent(page.url.pathname)}`),
|
resolve(
|
||||||
|
`/auth/login?redirect=${encodeURIComponent(page.url.pathname)}` as any,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const filters = [
|
|||||||
<div class="divide-y divide-border/50">
|
<div class="divide-y divide-border/50">
|
||||||
{#each filters as filter (filter.label)}
|
{#each filters as filter (filter.label)}
|
||||||
<a
|
<a
|
||||||
href={resolve(filter.href)}
|
href={resolve(filter.href as any)}
|
||||||
class="group flex items-center gap-3 px-5 py-3 transition-colors hover:bg-muted/30"
|
class="group flex items-center gap-3 px-5 py-3 transition-colors hover:bg-muted/30"
|
||||||
>
|
>
|
||||||
<div class="flex h-7 w-7 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-foreground/10 group-hover:text-foreground">
|
<div class="flex h-7 w-7 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-foreground/10 group-hover:text-foreground">
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function handleTabChange(tabId: string) {
|
|||||||
} else {
|
} else {
|
||||||
url.searchParams.set("tab", tabId);
|
url.searchParams.set("tab", tabId);
|
||||||
}
|
}
|
||||||
goto(resolve(url.toString()), { replaceState: true, noScroll: true });
|
goto(resolve(url.toString() as any), { replaceState: true, noScroll: true });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import MonitorIcon from "@lucide/svelte/icons/monitor";
|
|||||||
import ShieldCheckIcon from "@lucide/svelte/icons/shield-check";
|
import ShieldCheckIcon from "@lucide/svelte/icons/shield-check";
|
||||||
import UserIcon from "@lucide/svelte/icons/user";
|
import UserIcon from "@lucide/svelte/icons/user";
|
||||||
import { createQuery } from "@tanstack/svelte-query";
|
import { createQuery } from "@tanstack/svelte-query";
|
||||||
|
import { resolve } from "$app/paths";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
import { api } from "$lib/api/client";
|
import { api } from "$lib/api/client";
|
||||||
import { DashboardLayout } from "$lib/components/layout";
|
import { DashboardLayout } from "$lib/components/layout";
|
||||||
@@ -91,10 +92,10 @@ function isActive(href: string): boolean {
|
|||||||
<nav class="w-full shrink-0 lg:w-64">
|
<nav class="w-full shrink-0 lg:w-64">
|
||||||
<!-- Mobile: horizontal scroll -->
|
<!-- Mobile: horizontal scroll -->
|
||||||
<div class="flex gap-2 overflow-x-auto pb-2 lg:hidden">
|
<div class="flex gap-2 overflow-x-auto pb-2 lg:hidden">
|
||||||
{#each navItems as item}
|
{#each navItems as item (item.href)}
|
||||||
{@const active = isActive(item.href)}
|
{@const active = isActive(item.href)}
|
||||||
<a
|
<a
|
||||||
href={item.href}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex shrink-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors",
|
"flex shrink-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors",
|
||||||
active
|
active
|
||||||
@@ -110,10 +111,10 @@ function isActive(href: string): boolean {
|
|||||||
|
|
||||||
<!-- Desktop: vertical list -->
|
<!-- Desktop: vertical list -->
|
||||||
<div class="hidden space-y-1 lg:block">
|
<div class="hidden space-y-1 lg:block">
|
||||||
{#each navItems as item}
|
{#each navItems as item (item.href)}
|
||||||
{@const active = isActive(item.href)}
|
{@const active = isActive(item.href)}
|
||||||
<a
|
<a
|
||||||
href={item.href}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"group flex items-start gap-3 rounded-lg px-3 py-2.5 transition-colors",
|
"group flex items-start gap-3 rounded-lg px-3 py-2.5 transition-colors",
|
||||||
active
|
active
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ async function handleSignOut() {
|
|||||||
await api.auth.logout();
|
await api.auth.logout();
|
||||||
queryClient.clear();
|
queryClient.clear();
|
||||||
open = false;
|
open = false;
|
||||||
goto(resolve("/login"));
|
goto(resolve("/auth/login"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sign out:", error);
|
console.error("Failed to sign out:", error);
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ const navItems = [
|
|||||||
? $page.url.pathname === "/admin"
|
? $page.url.pathname === "/admin"
|
||||||
: $page.url.pathname.startsWith(item.href)}
|
: $page.url.pathname.startsWith(item.href)}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
onclick={handleNavClick}
|
onclick={handleNavClick}
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ async function handleSignOut() {
|
|||||||
try {
|
try {
|
||||||
await api.auth.logout();
|
await api.auth.logout();
|
||||||
queryClient.clear();
|
queryClient.clear();
|
||||||
goto(resolve("/login"));
|
goto(resolve("/auth/login"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sign out:", error);
|
console.error("Failed to sign out:", error);
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ const navItems = [
|
|||||||
? $page.url.pathname === "/admin"
|
? $page.url.pathname === "/admin"
|
||||||
: $page.url.pathname.startsWith(item.href)}
|
: $page.url.pathname.startsWith(item.href)}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"group relative flex h-8 w-8 items-center justify-center rounded-lg transition-all duration-150",
|
"group relative flex h-8 w-8 items-center justify-center rounded-lg transition-all duration-150",
|
||||||
isActive
|
isActive
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const navItems = $derived.by(() => {
|
|||||||
: $page.url.pathname === item.href ||
|
: $page.url.pathname === item.href ||
|
||||||
$page.url.pathname.startsWith(item.href + "/")}
|
$page.url.pathname.startsWith(item.href + "/")}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"group relative flex h-8 w-8 items-center justify-center rounded-lg transition-all duration-150",
|
"group relative flex h-8 w-8 items-center justify-center rounded-lg transition-all duration-150",
|
||||||
isActive
|
isActive
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ async function handleSignOut() {
|
|||||||
await api.auth.logout();
|
await api.auth.logout();
|
||||||
queryClient.clear();
|
queryClient.clear();
|
||||||
open = false;
|
open = false;
|
||||||
goto(resolve("/login"));
|
goto(resolve("/auth/login"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sign out:", error);
|
console.error("Failed to sign out:", error);
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ async function handleSignOut() {
|
|||||||
$page.url.pathname === item.href ||
|
$page.url.pathname === item.href ||
|
||||||
(item.href !== "/" && $page.url.pathname.startsWith(item.href))}
|
(item.href !== "/" && $page.url.pathname.startsWith(item.href))}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
onclick={handleNavClick}
|
onclick={handleNavClick}
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const orgsQuery = createQuery(() => ({
|
|||||||
const orgs = $derived(orgsQuery.data ?? []);
|
const orgs = $derived(orgsQuery.data ?? []);
|
||||||
|
|
||||||
function handleOrgSelect(slug: string) {
|
function handleOrgSelect(slug: string) {
|
||||||
goto(resolve(`/dashboard/${slug}`));
|
goto(resolve(`/dashboard/${slug}` as any));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ async function handleSignOut() {
|
|||||||
await api.auth.logout();
|
await api.auth.logout();
|
||||||
// Clear all cached queries
|
// Clear all cached queries
|
||||||
queryClient.clear();
|
queryClient.clear();
|
||||||
goto(resolve("/login"));
|
goto(resolve("/auth/login"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sign out:", error);
|
console.error("Failed to sign out:", error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function isActive(href: string): boolean {
|
|||||||
{#each navItems as item (item.href)}
|
{#each navItems as item (item.href)}
|
||||||
{@const active = isActive(item.href)}
|
{@const active = isActive(item.href)}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex shrink-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors",
|
"flex shrink-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors",
|
||||||
active
|
active
|
||||||
@@ -81,7 +81,7 @@ function isActive(href: string): boolean {
|
|||||||
{#each navItems as item (item.href)}
|
{#each navItems as item (item.href)}
|
||||||
{@const active = isActive(item.href)}
|
{@const active = isActive(item.href)}
|
||||||
<a
|
<a
|
||||||
href={resolve(item.href)}
|
href={resolve(item.href as any)}
|
||||||
class={cn(
|
class={cn(
|
||||||
"group flex items-start gap-3 rounded-lg px-3 py-2.5 transition-colors",
|
"group flex items-start gap-3 rounded-lg px-3 py-2.5 transition-colors",
|
||||||
active
|
active
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ const orgsQuery = createQuery(() => ({
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (orgsQuery.error) {
|
if (orgsQuery.error) {
|
||||||
// Not authenticated, redirect to login
|
// Not authenticated, redirect to login
|
||||||
goto(resolve(`/auth/login?redirect=${encodeURIComponent("/")}`));
|
goto(resolve(`/auth/login?redirect=${encodeURIComponent("/")}` as any));
|
||||||
} else if (orgsQuery.data) {
|
} else if (orgsQuery.data) {
|
||||||
if (orgsQuery.data.length > 0) {
|
if (orgsQuery.data.length > 0) {
|
||||||
// Redirect to first org's dashboard
|
// Redirect to first org's dashboard
|
||||||
goto(resolve(`/dashboard/${orgsQuery.data[0].slug}`), {
|
goto(resolve(`/dashboard/${orgsQuery.data[0].slug}` as any), {
|
||||||
replaceState: true,
|
replaceState: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { createQuery, useQueryClient } from "@tanstack/svelte-query";
|
import { createQuery, useQueryClient } from "@tanstack/svelte-query";
|
||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
|
import { resolve } from "$app/paths";
|
||||||
import { api } from "$lib/api/client";
|
import { api } from "$lib/api/client";
|
||||||
import { ConfirmDialog } from "$lib/components/account";
|
import { ConfirmDialog } from "$lib/components/account";
|
||||||
import { Alert, AlertDescription } from "$lib/components/ui/alert";
|
import { Alert, AlertDescription } from "$lib/components/ui/alert";
|
||||||
@@ -38,7 +39,7 @@ const userQuery = createQuery(() => ({
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (userQuery.data && !userQuery.data.isSuperuser) {
|
if (userQuery.data && !userQuery.data.isSuperuser) {
|
||||||
toast.error("Access denied. Superuser privileges required.");
|
toast.error("Access denied. Superuser privileges required.");
|
||||||
goto("/account");
|
goto(resolve("/account"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const acceptMutation = createMutation(() => ({
|
|||||||
queryClient.invalidateQueries({ queryKey: ["orgs"] });
|
queryClient.invalidateQueries({ queryKey: ["orgs"] });
|
||||||
// Redirect to the org dashboard
|
// Redirect to the org dashboard
|
||||||
if (inviteQuery.data) {
|
if (inviteQuery.data) {
|
||||||
goto(resolve(`/dashboard/${inviteQuery.data.org.slug}`));
|
goto(resolve(`/dashboard/${inviteQuery.data.org.slug}` as any));
|
||||||
} else {
|
} else {
|
||||||
goto(resolve("/dashboard"));
|
goto(resolve("/dashboard"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ $effect(() => {
|
|||||||
if (userQuery.error) {
|
if (userQuery.error) {
|
||||||
goto(
|
goto(
|
||||||
resolve(
|
resolve(
|
||||||
`/auth/login?redirect=${encodeURIComponent(window.location.pathname)}`,
|
`/auth/login?redirect=${encodeURIComponent(window.location.pathname)}` as any,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,9 +81,9 @@ let { children }: Props = $props();
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<p class="text-center text-xs text-muted-foreground">
|
<p class="text-center text-xs text-muted-foreground">
|
||||||
By continuing, you agree to our
|
By continuing, you agree to our
|
||||||
<a href={resolve("/terms")} class="underline underline-offset-4 hover:text-foreground">Terms of Service</a>
|
<a href={resolve("/terms" as any)} class="underline underline-offset-4 hover:text-foreground">Terms of Service</a>
|
||||||
and
|
and
|
||||||
<a href={resolve("/privacy")} class="underline underline-offset-4 hover:text-foreground">Privacy Policy</a>
|
<a href={resolve("/privacy" as any)} class="underline underline-offset-4 hover:text-foreground">Privacy Policy</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const statusQuery = createQuery(() => ({
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (statusQuery.data?.status === "completed") {
|
if (statusQuery.data?.status === "completed") {
|
||||||
clearLoginFlowState();
|
clearLoginFlowState();
|
||||||
goto(resolve(statusQuery.data.redirectTo || "/"));
|
goto(resolve((statusQuery.data.redirectTo || "/") as any));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ async function handleTrust() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSkip() {
|
async function handleSkip() {
|
||||||
goto(resolve("/performance"));
|
goto(resolve("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get device icon based on type
|
// Get device icon based on type
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ $effect(() => {
|
|||||||
if (orgsQuery.error) {
|
if (orgsQuery.error) {
|
||||||
goto(
|
goto(
|
||||||
resolve(
|
resolve(
|
||||||
`/auth/login?redirect=${encodeURIComponent(window.location.pathname)}`,
|
`/auth/login?redirect=${encodeURIComponent(window.location.pathname)}` as any,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ async function acceptInvite(): Promise<void> {
|
|||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
// Redirect to login with return URL
|
// Redirect to login with return URL
|
||||||
const returnUrl = `/invite/accept?token=${encodeURIComponent(token)}`;
|
const returnUrl = `/invite/accept?token=${encodeURIComponent(token)}`;
|
||||||
goto(resolve(`/auth/login?redirect=${encodeURIComponent(returnUrl)}`));
|
goto(
|
||||||
|
resolve(`/auth/login?redirect=${encodeURIComponent(returnUrl)}` as any),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Use tea 0.10.1 to avoid TTY bug in 0.11.x
|
||||||
|
# See: https://gitea.com/gitea/tea/issues/827
|
||||||
|
tea = pkgs.callPackage ./nix/tea.nix { };
|
||||||
|
in
|
||||||
{
|
{
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
nixfmt-rfc-style
|
nixfmt-rfc-style
|
||||||
|
|||||||
53
nix/tea.nix
Normal file
53
nix/tea.nix
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
fetchurl,
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "0.10.1";
|
||||||
|
|
||||||
|
sources = {
|
||||||
|
x86_64-linux = {
|
||||||
|
url = "https://dl.gitea.com/tea/${version}/tea-${version}-linux-amd64";
|
||||||
|
sha256 = "sha256-QcODwFm2T8hVCqBkp8FAnQ3KbNw8P0ZHv0iJ4zSP5mA=";
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
url = "https://dl.gitea.com/tea/${version}/tea-${version}-linux-arm64";
|
||||||
|
sha256 = "sha256-qfvJ4FJSHt1+sMG4hPwGNFLChqhNNf+l3ELQ97zZm50=";
|
||||||
|
};
|
||||||
|
x86_64-darwin = {
|
||||||
|
url = "https://dl.gitea.com/tea/${version}/tea-${version}-darwin-amd64";
|
||||||
|
sha256 = "sha256-WKjZKhFKWjZqnrdxPv00fzTIc0z4xrLSsL+jqLQ1huc=";
|
||||||
|
};
|
||||||
|
aarch64-darwin = {
|
||||||
|
url = "https://dl.gitea.com/tea/${version}/tea-${version}-darwin-arm64";
|
||||||
|
sha256 = "sha256-SMwxMEDKmhbLvLn1ZR1MmbjutZPk0P9QAfvNKCvrSk0=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
src = sources.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "tea";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
inherit (src) url sha256;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
install -D $src $out/bin/tea
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A command line tool to interact with Gitea servers";
|
||||||
|
homepage = "https://gitea.com/gitea/tea";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = builtins.attrNames sources;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,8 +3,13 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
|||||||
@@ -3,8 +3,13 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
|||||||
Reference in New Issue
Block a user