@@ -13,6 +13,7 @@ | |||
"@radix-ui/react-switch": "^1.2.5", | |||
"@radix-ui/react-toast": "^1.2.14", | |||
"axios": "^1.9.0", | |||
"camelcase-keys": "^9.1.3", | |||
"class-variance-authority": "^0.7.1", | |||
"clsx": "^2.1.1", | |||
"humps": "^2.0.1", | |||
@@ -2591,6 +2592,18 @@ | |||
"node": ">=6" | |||
} | |||
}, | |||
"node_modules/camelcase": { | |||
"version": "8.0.0", | |||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", | |||
"integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", | |||
"license": "MIT", | |||
"engines": { | |||
"node": ">=16" | |||
}, | |||
"funding": { | |||
"url": "https://github.com/sponsors/sindresorhus" | |||
} | |||
}, | |||
"node_modules/camelcase-css": { | |||
"version": "2.0.1", | |||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", | |||
@@ -2601,6 +2614,24 @@ | |||
"node": ">= 6" | |||
} | |||
}, | |||
"node_modules/camelcase-keys": { | |||
"version": "9.1.3", | |||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-9.1.3.tgz", | |||
"integrity": "sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg==", | |||
"license": "MIT", | |||
"dependencies": { | |||
"camelcase": "^8.0.0", | |||
"map-obj": "5.0.0", | |||
"quick-lru": "^6.1.1", | |||
"type-fest": "^4.3.2" | |||
}, | |||
"engines": { | |||
"node": ">=16" | |||
}, | |||
"funding": { | |||
"url": "https://github.com/sponsors/sindresorhus" | |||
} | |||
}, | |||
"node_modules/caniuse-lite": { | |||
"version": "1.0.30001718", | |||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", | |||
@@ -4151,6 +4182,18 @@ | |||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" | |||
} | |||
}, | |||
"node_modules/map-obj": { | |||
"version": "5.0.0", | |||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", | |||
"integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==", | |||
"license": "MIT", | |||
"engines": { | |||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0" | |||
}, | |||
"funding": { | |||
"url": "https://github.com/sponsors/sindresorhus" | |||
} | |||
}, | |||
"node_modules/markdown-it": { | |||
"version": "14.1.0", | |||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", | |||
@@ -5362,6 +5405,18 @@ | |||
], | |||
"license": "MIT" | |||
}, | |||
"node_modules/quick-lru": { | |||
"version": "6.1.2", | |||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", | |||
"integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", | |||
"license": "MIT", | |||
"engines": { | |||
"node": ">=12" | |||
}, | |||
"funding": { | |||
"url": "https://github.com/sponsors/sindresorhus" | |||
} | |||
}, | |||
"node_modules/react": { | |||
"version": "19.1.0", | |||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", | |||
@@ -6192,6 +6247,18 @@ | |||
"node": ">= 0.8.0" | |||
} | |||
}, | |||
"node_modules/type-fest": { | |||
"version": "4.41.0", | |||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", | |||
"integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", | |||
"license": "(MIT OR CC0-1.0)", | |||
"engines": { | |||
"node": ">=16" | |||
}, | |||
"funding": { | |||
"url": "https://github.com/sponsors/sindresorhus" | |||
} | |||
}, | |||
"node_modules/typescript": { | |||
"version": "5.8.3", | |||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", | |||
@@ -14,6 +14,7 @@ | |||
"@radix-ui/react-switch": "^1.2.5", | |||
"@radix-ui/react-toast": "^1.2.14", | |||
"axios": "^1.9.0", | |||
"camelcase-keys": "^9.1.3", | |||
"class-variance-authority": "^0.7.1", | |||
"clsx": "^2.1.1", | |||
"humps": "^2.0.1", | |||
@@ -1,13 +1,18 @@ | |||
import axios from 'axios' | |||
import toCamel from 'camelcase-keys' | |||
import React, { useEffect, useState } from 'react' | |||
import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription } from './ui/dialog' | |||
import { Switch } from './ui/switch' | |||
import { Button } from './ui/button' | |||
import { Link, useNavigate, useLocation } from 'react-router-dom' | |||
import { Button } from '@/components/ui/button' | |||
import { Dialog, | |||
DialogContent, | |||
DialogDescription, | |||
DialogTitle, | |||
DialogTrigger } from '@/components/ui/dialog' | |||
import { Input } from '@/components/ui/input' | |||
import { Switch } from '@/components/ui/switch' | |||
import { toast } from '@/components/ui/use-toast' | |||
import axios from 'axios' | |||
import { Link, useNavigate, useLocation } from 'react-router-dom' | |||
import { API_BASE_URL } from '@/config' | |||
import { camelizeKeys } from 'humps' | |||
import type { Tag, User } from '@/types' | |||
@@ -17,7 +22,10 @@ type Props = { visible: boolean | |||
setUser: (user: User) => void } | |||
const SettingsDialogue: React.FC = ({ visible, onVisibleChange, user, setUser }: Props) => { | |||
const SettingsDialogue: React.FC = ({ visible, | |||
onVisibleChange, | |||
user, | |||
setUser }: Props) => { | |||
const [inputCode, setInputCode] = useState ('') | |||
const handleShowCode = () => { | |||
@@ -35,7 +43,7 @@ const SettingsDialogue: React.FC = ({ visible, onVisibleChange, user, setUser }: | |||
if (res.data.valid) | |||
{ | |||
localStorage.setItem ('user_code', inputCode) | |||
setUser (camelizeKeys (res.data.user)) | |||
setUser (toCamel (res.data.user, { deep: true })) | |||
toast ({ title: '引継ぎ成功!' }) | |||
} | |||
else | |||
@@ -1,4 +1,5 @@ | |||
import axios from 'axios' | |||
import toCamel from 'camelcase-keys' | |||
import { useEffect, useState } from 'react' | |||
import { Helmet } from 'react-helmet' | |||
import ReactMarkdown from 'react-markdown' | |||
@@ -33,7 +34,7 @@ export default () => { | |||
void (axios.get (`${ API_BASE_URL }/wiki/title/${ encodeURIComponent (title) }`, version && { params: { version } }) | |||
.then (res => { | |||
setWikiPage (res.data) | |||
setWikiPage (toCamel (res.data, { deep: true })) | |||
WikiIdBus.set (res.data.id) | |||
}) | |||
.catch (() => setWikiPage (null))) | |||
@@ -51,7 +52,7 @@ export default () => { | |||
< 古 | |||
</Link>) : <>(最古)</>} | |||
<span>{wikiPage.updated_at}</span> | |||
<span>{wikiPage.updatedAt}</span> | |||
{wikiPage.succ ? ( | |||
<Link to={`/wiki/${ title }?version=${ wikiPage.succ }`}> | |||
@@ -1,4 +1,5 @@ | |||
import axios from 'axios' | |||
import toCamel from 'camelcase-keys' | |||
import { useEffect, useState } from 'react' | |||
import { Helmet } from 'react-helmet' | |||
import { Link, useLocation, useParams } from 'react-router-dom' | |||
@@ -23,7 +24,7 @@ export default () => { | |||
useEffect (() => { | |||
void (axios.get (`${ API_BASE_URL }/wiki/${ id }/diff`, { params: { from, to } }) | |||
.then (res => setDiff (res.data))) | |||
.then (res => setDiff (toCamel (res.data, { deep: true })))) | |||
}, []) | |||
return ( | |||
@@ -1,4 +1,5 @@ | |||
import axios from 'axios' | |||
import toCamel from 'camelcase-keys' | |||
import { useEffect, useState } from 'react' | |||
import { Helmet } from 'react-helmet' | |||
import { Link, useLocation, useParams } from 'react-router-dom' | |||
@@ -18,7 +19,7 @@ export default () => { | |||
useEffect (() => { | |||
void (axios.get (`${ API_BASE_URL }/wiki/changes`, id && { params: { id } }) | |||
.then (res => setChanges (res.data))) | |||
.then (res => setChanges (toCamel (res.data, { deep: true })))) | |||
}, [location.search]) | |||
return ( | |||
@@ -39,19 +40,19 @@ export default () => { | |||
{changes.map (change => ( | |||
<tr key={change.sha}> | |||
<td> | |||
{change.change_type === 'update' && ( | |||
<Link to={`/wiki/${ change.wiki_page.id }/diff?from=${ change.pred }&to=${ change.sha }`}> | |||
{change.changeType === 'update' && ( | |||
<Link to={`/wiki/${ change.wikiPage.id }/diff?from=${ change.pred }&to=${ change.sha }`}> | |||
差分 | |||
</Link>)} | |||
</td> | |||
<td className="p-2"> | |||
<Link to={`/wiki/${ encodeURIComponent (change.wiki_page.title) }?version=${ change.sha }`}> | |||
{change.wiki_page.title} | |||
<Link to={`/wiki/${ encodeURIComponent (change.wikiPage.title) }?version=${ change.sha }`}> | |||
{change.wikiPage.title} | |||
</Link> | |||
</td> | |||
<td className="p-2"> | |||
{(() => { | |||
switch (change.change_type) | |||
switch (change.changeType) | |||
{ | |||
case 'create': | |||
return '新規' | |||
@@ -23,28 +23,28 @@ export type User = { | |||
role: UserRole } | |||
export type WikiPage = { | |||
id: number | |||
title: string | |||
sha: string | |||
pred?: string | |||
succ?: string | |||
updated_at?: string } | |||
id: number | |||
title: string | |||
sha: string | |||
pred?: string | |||
succ?: string | |||
updatedAt?: string } | |||
export type WikiPageChange = { | |||
sha: string | |||
pred?: string | |||
succ?: string | |||
wiki_page: WikiPage | |||
user: User | |||
change_type: string | |||
timestamp: string } | |||
sha: string | |||
pred?: string | |||
succ?: string | |||
wikiPage: WikiPage | |||
user: User | |||
changeType: string | |||
timestamp: string } | |||
export type WikiPageDiff = { | |||
wiki_page_id: number | |||
title: string | |||
older_sha: string | |||
newer_sha: string | |||
diff: WikiPageDiffDiff[] } | |||
wikiPageId: number | |||
title: string | |||
olderSha: string | |||
newerSha: string | |||
diff: WikiPageDiffDiff[] } | |||
export type WikiPageDiffDiff = { | |||
type: 'context' | 'added' | 'removed' | |||