Skip to content

Commit 38577a9

Browse files
committed
fix toggle behavior and reorder replays table with play at beginning. Add missing messages script
1 parent 72bb63f commit 38577a9

File tree

7 files changed

+109
-24
lines changed

7 files changed

+109
-24
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"update-db": "prisma migrate deploy",
3434
"check-db": "node scripts/check-db.js",
3535
"check-env": "node scripts/check-env.js",
36+
"check-missing-messages": "node scripts/check-missing-messages.js",
3637
"copy-db-files": "node scripts/copy-db-files.js",
3738
"download-country-names": "node scripts/download-country-names.js",
3839
"download-language-names": "node scripts/download-language-names.js",

public/intl/messages/en-US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@
250250
"remaining": "Remaining",
251251
"remove": "Remove",
252252
"remove-member": "Remove member",
253+
"play": "Play",
253254
"replay": "Replay",
254255
"replay-id": "Replay ID",
255256
"replay-enabled": "Replay enabled",

scripts/check-missing-messages.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { readdirSync, readFileSync } from 'node:fs';
2+
import { dirname, join } from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const __filename = fileURLToPath(import.meta.url);
6+
const __dirname = dirname(__filename);
7+
const messagesDir = join(__dirname, '..', 'public', 'intl', 'messages');
8+
9+
const en = JSON.parse(readFileSync(join(messagesDir, 'en-US.json'), 'utf8'));
10+
11+
// Flatten nested structure: { label: { foo: 'bar' } } -> { 'label.foo': 'bar' }
12+
function flatten(obj, prefix = '') {
13+
const result = {};
14+
for (const [k, v] of Object.entries(obj)) {
15+
const key = prefix ? `${prefix}.${k}` : k;
16+
if (typeof v === 'object' && v !== null) {
17+
Object.assign(result, flatten(v, key));
18+
} else {
19+
result[key] = v;
20+
}
21+
}
22+
return result;
23+
}
24+
25+
const enFlat = flatten(en);
26+
const enKeys = Object.keys(enFlat);
27+
console.log(`en-US.json has ${enKeys.length} keys`);
28+
29+
const files = readdirSync(messagesDir)
30+
.filter(f => f.endsWith('.json') && f !== 'en-US.json')
31+
.sort();
32+
33+
const allMissing = {};
34+
let total = 0;
35+
36+
for (const fname of files) {
37+
const data = JSON.parse(readFileSync(join(messagesDir, fname), 'utf8'));
38+
const flat = flatten(data);
39+
const missing = enKeys.filter(k => !(k in flat));
40+
if (missing.length) {
41+
allMissing[fname] = missing;
42+
console.log(`${fname}: ${missing.length} missing`);
43+
total += missing.length;
44+
}
45+
}
46+
console.log(`\nTotal missing across all locales: ${total}`);
47+
48+
const keyCounts = {};
49+
for (const missing of Object.values(allMissing)) {
50+
for (const k of missing) {
51+
keyCounts[k] = (keyCounts[k] || 0) + 1;
52+
}
53+
}
54+
const sorted = Object.entries(keyCounts).sort((a, b) => b[1] - a[1]);
55+
if (sorted.length) {
56+
console.log('\nMost commonly missing keys:');
57+
for (const [k, count] of sorted) {
58+
console.log(` "${k}": missing from ${count} files (en value: "${enFlat[k]}")`);
59+
}
60+
}

