Skip to content
Merged
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
8 changes: 5 additions & 3 deletions content/docs/guides/oidc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ To set up OIDC authentication with Pocket Id, follow these steps:

Go to your Pocket ID dashboard and create a new application. Give it a name and leave the redirect URI blank for now.

TODO: Pocket Id application creation image here
![Pocket ID Application Creation](/assets/docs/pocketid-orca-registration.png?url)

You can find the OrcaCD logo [here](https://github.com/OrcaCD/orca-cd/tree/main/frontend/public/assets).

### 2. Configure OrcaCD

Expand All @@ -35,7 +37,7 @@ TODO: Pocket Id application creation image here
- **Client Secret**: The client secret from your Pocket Id application.
3. Save the configuration and ensure it is enabled.

TODO: Orca CD OIDC configuration image here
![OrcaCD OIDC Configuration](/assets/docs/orca-sso-registration.png?url)

### 3. Test the Configuration

Expand All @@ -44,4 +46,4 @@ TODO: Orca CD OIDC configuration image here
3. You will be redirected to the Pocket Id login page. Enter your credentials and log in.
4. After successful authentication, you will be redirected back to OrcaCD and logged in with your Pocket Id account.

TODO: Login page image here
<div className="w-xl mx-auto">![OrcaCD Login Page](/assets/docs/sso-login-screen.png?url)</div>
2 changes: 1 addition & 1 deletion content/docs/guides/reverse-proxy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TODO

To use Traefik as a reverse proxy for OrcaCD, you can add the following labels to your Docker Compose configuration for the OrcaCD Hub service:

```yml
```yml lineNumbers
services:
hub:
image: ghcr.io/orcacd/hub:latest
Expand Down
2 changes: 1 addition & 1 deletion content/docs/helping-out/documentation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ All markdown pages are under `/content/docs`. The file `meta.json` controls the

3. Add frontmatter:

```yaml
```yaml lineNumbers
---
title: Installation
description: Get OrcaCD running quickly with Docker installation
Expand Down
17 changes: 17 additions & 0 deletions content/docs/troubleshooting/account-recovery.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Account Recovery
description: Steps to recover your account if you have lost access
---

There are two ways to reset a password for a user:

1. UI: An admin can reset the password for a user in the admin panel under the "Users" tab by clicking on the three dots next to the user's name and selecting "Edit".
2. Terminal: You can reset a password for a user by running `hub reset-password <user id or email>`. To execute this script with Docker you have to run the following command:

```bash
docker compose exec hub /app/hub reset-password <user id or email>
```

<Callout>The user with the reset password has to change the password on the next login.</Callout>

<AccountRecoveryTerminal />
Binary file added public/assets/docs/orca-sso-registration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/docs/sso-login-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/components/account-recovery-terminal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { AnimatedSpan, Terminal, TypingAnimation } from "./terminal";

export function AccountRecoveryTerminal() {
return (
<Terminal>
<TypingAnimation delay={0} duration={30}>
$ docker compose exec hub /app/hub reset-password 019dc111-5220-77bc-9729-2335f88fa658
</TypingAnimation>
<AnimatedSpan delay={2500} className="text-fd-primary">
{`
╭────────────────────────────────────────────────────────────────────╮
│ │
│ Password Reset Successful │
│ │
│ User ID: 019dc111-5220-77bc-9729-2335f88fa658 │
│ Email: test@orcacd.dev │
│ New temporary password: w&BU6G,WM#!MX9M4eq │
│ │
│ Important: The user must change this password on the next login. │
│ │
╰────────────────────────────────────────────────────────────────────╯
`}
</AnimatedSpan>
</Terminal>
);
}
111 changes: 111 additions & 0 deletions src/components/terminal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"use client";

import { cn } from "@/lib/utils";
import { type MotionProps, motion } from "motion/react";
import { useEffect, useRef, useState } from "react";

interface AnimatedSpanProps extends MotionProps {
children: React.ReactNode;
delay?: number;
className?: string;
}

export const AnimatedSpan = ({ children, delay = 0, className, ...props }: AnimatedSpanProps) => (
<motion.div
animate={{ opacity: 1, y: 0 }}
className={cn("grid text-sm font-normal tracking-tight", className)}
initial={{ opacity: 0, y: -5 }}
transition={{ duration: 0.3, delay: delay / 1000 }}
{...(props as any)}
>
{children}
</motion.div>
);

interface TypingAnimationProps extends MotionProps {
children: string;
className?: string;
duration?: number;
delay?: number;
as?: React.ElementType;
}

export const TypingAnimation = ({
children,
className,
duration = 60,
delay = 0,
as: Component = "span",
...props
}: TypingAnimationProps) => {
if (typeof children !== "string") {
throw new Error("TypingAnimation: children must be a string. Received:");
}

const MotionComponent = motion.create(Component, {
forwardMotionProps: true,
});

const [displayedText, setDisplayedText] = useState<string>("");
const [started, setStarted] = useState(false);
const elementRef = useRef<HTMLElement | null>(null);

useEffect(() => {
const startTimeout = setTimeout(() => {
setStarted(true);
}, delay);
return () => clearTimeout(startTimeout);
}, [delay]);

useEffect(() => {
if (!started) {
return;
}

let i = 0;
const typingEffect = setInterval(() => {
if (i < children.length) {
setDisplayedText(children.substring(0, i + 1));
i++;
} else {
clearInterval(typingEffect);
}
}, duration);

return () => {
clearInterval(typingEffect);
};
}, [children, duration, started]);

return (
<MotionComponent
className={cn("text-sm font-normal tracking-tight", className)}
ref={elementRef}
{...(props as any)}
>
{displayedText}
</MotionComponent>
);
};

interface TerminalProps {
children: React.ReactNode;
className?: string;
}

export const Terminal = ({ children, className }: TerminalProps) => {
return (
<div className={cn("w-full rounded-xl border border-border bg-background", className)}>
<div className="flex flex-col gap-y-2 border-b border-border p-4 ">
<div className="flex flex-row gap-x-2">
<div className="h-2 w-2 rounded-full bg-red-500" />
<div className="h-2 w-2 rounded-full bg-yellow-500" />
<div className="h-2 w-2 rounded-full bg-green-500" />
</div>
</div>
<pre>
<code className="grid gap-y-1 overflow-auto">{children}</code>
</pre>
</div>
);
};
6 changes: 6 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
4 changes: 4 additions & 0 deletions src/routes/docs/$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import defaultMdxComponents from "fumadocs-ui/mdx";
import { baseOptions } from "@/lib/layout.shared";
import { getPageMarkdownUrl, source } from "@/lib/source";
import { Suspense } from "react";
import { AccountRecoveryTerminal } from "@/components/account-recovery-terminal";
import { ImageZoom } from "fumadocs-ui/components/image-zoom";

export const Route = createFileRoute("/docs/$")({
component: Page,
Expand Down Expand Up @@ -77,6 +79,8 @@ const clientLoader = browserCollections.docs.createClientLoader({
<MDX
components={{
...defaultMdxComponents,
AccountRecoveryTerminal,
img: (props) => <ImageZoom {...(props as any)} />,
}}
/>
</DocsBody>
Expand Down