Skip to content

Commit ab9b8da

Browse files
committed
Fix minor UI issues
1 parent 8527242 commit ab9b8da

File tree

5 files changed

+70
-14
lines changed

5 files changed

+70
-14
lines changed

site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const useStyles = makeStyles((theme) => ({
8787
color: theme.palette.text.primary,
8888
},
8989

90-
"& p": {
90+
"& p:not(.MuiFormHelperText-root)": {
9191
margin: 0,
9292
},
9393

site/src/components/TemplateVersionEditor/FileDialog.tsx

+24-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import { Stack } from "components/Stack/Stack"
44
import { ChangeEvent, FC, useState } from "react"
55
import Typography from "@material-ui/core/Typography"
66
import { allowedExtensions, isAllowedFile } from "util/templateVersion"
7+
import { FileTree, validatePath } from "util/filetree"
78

89
export const CreateFileDialog: FC<{
910
onClose: () => void
1011
checkExists: (path: string) => boolean
1112
onConfirm: (path: string) => void
1213
open: boolean
13-
}> = ({ checkExists, onClose, onConfirm, open }) => {
14+
fileTree: FileTree
15+
}> = ({ checkExists, onClose, onConfirm, open, fileTree }) => {
1416
const [pathValue, setPathValue] = useState("")
15-
const [error, setError] = useState("")
17+
const [error, setError] = useState<string>()
1618
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
1719
setPathValue(event.target.value)
1820
}
@@ -32,7 +34,13 @@ export const CreateFileDialog: FC<{
3234
)
3335
return
3436
}
37+
const pathError = validatePath(pathValue, fileTree)
38+
if (pathError) {
39+
setError(pathError)
40+
return
41+
}
3542
onConfirm(pathValue)
43+
setError(undefined)
3644
setPathValue("")
3745
}
3846

@@ -41,6 +49,7 @@ export const CreateFileDialog: FC<{
4149
open={open}
4250
onClose={() => {
4351
onClose()
52+
setError(undefined)
4453
setPathValue("")
4554
}}
4655
onConfirm={handleConfirm}
@@ -62,6 +71,7 @@ export const CreateFileDialog: FC<{
6271
handleConfirm()
6372
}
6473
}}
74+
error={Boolean(error)}
6575
helperText={error}
6676
name="file-path"
6777
autoComplete="off"
@@ -109,9 +119,10 @@ export const RenameFileDialog: FC<{
109119
checkExists: (path: string) => boolean
110120
open: boolean
111121
filename: string
112-
}> = ({ checkExists, onClose, onConfirm, open, filename }) => {
122+
fileTree: FileTree
123+
}> = ({ checkExists, onClose, onConfirm, open, filename, fileTree }) => {
113124
const [pathValue, setPathValue] = useState(filename)
114-
const [error, setError] = useState("")
125+
const [error, setError] = useState<string>()
115126
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
116127
setPathValue(event.target.value)
117128
}
@@ -127,11 +138,17 @@ export const RenameFileDialog: FC<{
127138
if (!isAllowedFile(pathValue)) {
128139
const extensions = allowedExtensions.join(", ")
129140
setError(
130-
`This extension is not allowed. You only can create files with the following extensions: ${extensions}.`,
141+
`This extension is not allowed. You only can rename files with the following extensions: ${extensions}.`,
131142
)
132143
return
133144
}
145+
const pathError = validatePath(pathValue, fileTree)
146+
if (pathError) {
147+
setError(pathError)
148+
return
149+
}
134150
onConfirm(pathValue)
151+
setError(undefined)
135152
setPathValue("")
136153
}
137154

@@ -140,6 +157,7 @@ export const RenameFileDialog: FC<{
140157
open={open}
141158
onClose={() => {
142159
onClose()
160+
setError(undefined)
143161
setPathValue("")
144162
}}
145163
onConfirm={handleConfirm}
@@ -161,6 +179,7 @@ export const RenameFileDialog: FC<{
161179
handleConfirm()
162180
}
163181
}}
182+
error={Boolean(error)}
164183
helperText={error}
165184
name="file-path"
166185
autoComplete="off"