src/app/(main)/websites/[websiteId]/replays/ReplaysTable.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ export function ReplaysTable({ ...props }: DataTableProps) {
2020

2121
return (
2222
<DataTable {...props}>
23+
<DataColumn id="play" label="" width="80px">
24+
{(row: any) => (
25+
<Button variant="quiet" onClick={() => router.push(updateParams({ replay: row.id }))}>
26+
<Icon>
27+
<Play />
28+
</Icon>
29+
</Button>
30+
)}
31+
</DataColumn>
2332
<DataColumn id="id" label={t(labels.session)} width="100px">
2433
{(row: any) => (
2534
<Link href={updateParams({ session: row.sessionId })}>
@@ -63,15 +72,6 @@ export function ReplaysTable({ ...props }: DataTableProps) {
6372
<DataColumn id="createdAt" label={t(labels.recordedAt)} width="140px">
6473
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
6574
</DataColumn>
66-
<DataColumn id="play" label="" width="80px">
67-
{(row: any) => (
68-
<Button variant="quiet" onClick={() => router.push(updateParams({ replay: row.id }))}>
69-
<Icon>
70-
<Play />
71-
</Icon>
72-
</Button>
73-
)}
74-
</DataColumn>
7575
</DataTable>
7676
);
7777
}

src/app/(main)/websites/[websiteId]/sessions/SessionReplaysTable.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,6 @@ export function SessionReplaysTable({
1919

2020
return (
2121
<DataTable {...props}>
22-
<DataColumn id="id" label={t(labels.replayId)} />
23-
<DataColumn id="duration" label={t(labels.duration)} width="100px">
24-
{(row: any) => formatDuration(row.duration || 0)}
25-
</DataColumn>
26-
<DataColumn id="eventCount" label={t(labels.actions)} width="80px" />
27-
<DataColumn id="createdAt" label={t(labels.recordedAt)} width="140px">
28-
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
29-
</DataColumn>
3022
<DataColumn id="play" label="" width="80px">
3123
{(row: any) => (
3224
<Button
@@ -39,6 +31,14 @@ export function SessionReplaysTable({
3931
</Button>
4032
)}
4133
</DataColumn>
34+
<DataColumn id="id" label={t(labels.replayId)} />
35+
<DataColumn id="duration" label={t(labels.duration)} width="100px">
36+
{(row: any) => formatDuration(row.duration || 0)}
37+
</DataColumn>
38+
<DataColumn id="eventCount" label={t(labels.actions)} width="80px" />
39+
<DataColumn id="createdAt" label={t(labels.recordedAt)} width="140px">
40+
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
41+
</DataColumn>
4242
</DataTable>
4343
);
4444
}

src/app/(main)/websites/[websiteId]/settings/WebsiteReplaySettings.tsx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,28 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
3232
const [maxDuration, setMaxDuration] = useState(String(config.maxDuration ?? 300000));
3333
const [blockSelector, setBlockSelector] = useState(config.blockSelector ?? '');
3434

35+
const handleToggle = async (value: boolean) => {
36+
const previous = enabled;
37+
setEnabled(value);
38+
39+
try {
40+
await mutateAsync(
41+
{
42+
replayEnabled: value,
43+
},
44+
{
45+
onSuccess: async () => {
46+
toast(t(messages.saved));
47+
touch('websites');
48+
touch(`website:${websiteId}`);
49+
},
50+
},
51+
);
52+
} catch {
53+
setEnabled(previous);
54+
}
55+
};
56+
3557
const handleSave = async () => {
3658
await mutateAsync(
3759
{
@@ -47,7 +69,7 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
4769
onSuccess: async () => {
4870
toast(t(messages.saved));
4971
touch('websites');
50-
touch(`website:${website.id}`);
72+
touch(`website:${websiteId}`);
5173
},
5274
},
5375
);
@@ -56,7 +78,7 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
5678
return (
5779
<Column gap="4">
5880
<Label>{t(labels.replays)}</Label>
59-
<Switch isSelected={enabled} onChange={setEnabled}>
81+
<Switch isSelected={enabled} onChange={handleToggle} isDisabled={isPending}>
6082
{t(labels.replayEnabled)}
6183
</Switch>
6284
{enabled && (
@@ -92,13 +114,13 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
92114
<Label>{t(labels.blockSelector)}</Label>
93115
<TextField value={blockSelector} onChange={setBlockSelector} />
94116
</Column>
117+
<Row>
118+
<Button variant="primary" onPress={handleSave} isDisabled={isPending}>
119+
{t(labels.save)}
120+
</Button>
121+
</Row>
95122
</>
96123
)}
97-
<Row>
98-
<Button variant="primary" onPress={handleSave} isDisabled={isPending}>
99-
{t(labels.save)}
100-
</Button>
101-
</Row>
102124
</Column>
103125
);
104126
}

src/components/messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ export const labels: Record<string, string> = {
358358
needsImprovement: 'label.needs-improvement',
359359
poor: 'label.poor',
360360
sampleSize: 'label.sample-size',
361+
play: 'label.play',
361362
replays: 'label.replays',
362363
replay: 'label.replay',
363364
replayId: 'label.replay-id',

0 commit comments

Comments
 (0)