Skip to content

Commit 9d84a03

Browse files
authored
feat: OIDC images (#31)
1 parent c86eb4e commit 9d84a03

11 files changed

Lines changed: 171 additions & 5 deletions

File tree

content/docs/guides/oidc.mdx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ To set up OIDC authentication with Pocket Id, follow these steps:
2323

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

26-
TODO: Pocket Id application creation image here
26+
![Pocket ID Application Creation](/assets/docs/pocketid-orca-registration.png?url)
27+
28+
You can find the OrcaCD logo [here](https://github.com/OrcaCD/orca-cd/tree/main/frontend/public/assets).
2729

2830
### 2. Configure OrcaCD
2931

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

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

4042
### 3. Test the Configuration
4143

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

47-
TODO: Login page image here
49+
<div className="w-xl mx-auto">![OrcaCD Login Page](/assets/docs/sso-login-screen.png?url)</div>

content/docs/guides/reverse-proxy.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ TODO
1111

1212
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:
1313

14-
```yml
14+
```yml lineNumbers
1515
services:
1616
hub:
1717
image: ghcr.io/orcacd/hub:latest

content/docs/helping-out/documentation.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ All markdown pages are under `/content/docs`. The file `meta.json` controls the
1717

1818
3. Add frontmatter:
1919

20-
```yaml
20+
```yaml lineNumbers
2121
---
2222
title: Installation
2323
description: Get OrcaCD running quickly with Docker installation
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: Account Recovery
3+
description: Steps to recover your account if you have lost access
4+
---
5+
6+
There are two ways to reset a password for a user:
7+
8+
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".
9+
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:
10+
11+
```bash
12+
docker compose exec hub /app/hub reset-password <user id or email>
13+
```
14+
15+
<Callout>The user with the reset password has to change the password on the next login.</Callout>
16+
17+
<AccountRecoveryTerminal />
324 KB
Loading
264 KB
Loading
84 KB
Loading
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { AnimatedSpan, Terminal, TypingAnimation } from "./terminal";
2+
3+
export function AccountRecoveryTerminal() {
4+
return (
5+
<Terminal>
6+
<TypingAnimation delay={0} duration={30}>
7+
$ docker compose exec hub /app/hub reset-password 019dc111-5220-77bc-9729-2335f88fa658
8+
</TypingAnimation>
9+
<AnimatedSpan delay={2500} className="text-fd-primary">
10+
{`
11+
╭────────────────────────────────────────────────────────────────────╮
12+
│ │
13+
│ Password Reset Successful │
14+
│ │
15+
│ User ID: 019dc111-5220-77bc-9729-2335f88fa658 │
16+
│ Email: test@orcacd.dev │
17+
│ New temporary password: w&BU6G,WM#!MX9M4eq │
18+
│ │
19+
│ Important: The user must change this password on the next login. │
20+
│ │
21+
╰────────────────────────────────────────────────────────────────────╯
22+
`}
23+
</AnimatedSpan>
24+
</Terminal>
25+
);
26+
}

src/components/terminal.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"use client";
2+
3+
import { cn } from "@/lib/utils";
4+
import { type MotionProps, motion } from "motion/react";
5+
import { useEffect, useRef, useState } from "react";
6+
7+
interface AnimatedSpanProps extends MotionProps {
8+
children: React.ReactNode;
9+
delay?: number;
10+
className?: string;
11+
}
12+
13+
export const AnimatedSpan = ({ children, delay = 0, className, ...props }: AnimatedSpanProps) => (
14+
<motion.div
15+
animate={{ opacity: 1, y: 0 }}
16+
className={cn("grid text-sm font-normal tracking-tight", className)}
17+
initial={{ opacity: 0, y: -5 }}
18+
transition={{ duration: 0.3, delay: delay / 1000 }}
19+
{...(props as any)}
20+
>
21+
{children}
22+
</motion.div>
23+
);
24+
25+
interface TypingAnimationProps extends MotionProps {
26+
children: string;
27+
className?: string;
28+
duration?: number;
29+
delay?: number;
30+
as?: React.ElementType;
31+
}
32+
33+
export const TypingAnimation = ({
34+
children,
35+
className,
36+
duration = 60,
37+
delay = 0,
38+
as: Component = "span",
39+
...props
40+
}: TypingAnimationProps) => {
41+
if (typeof children !== "string") {
42+
throw new Error("TypingAnimation: children must be a string. Received:");
43+
}
44+
45+
const MotionComponent = motion.create(Component, {
46+
forwardMotionProps: true,
47+
});
48+
49+
const [displayedText, setDisplayedText] = useState<string>("");
50+
const [started, setStarted] = useState(false);
51+
const elementRef = useRef<HTMLElement | null>(null);
52+
53+
useEffect(() => {
54+
const startTimeout = setTimeout(() => {
55+
setStarted(true);
56+
}, delay);
57+
return () => clearTimeout(startTimeout);
58+
}, [delay]);
59+
60+
useEffect(() => {
61+
if (!started) {
62+
return;
63+
}
64+
65+
let i = 0;
66+
const typingEffect = setInterval(() => {
67+
if (i < children.length) {
68+
setDisplayedText(children.substring(0, i + 1));
69+
i++;
70+
} else {
71+
clearInterval(typingEffect);
72+
}
73+
}, duration);
74+
75+
return () => {
76+
clearInterval(typingEffect);
77+
};
78+
}, [children, duration, started]);
79+
80+
return (
81+
<MotionComponent
82+
className={cn("text-sm font-normal tracking-tight", className)}
83+
ref={elementRef}
84+
{...(props as any)}
85+
>
86+
{displayedText}
87+
</MotionComponent>
88+
);
89+
};
90+
91+
interface TerminalProps {
92+
children: React.ReactNode;
93+
className?: string;
94+
}
95+
96+
export const Terminal = ({ children, className }: TerminalProps) => {
97+
return (
98+
<div className={cn("w-full rounded-xl border border-border bg-background", className)}>
99+
<div className="flex flex-col gap-y-2 border-b border-border p-4 ">
100+
<div className="flex flex-row gap-x-2">
101+
<div className="h-2 w-2 rounded-full bg-red-500" />
102+
<div className="h-2 w-2 rounded-full bg-yellow-500" />
103+
<div className="h-2 w-2 rounded-full bg-green-500" />
104+
</div>
105+
</div>
106+
<pre>
107+
<code className="grid gap-y-1 overflow-auto">{children}</code>
108+
</pre>
109+
</div>
110+
);
111+
};

src/lib/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type ClassValue, clsx } from "clsx";
2+
import { twMerge } from "tailwind-merge";
3+
4+
export function cn(...inputs: ClassValue[]) {
5+
return twMerge(clsx(inputs));
6+
}

0 commit comments

Comments
 (0)