FileEdit.tsx
Raw
1import { MAX_FILE_PATH_LENGTH } from "../../constants.ts";
2import type { RepositoryRow } from "../../db/index.ts";
3import type { SessionUser } from "../../middleware/session.ts";
4import { Layout } from "../layout.tsx";
5import { RepoHeader } from "../repos/RepoHeader.tsx";
6import { RepoNav } from "./RepoNav.tsx";
7
8interface FileEditProps {
9 user: SessionUser;
10 repo: RepositoryRow;
11 ref: string;
12 filePath: string;
13 content: string;
14 error?: string;
15 queryError?: string;
16}
17
18export function FileEdit({
19 user,
20 repo,
21 ref: editRef,
22 filePath,
23 content,
24 error,
25 queryError,
26}: FileEditProps) {
27 const parts = filePath.split("/");
28 const filename = parts[parts.length - 1] ?? filePath;
29 return (
30 <Layout user={user} title={`Edit ${repo.name}/${filePath}`}>
31 <div class="container">
32 <RepoHeader repo={repo} />
33 <RepoNav repo={repo} active="code" user={user} />
34 <div class="breadcrumb">
35 <a href={`/${repo.name}/tree/${editRef}`} safe>
36 {repo.name}
37 </a>
38 {parts.map((part, i) => {
39 const partPath = parts.slice(0, i + 1).join("/");
40 const isLast = i === parts.length - 1;
41 return (
42 <>
43 <span class="breadcrumb-sep">/</span>
44 {isLast ? (
45 <span class="breadcrumb-current" safe>
46 {part}
47 </span>
48 ) : (
49 <a
50 href={`/${repo.name}/tree/${editRef}/${partPath}`}
51 safe
52 >
53 {part}
54 </a>
55 )}
56 </>
57 );
58 })}
59 </div>
60 <p class="form-hint">
61 WARNING: Line endings are normalized to LF (\n) on save.
62 </p>
63 {(!!error || !!queryError) && (
64 <p class="form-error" safe>
65 {error ?? queryError}
66 </p>
67 )}
68 <form
69 method="POST"
70 action={`/${repo.name}/edit/${editRef}/${filePath}`}
71 >
72 <div class="file-blob-header">
73 <span class="file-blob-name" safe>
74 {filename}
75 </span>
76 <div class="file-blob-actions">
77 <a
78 href={`/${repo.name}/blob/${editRef}/${filePath}`}
79 class="btn btn-sm"
80 >
81 Cancel
82 </a>
83 </div>
84 </div>
85 <div class="file-blob-body">
86 <textarea
87 name="content"
88 class="file-edit-textarea"
89 rows="30"
90 spellcheck="false"
91 autocorrect="off"
92 autocapitalize="off"
93 {...{ autocomplete: "off" }}
94 safe
95 >
96 {content}
97 </textarea>
98 </div>
99 <div class="form-card">
100 <p
101 class="form-hint"
102 style="margin-bottom: var(--space-4);"
103 >
104 Committing directly to{" "}
105 <strong safe>{editRef}</strong>
106 </p>
107 <div class="form-group">
108 <label for="file-path">File path</label>
109 <input
110 id="file-path"
111 name="new_path"
112 type="text"
113 value={filePath}
114 class="mono"
115 maxlength={MAX_FILE_PATH_LENGTH}
116 />
117 </div>
118 <div class="form-group">
119 <label for="message">Commit message</label>
120 <textarea
121 id="message"
122 name="message"
123 rows="3"
124 required
125 safe
126 >
127 {`Edited ${filename}`}
128 </textarea>
129 </div>
130 <div class="form-actions">
131 <button type="submit" class="btn btn-primary">
132 Commit changes
133 </button>
134 <a
135 href={`/${repo.name}/blob/${editRef}/${filePath}`}
136 class="btn"
137 >
138 Cancel
139 </a>
140 </div>
141 </div>
142 </form>
143 </div>
144 </Layout>
145 );
146}
147