Skip to content

Commit 5cb7977

Browse files
Merge origin/main into feat/precommit-oxfmt-docs
Co-authored-by: erickteowarang <30395423+erickteowarang@users.noreply.github.com>
2 parents 5beb4b1 + f02f702 commit 5cb7977

25 files changed

Lines changed: 1483 additions & 366 deletions

.changeset/brave-olives-march.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@tailor-platform/app-shell": patch
3+
---
4+
5+
Fix and improve `DescriptionCard` component:
6+
7+
- Fix relative date formatting producing incorrect output for future dates (negative time diff)
8+
- Add i18n label support for relative date strings
9+
- Use react-router `<Link>` for internal navigation in link and reference fields instead of plain `<a>` tags

.github/workflows/ci-e2e.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: CI (e2e)
2+
3+
on:
4+
push:
5+
paths:
6+
- "packages/core/**"
7+
- "e2e/**"
8+
- ".github/workflows/ci-e2e.yaml"
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
e2e:
16+
runs-on: ubuntu-latest
17+
container:
18+
image: mcr.microsoft.com/playwright:v1.51.1-noble
19+
steps:
20+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21+
with:
22+
persist-credentials: false
23+
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
24+
with:
25+
run_install: false
26+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
27+
with:
28+
cache: pnpm
29+
cache-dependency-path: ./pnpm-lock.yaml
30+
node-version-file: "./package.json"
31+
- name: Install dependencies
32+
run: pnpm install
33+
- name: Build packages
34+
run: pnpm exec turbo run build
35+
- name: Lint & Type-check
36+
run: pnpm exec turbo run lint type-check --filter=e2e
37+
- name: Run E2E tests
38+
run: pnpm --filter e2e test:e2e
39+
env:
40+
VITE_TAILOR_APP_URL: ${{ secrets.E2E_TAILOR_APP_URL }}
41+
VITE_TAILOR_CLIENT_ID: ${{ secrets.E2E_TAILOR_CLIENT_ID }}
42+
E2E_USER_EMAIL: ${{ secrets.E2E_USER_EMAIL }}
43+
E2E_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}

.github/workflows/ci-packages.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ on:
66
- "packages/**"
77
- "examples/**"
88
- "docs/**"
9+
- "package.json"
10+
- "pnpm-lock.yaml"
11+
- "pnpm-workspace.yaml"
912
- ".github/workflows/ci-packages.yaml"
1013
- ".github/actions/ci/action.yaml"
1114

docs/components/description-card.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ Format examples:
127127
- `short`: 3/6/2026
128128
- `medium`: Mar 6, 2026
129129
- `long`: March 6, 2026 at 2:30 PM
130-
- `relative`: 2 hours ago
130+
- `relative`: 2 hours ago / In 3 days
131+
132+
Relative dates support both past and future values and are automatically localized based on the AppShell locale (English and Japanese are built in).
131133

132134
### link
133135