site/src/components/TemplateVersionEditor/TemplateVersionEditor.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ import { WorkspaceBuildLogs } from "components/WorkspaceBuildLogs/WorkspaceBuild
1818
import { FC, useCallback, useEffect, useRef, useState } from "react"
1919
import { navHeight, dashboardContentBottomPadding } from "theme/constants"
2020
import {
21+
createFile,
2122
existsFile,
2223
FileTree,
2324
getFileContent,
2425
isFolder,
2526
moveFile,
2627
removeFile,
27-
setFile,
2828
traverse,
29+
updateFile,
2930
} from "util/filetree"
3031
import {
3132
CreateFileDialog,
@@ -217,13 +218,14 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
217218
</Tooltip>
218219
</div>
219220
<CreateFileDialog
221+
fileTree={fileTree}
220222
open={createFileOpen}
221223
onClose={() => {
222224
setCreateFileOpen(false)
223225
}}
224226
checkExists={(path) => existsFile(path, fileTree)}
225227
onConfirm={(path) => {
226-
setFileTree((fileTree) => setFile(path, "", fileTree))
228+
setFileTree((fileTree) => createFile(path, fileTree, ""))
227229
setActivePath(path)
228230
setCreateFileOpen(false)
229231
setDirty(true)
@@ -246,6 +248,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
246248
filename={deleteFileOpen || ""}
247249
/>
248250
<RenameFileDialog
251+
fileTree={fileTree}
249252
open={Boolean(renameFileOpen)}
250253
onClose={() => {
251254
setRenameFileOpen(undefined)
@@ -289,7 +292,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
289292
return
290293
}
291294
setFileTree((fileTree) =>
292-
setFile(activePath, value, fileTree),
295+
updateFile(activePath, value, fileTree),
293296
)
294297
setDirty(true)
295298
}}

site/src/util/filetree.ts

+36-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,38 @@ export type FileTree = {
77
[key: string]: FileTree | string
88
}
99

10-
export const setFile = (
10+
export const createFile = (
11+
path: string,
12+
fileTree: FileTree,
13+
value: string,
14+
): FileTree => {
15+
if (existsFile(path, fileTree)) {
16+
throw new Error(`File ${path} already exists`)
17+
}
18+
const pathError = validatePath(path, fileTree)
19+
if (pathError) {
20+
throw new Error(pathError)
21+
}
22+
23+
return set(fileTree, path.split("/"), value)
24+
}
25+
26+
export const validatePath = (
27+
path: string,
28+
fileTree: FileTree,
29+
): string | undefined => {
30+
const paths = path.split("/")
31+
paths.pop() // The last item is the filename
32+
for (let i = 0; i <= paths.length; i++) {
33+
const path = paths.slice(0, i + 1)
34+
const pathStr = path.join("/")
35+
if (existsFile(pathStr, fileTree) && !isFolder(pathStr, fileTree)) {
36+
return `Invalid path. The path ${path} is not a folder`
37+
}
38+
}
39+
}
40+
41+
export const updateFile = (
1142
path: string,
1243
content: FileTree | string,
1344
fileTree: FileTree,
@@ -31,8 +62,11 @@ export const moveFile = (
3162
fileTree: FileTree,
3263
) => {
3364
const content = getFileContent(currentPath, fileTree)
65+
if (typeof content !== "string") {
66+
throw new Error("Move folders is not allowed")
67+
}
3468
fileTree = removeFile(currentPath, fileTree)
35-
fileTree = setFile(newPath, content, fileTree)
69+
fileTree = createFile(newPath, fileTree, content)
3670
return fileTree
3771
}
3872

site/src/util/templateVersion.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as API from "api/api"
22
import { TemplateVersion } from "api/typesGenerated"
3-
import { FileTree, setFile } from "./filetree"
3+
import { FileTree, createFile } from "./filetree"
44
import { TarReader } from "./tar"
55

66
/**
@@ -35,10 +35,10 @@ export const createTemplateVersionFileTree = async (
3535
let fileTree: FileTree = {}
3636
for (const file of tarReader.fileInfo) {
3737
if (isAllowedFile(file.name)) {
38-
fileTree = setFile(
38+
fileTree = createFile(
3939
file.name,
40-
tarReader.getTextFile(file.name) as string,
4140
fileTree,
41+
tarReader.getTextFile(file.name) as string,
4242
)
4343
}
4444
}

0 commit comments

Comments
 (0)