Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
943d2e8
refactor(dashboard): unify icons on Lucide, drop Material Symbols font
Abdulkhalek-1 Jul 7, 2026
6a8495e
fix(dashboard): resolve UI/UX review findings (a11y, dead controls, l…
Abdulkhalek-1 Jul 7, 2026
57caaad
chore(i18n): remove unused header/sidebar keys from all locales
Abdulkhalek-1 Jul 7, 2026
74fc2ae
perf(dashboard): code-split route pages and vendor chunks
Abdulkhalek-1 Jul 7, 2026
907a04c
fix(dashboard): a11y in shared Discord selects; add volume icon
Abdulkhalek-1 Jul 7, 2026
fd1b7d8
fix(automation): editor accessibility + remove dead code
Abdulkhalek-1 Jul 7, 2026
3d2a58a
fix(dashboard): accessibility & UX sweep across feature pages
Abdulkhalek-1 Jul 7, 2026
2d4950c
fix(dashboard): harden design tokens (Discord contrast, type scale, m…
Abdulkhalek-1 Jul 7, 2026
5f9a2d5
fix(docker): mount pgdata at postgres root for Postgres 18
Abdulkhalek-1 Jul 7, 2026
919dce1
chore(deps): sync lockfile for @playwright/test and @radix-ui/react-d…
Abdulkhalek-1 Jul 7, 2026
672e354
feat(i18n): complete dashboard i18n coverage across 48 locales
Abdulkhalek-1 Jul 7, 2026
cdf6a16
fix(dashboard): language switcher scrolling, RTL, and hover
Abdulkhalek-1 Jul 7, 2026
93945ca
fix(dashboard): RTL mirroring, icon-fill corruption & clipped focus r…
Abdulkhalek-1 Jul 7, 2026
0f775ab
feat(dashboard): enable component animations via tw-animate-css
Abdulkhalek-1 Jul 7, 2026
c11021d
fix(automation): pin node detail panel to physical right in RTL
Abdulkhalek-1 Jul 7, 2026
87d7717
fix(automation): force workflow canvas to LTR so nodes render in RTL
Abdulkhalek-1 Jul 7, 2026
4cf6296
fix(dashboard): stop Radix ScrollArea content overflowing horizontally
Abdulkhalek-1 Jul 7, 2026
b8661f6
docs(dashboard): add variable text fields design spec
Abdulkhalek-1 Jul 7, 2026
d4d5c78
fix(dashboard): authorize guild admin against live Discord state
Abdulkhalek-1 Jul 8, 2026
541e3e6
feat(dashboard): add servers refresh button and owner-aware guild list
Abdulkhalek-1 Jul 8, 2026
68b66c4
chore(hooks): make test-reminder CWD-independent and convention-aware
Abdulkhalek-1 Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 15 additions & 1 deletion .claude/hooks/test-reminder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ if ! echo "$LAST_MESSAGE" | grep -qiE '(created|wrote|added|implemented|built|up
exit 0
fi

# git returns repo-root-relative paths, but this hook may run from any CWD, so
# resolve file existence against the repo root rather than the current dir.
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")

# Find source files modified in the working tree (staged + unstaged)
CHANGED_SRC_FILES=$(git diff --name-only HEAD 2>/dev/null || git diff --name-only --cached 2>/dev/null || echo "")

Expand Down Expand Up @@ -56,7 +60,17 @@ while IFS= read -r file; do
continue
fi

if [ -n "$TEST_FILE" ] && [ ! -f "$TEST_FILE" ]; then
if [ -n "$TEST_FILE" ] && [ ! -f "$REPO_ROOT/$TEST_FILE" ]; then
# This repo consolidates a feature's tests into <feature>.test.ts within the
# mirrored test directory (e.g. features/guilds/routes.ts is covered by
# tests/server/features/guilds/guilds.test.ts). Accept that convention —
# a <parentDirName>.test.ts alongside the expected path — but nothing broader,
# so genuinely untested files elsewhere are still flagged.
TEST_DIR=$(dirname "$TEST_FILE")
PARENT_DIR=$(basename "$(dirname "$file")")
if [ -f "$REPO_ROOT/$TEST_DIR/$PARENT_DIR.test.ts" ]; then
continue
fi
MISSING_TESTS="${MISSING_TESTS}\n - ${file} → missing ${TEST_FILE}"
fi
done <<< "$ALL_FILES"
Expand Down
1 change: 1 addition & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"recharts": "^3.8.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"zod": "^3.25.17"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useTranslation } from "react-i18next";
import { Icon } from "../../../shared/components/Icon";
import { Label } from "../../../shared/ui/label";
import { Input } from "../../../shared/ui/input";
import { Textarea } from "../../../shared/ui/textarea";
Expand Down Expand Up @@ -41,28 +42,45 @@ export function ActionFields({
<div className="flex flex-col gap-3">
{fields.map((field) => {
const value = getNestedValue(values, field.key) ?? "";
const fieldId = `af-${field.key.replace(/\./g, "-")}`;
const colorHex =
typeof value === "number"
? `#${value.toString(16).padStart(6, "0")}`
: String(value) || "#5865f2";

return (
<div key={field.key}>
<Label>
<Label htmlFor={fieldId}>
{field.label}
{field.required && <span className="text-danger"> *</span>}
{field.required && (
<>
<span aria-hidden="true" className="text-danger"> *</span>
<span className="sr-only"> ({t("labels.required")})</span>
</>
)}
</Label>

{field.type === "channel" && (
<Select
value={String(value) || undefined}
onValueChange={(v) => onChange(field.key, v)}
>
<SelectTrigger>
<SelectTrigger id={fieldId} aria-required={field.required}>
<SelectValue placeholder={t("form.selectChannel")} />
</SelectTrigger>
<SelectContent>
{channels
.filter((c) => c.type === 0 || c.type === 2)
.map((c) => (
<SelectItem key={c.id} value={c.id}>
{c.type === 2 ? `🔊 ${c.name}` : `# ${c.name}`}
<span className="flex items-center gap-1.5">
<Icon
name={c.type === 2 ? "volume_up" : "hash"}
size={14}
className="text-text-muted"
/>
{c.name}
</span>
</SelectItem>
))}
</SelectContent>
Expand All @@ -74,7 +92,7 @@ export function ActionFields({
value={String(value) || undefined}
onValueChange={(v) => onChange(field.key, v)}
>
<SelectTrigger>
<SelectTrigger id={fieldId} aria-required={field.required}>
<SelectValue placeholder={t("form.selectRole")} />
</SelectTrigger>
<SelectContent>
Expand All @@ -89,7 +107,9 @@ export function ActionFields({

{field.type === "text" && (
<Input
id={fieldId}
type="text"
aria-required={field.required}
value={String(value)}
onChange={(e) => onChange(field.key, e.target.value)}
placeholder={field.placeholder}
Expand All @@ -99,6 +119,8 @@ export function ActionFields({

{field.type === "textarea" && (
<Textarea
id={fieldId}
aria-required={field.required}
value={String(value)}
onChange={(e) => onChange(field.key, e.target.value)}
placeholder={field.placeholder}
Expand All @@ -107,26 +129,27 @@ export function ActionFields({
)}

{field.type === "color" && (
<input
type="color"
className="h-9 w-full cursor-pointer rounded-sm bg-surface-lowest p-1"
value={
typeof value === "number"
? `#${value.toString(16).padStart(6, "0")}`
: String(value) || "#5865f2"
}
onChange={(e) =>
onChange(field.key, parseInt(e.target.value.slice(1), 16))
}
/>
<div className="flex items-center gap-2">
<input
id={fieldId}
type="color"
aria-label={field.label}
className="h-9 w-14 shrink-0 cursor-pointer rounded-sm bg-surface-lowest p-1"
value={colorHex}
onChange={(e) =>
onChange(field.key, parseInt(e.target.value.slice(1), 16))
}
/>
<span className="font-mono text-xs text-text-muted">{colorHex}</span>
</div>
)}

{field.type === "select" && field.options && (
<Select
value={String(value) || undefined}
onValueChange={(v) => onChange(field.key, v)}
>
<SelectTrigger>
<SelectTrigger id={fieldId} aria-required={field.required}>
<SelectValue placeholder={t("form.select")} />
</SelectTrigger>
<SelectContent>
Expand Down
173 changes: 0 additions & 173 deletions apps/dashboard/src/client/features/automation/components/ActionRow.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function ChipList({
onRemove: (id: string) => void;
color?: "secondary" | "destructive";
}) {
const { t } = useTranslation("rules");
if (items.length === 0) return null;
return (
<div className="flex flex-wrap gap-1.5">
Expand All @@ -38,7 +39,7 @@ function ChipList({
{item.label}
<button
type="button"
aria-label={`Remove ${item.label}`}
aria-label={t("conditions.removeItem", { label: item.label })}
onClick={() => onRemove(item.id)}
className="ms-0.5 rounded-full p-0.5 hover:bg-white/10"
>
Expand Down
Loading