@@ -145,6 +147,8 @@ Renders a clickable link.
145147
}
146148
```
147149

150+
Internal links (when `external` is not set or `false`) use react-router `<Link>` for client-side navigation. External links (when `external: true`) open in a new tab using a standard `<a>` tag.
151+
148152
### address
149153

150154
Formats multi-line address display.
@@ -168,7 +172,7 @@ Formats multi-line address display.
168172

169173
### reference
170174

171-
Links to related documents with auto-generated URLs.
175+
Links to related documents with auto-generated URLs using react-router `<Link>` for client-side navigation.
172176

173177
```tsx
174178
{

e2e/.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Tailor Platform workspace URL (e.g., https://xyz.erp.dev)
2+
VITE_TAILOR_APP_URL=
3+
# OAuth2 public client ID
4+
VITE_TAILOR_CLIENT_ID=
5+
6+
# E2E test user credentials
7+
E2E_USER_EMAIL=e2e-test@example.com
8+
E2E_USER_PASSWORD=TestPassword123!

e2e/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
.env
3+
test-results/
4+
playwright-report/
5+
blob-report/
6+
.tailor-sdk

e2e/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# E2E Tests for AuthProvider
2+
3+
Playwright-based E2E tests that verify the AuthProvider OAuth authentication flow against a real Tailor Platform workspace.
4+
5+
## Setup
6+
7+
### 1. Deploy backend to Tailor Platform
8+
9+
```bash
10+
cd e2e/backend
11+
TAILOR_PLATFORM_WORKSPACE_ID=<your-workspace-id> pnpm deploy
12+
```
13+
14+
After deploy, retrieve the app URL and client ID using `tailor-sdk`:
15+
16+
```bash
17+
# Get the app URL
18+
npx tailor-sdk show --workspace-id <your-workspace-id> --json
19+
# → {"url": "https://<slug>.erp.dev", ...}
20+
21+
# Get the OAuth2 client ID
22+
npx tailor-sdk oauth2client list --workspace-id <your-workspace-id> --json
23+
# → [{"clientId": "tpoc_...", ...}]
24+
```
25+
26+
### 2. Create a test user
27+
28+
Open the GraphQL Playground for the workspace at [console.tailor.tech](https://console.tailor.tech) and run:
29+
30+
```graphql
31+
# 1. Create the IDP user (authentication credentials)
32+
mutation CreateIdpUser {
33+
_createUser(input: { password: "TestPassword123!", name: "e2e-test@example.com" }) {
34+
id
35+
name
36+
}
37+
}
38+
39+
# 2. Create the TailorDB user profile (required for user lookup after auth)
40+
mutation CreateUserProfile {
41+
createUser(input: { email: "e2e-test@example.com", name: "E2E Test User", roles: [] }) {
42+
id
43+
}
44+
}
45+
```
46+
47+
### 3. Configure environment
48+
49+
```bash
50+
cp e2e/.env.example e2e/.env
51+
```
52+
53+
Fill in `VITE_TAILOR_APP_URL` and `VITE_TAILOR_CLIENT_ID` (retrieved above). The test user credentials are pre-filled.
54+
55+
### 4. Install dependencies & browsers
56+
57+
```bash
58+
pnpm install
59+
cd e2e && npx playwright install chromium
60+
```
61+
62+
## Running Tests
63+
64+
```bash
65+
# From monorepo root
66+
cd e2e && pnpm test
67+
68+
# With Playwright UI
69+
cd e2e && pnpm test:ui
70+
71+
# Dev server only (for debugging)
72+
cd e2e && pnpm dev
73+
```
74+
75+
## Test Scenarios
76+
77+
| Test | Description |
78+
| ------------------- | ---------------------------------------------------------------- |
79+
| Auth guard display | Verifies unauthenticated users see the login UI |
80+
| Login flow | Full OAuth redirect → IDP login → callback → authenticated state |
81+
| Logout | Verifies logout returns to auth guard |
82+
| Session persistence | Confirms page reload maintains authentication |
83+
84+
## Architecture
85+
86+
```
87+
e2e/
88+
├── app/ # Minimal Vite app with AuthProvider
89+
│ ├── src/App.tsx # Test app using AuthProvider + guardComponent
90+
│ └── vite.config.ts
91+
├── backend/ # Tailor Platform config for E2E workspace
92+
│ ├── tailor.config.ts
93+
│ └── src/tailordb/user.ts
94+
├── tests/
95+
│ └── auth.spec.ts # Playwright test specs
96+
└── playwright.config.ts
97+
```

e2e/app/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>AppShell E2E Test</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

e2e/app/src/App.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { AuthProvider, createAuthClient, useAuth } from "@tailor-platform/app-shell";
2+
3+
const authClient = createAuthClient({
4+
appUri: import.meta.env.VITE_TAILOR_APP_URL,
5+
clientId: import.meta.env.VITE_TAILOR_CLIENT_ID,
6+
});
7+
8+
const AuthGuard = () => {
9+
const { login } = useAuth();
10+
11+
return (
12+
<main data-testid="auth-guard">
13+
<h1>Sign in required</h1>
14+
<p>You need to sign in to access this app.</p>
15+
<button
16+
type="button"
17+
data-testid="login-button"
18+
onClick={() => {
19+
void login();
20+
}}
21+
>
22+
Sign in
23+
</button>
24+
</main>
25+
);
26+
};
27+
28+
const AuthenticatedContent = () => {
29+
const { logout, isAuthenticated } = useAuth();
30+
31+
return (
32+
<main data-testid="authenticated-content">
33+
<h1>Authenticated</h1>
34+
<p data-testid="auth-status">{isAuthenticated ? "Logged in" : "Not logged in"}</p>
35+
<button
36+
type="button"
37+
data-testid="logout-button"
38+
onClick={() => {
39+
void logout();
40+
}}
41+
>
42+
Log out
43+
</button>
44+
</main>
45+
);
46+
};
47+
48+
export const App = () => {
49+
return (
50+
<AuthProvider client={authClient} guardComponent={AuthGuard}>
51+
<AuthenticatedContent />
52+
</AuthProvider>
53+
);
54+
};

e2e/app/src/index.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@import "tailwindcss";
2+
@import "@tailor-platform/app-shell/styles";
3+
@import "@tailor-platform/app-shell/theme.css";

0 commit comments

Comments
 (0)