feat(preview): add file preview page with metadata and styling
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m48s
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m48s
Implement a rich file preview interface to allow users to view file contents directly in the browser. Changes include: - Exposing raw file size (`SizeBytes`) in the download handler's file view. - Adding comprehensive CSS styling for the preview layout and cards. - Integrating Prism.js for syntax highlighting of code files. - Updating Content Security Policy (CSP) headers to permit inline styles and frame sources required by the preview components. - Adding unit tests to ensure preview metadata attributes are correctly rendered on the download page.
This commit is contained in:
@@ -40,6 +40,7 @@ type fileView struct {
|
||||
ID string
|
||||
Name string
|
||||
Size string
|
||||
SizeBytes int64
|
||||
ContentType string
|
||||
PreviewKind string
|
||||
URL string
|
||||
@@ -404,6 +405,7 @@ func (a *App) fileViewWithReactions(box services.Box, file services.File, reacti
|
||||
ID: file.ID,
|
||||
Name: file.Name,
|
||||
Size: helpers.FormatBytes(file.Size),
|
||||
SizeBytes: file.Size,
|
||||
ContentType: file.ContentType,
|
||||
PreviewKind: file.PreviewKind,
|
||||
URL: fmt.Sprintf("/d/%s/f/%s", box.ID, file.ID),
|
||||
|
||||
@@ -151,6 +151,34 @@ func TestSocialPreviewBotGetsRawFilePreview(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilePreviewPageIncludesPreviewMetadata(t *testing.T) {
|
||||
app, cleanup := newTestApp(t)
|
||||
defer cleanup()
|
||||
payload := uploadThroughApp(t, app)
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "/d/"+payload.BoxID+"/f/"+payload.Files[0].ID, nil)
|
||||
request.SetPathValue("boxID", payload.BoxID)
|
||||
request.SetPathValue("fileID", payload.Files[0].ID)
|
||||
response := httptest.NewRecorder()
|
||||
app.DownloadFile(response, request)
|
||||
|
||||
if response.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, body = %s", response.Code, response.Body.String())
|
||||
}
|
||||
body := response.Body.String()
|
||||
for _, want := range []string{
|
||||
`data-size-bytes="5"`,
|
||||
`data-source-url="/d/` + payload.BoxID,
|
||||
`data-download-url="/d/` + payload.BoxID,
|
||||
`data-icon-url="/static/file-icons/`,
|
||||
`data-preview-tabs`,
|
||||
} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Fatalf("preview page missing %q: %s", want, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResumableUploadFlowCreatesNormalBox(t *testing.T) {
|
||||
app, cleanup := newTestApp(t)
|
||||
defer cleanup()
|
||||
|
||||
@@ -9,7 +9,7 @@ func SecurityHeaders(next http.Handler) http.Handler {
|
||||
header.Set("X-Frame-Options", "DENY")
|
||||
header.Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
header.Set("Permissions-Policy", "camera=(), microphone=(), geolocation=()")
|
||||
header.Set("Content-Security-Policy", "default-src 'self'; img-src 'self' data: blob:; media-src 'self' blob:; font-src 'self'; style-src 'self'; script-src 'self'; base-uri 'self'; frame-ancestors 'none'")
|
||||
header.Set("Content-Security-Policy", "default-src 'self'; img-src 'self' data: blob:; media-src 'self' blob:; font-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; frame-src 'self' about:; base-uri 'self'; frame-ancestors 'none'")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user