0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-12 04:43:32 +02:00

actions: align artifact preview page layout with repo UI

This commit is contained in:
Nicolas 2026-03-31 20:45:29 +02:00
parent 979572f808
commit c361782af9
6 changed files with 101 additions and 105 deletions

View File

@ -6,7 +6,6 @@ package devtest
import (
"archive/zip"
"fmt"
"html/template"
"io"
mathRand "math/rand/v2"
"net/http"
@ -31,12 +30,13 @@ type mockArtifactFile struct {
}
type mockArtifactPreviewTemplateData struct {
ArtifactName string
Files []mockArtifactPreviewTemplateFile
PreviewURL string
PreviewRaw string
DownloadURL string
SelectedPath string
ArtifactName string
PreviewFiles []mockArtifactPreviewTemplateFile
RunURL string
PreviewURL string
PreviewRawURL string
DownloadURL string
SelectedPath string
}
type mockArtifactPreviewTemplateFile struct {
@ -69,40 +69,6 @@ var mockActionsArtifactFiles = map[string][]mockArtifactFile{
},
}
var mockArtifactPreviewTemplate = template.Must(template.New("mock-artifact-preview").Parse(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Artifact Preview</title>
<style>
body { font-family: sans-serif; margin: 16px; }
.layout { display: grid; grid-template-columns: 260px 1fr; gap: 16px; }
.files { border: 1px solid #ddd; border-radius: 6px; padding: 8px; }
.files a { display: block; padding: 8px; text-decoration: none; color: inherit; border-radius: 4px; }
.files a.selected { background: #f0f6ff; }
iframe { width: 100%; min-height: 70vh; border: 1px solid #ddd; border-radius: 6px; }
</style>
</head>
<body>
<h2>Preview: {{.ArtifactName}}</h2>
<p><a href="{{.PreviewURL}}">Reload</a> | <a href="{{.DownloadURL}}">Download ZIP</a></p>
<div class="layout">
<div class="files">
{{range .Files}}
<a class="{{if .Selected}}selected{{end}}" href="{{$.PreviewURL}}?path={{.Path | urlquery}}">{{.Path}}</a>
{{end}}
</div>
<div>
{{if .SelectedPath}}
<iframe src="{{.PreviewRaw}}/{{.SelectedPath | urlquery}}" sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe>
{{else}}
<p>No files</p>
{{end}}
</div>
</div>
</body>
</html>`))
func normalizeMockArtifactPath(path string) string {
path = util.PathJoinRelX(path)
if path == "." {
@ -387,19 +353,23 @@ func MockActionsArtifactPreview(ctx *context.Context) {
previewRawURL := previewURL + "/raw"
downloadURL := fmt.Sprintf("%s/devtest/repo-action-view/runs/%d/artifacts/%s", setting.AppSubURL, runID, url.PathEscape(artifactName))
data := mockArtifactPreviewTemplateData{
ArtifactName: artifactName,
Files: templateFiles,
PreviewURL: previewURL,
PreviewRaw: previewRawURL,
DownloadURL: downloadURL,
SelectedPath: selectedPath,
ArtifactName: artifactName,
PreviewFiles: templateFiles,
RunURL: previewURL,
PreviewURL: previewURL,
PreviewRawURL: previewRawURL,
DownloadURL: downloadURL,
SelectedPath: selectedPath,
}
ctx.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := mockArtifactPreviewTemplate.Execute(ctx.Resp, data); err != nil {
ctx.ServerError("mockArtifactPreviewTemplate.Execute", err)
return
}
ctx.Data["ArtifactName"] = data.ArtifactName
ctx.Data["PreviewFiles"] = data.PreviewFiles
ctx.Data["RunURL"] = data.RunURL
ctx.Data["PreviewURL"] = data.PreviewURL
ctx.Data["PreviewRawURL"] = data.PreviewRawURL
ctx.Data["DownloadURL"] = data.DownloadURL
ctx.Data["SelectedPath"] = data.SelectedPath
ctx.HTML(http.StatusOK, "devtest/repo-action-artifact-preview")
}
func MockActionsArtifactPreviewRaw(ctx *context.Context) {
@ -410,7 +380,11 @@ func MockActionsArtifactPreviewRaw(ctx *context.Context) {
return
}
selectedPath := chooseMockArtifactPath(files, normalizeMockArtifactPath(ctx.Req.URL.Query().Get("path")))
selectedPath := normalizeMockArtifactPath(strings.TrimPrefix(ctx.PathParam("*"), "/"))
if selectedPath == "" {
selectedPath = normalizeMockArtifactPath(ctx.Req.URL.Query().Get("path"))
}
selectedPath = chooseMockArtifactPath(files, selectedPath)
if selectedPath == "" {
ctx.NotFound(nil)
return
@ -442,5 +416,6 @@ func MockActionsArtifactPreviewRaw(ctx *context.Context) {
ctx.ServeContent(strings.NewReader(selectedFile.Content), context.ServeHeaderOptions{
Filename: selectedFile.Path,
ContentLength: &size,
ContentType: "text/plain; charset=utf-8",
})
}

View File

@ -905,7 +905,8 @@ func previewArtifactByReadSeeker(ctx *context_module.Context, path string, reade
return
}
ctx.ServeContent(reader, context_module.ServeHeaderOptions{
Filename: path,
Filename: path,
ContentType: st.GetMimeType(),
})
}

View File

@ -0,0 +1,28 @@
{{template "base/head" .}}
<div class="page-content repository actions">
<div class="ui fluid container artifact-preview-page">
{{template "shared/actions/artifact_preview_content" .}}
</div>
</div>
<style>
.artifact-preview-page {
margin-top: 1rem;
}
.artifact-preview-title {
min-width: 0;
}
.artifact-preview-subtitle {
color: var(--color-text-light-3);
}
.artifact-preview-frame {
width: 100%;
min-height: 70vh;
border: 1px solid var(--color-secondary);
border-radius: var(--border-radius);
}
</style>
{{template "base/footer" .}}

View File

@ -3,43 +3,9 @@
<div class="page-content repository actions">
{{template "repo/header" .}}
<div class="ui container artifact-preview-page">
<div class="artifact-preview-header">
<div class="artifact-preview-title">
<h2 class="ui header">{{ctx.Locale.Tr "preview"}}: <span class="gt-ellipsis">{{.ArtifactName}}</span></h2>
<div class="artifact-preview-subtitle">
<a href="{{.RunURL}}">{{ctx.Locale.Tr "go_back"}}</a>
</div>
</div>
<a class="ui button" href="{{.DownloadURL}}">
{{svg "octicon-download"}}
{{ctx.Locale.Tr "repo.download_file"}}
</a>
</div>
<div class="ui stackable grid">
<div class="four wide column">
<div class="ui fluid vertical menu">
<div class="item">
<b>{{ctx.Locale.Tr "files"}}</b>
</div>
{{range .PreviewFiles}}
<a class="item gt-ellipsis {{if .Selected}}active{{end}}" href="{{$.PreviewURL}}?path={{QueryEscape .Path}}" title="{{.Path}}">
{{.Path}}
</a>
{{else}}
<div class="item disabled">{{ctx.Locale.Tr "none"}}</div>
{{end}}
</div>
</div>
<div class="twelve wide column">
{{if .SelectedPath}}
<iframe class="artifact-preview-frame" src="{{.PreviewRawURL}}/{{PathEscapeSegments .SelectedPath}}" sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe>
{{else}}
<div class="ui attached segment">{{ctx.Locale.Tr "none"}}</div>
{{end}}
</div>
</div>
<div class="ui fluid container artifact-preview-page">
{{template "base/alert" .}}
{{template "shared/actions/artifact_preview_content" .}}
</div>
</div>
@ -48,22 +14,10 @@
margin-top: 1rem;
}
.artifact-preview-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1rem;
}
.artifact-preview-title {
min-width: 0;
}
.artifact-preview-title .ui.header {
margin-bottom: 0.25rem;
}
.artifact-preview-subtitle {
color: var(--color-text-light-3);
}

View File

@ -0,0 +1,38 @@
<div class="ui top attached header tw-flex tw-items-center tw-justify-between">
<div class="artifact-preview-title">
<span class="tw-text-base tw-font-semibold">{{ctx.Locale.Tr "preview"}}: <span class="gt-ellipsis">{{.ArtifactName}}</span></span>
<div class="artifact-preview-subtitle tw-mt-1">
<a href="{{.RunURL}}">{{ctx.Locale.Tr "go_back"}}</a>
</div>
</div>
<a class="ui button" href="{{.DownloadURL}}">
{{svg "octicon-download"}}
{{ctx.Locale.Tr "repo.download_file"}}
</a>
</div>
<div class="ui attached segment">
<div class="ui stackable grid">
<div class="four wide column">
<div class="ui fluid vertical menu">
<div class="item">
<b>{{ctx.Locale.Tr "files"}}</b>
</div>
{{range .PreviewFiles}}
<a class="item gt-ellipsis {{if .Selected}}active{{end}}" href="{{$.PreviewURL}}?path={{QueryEscape .Path}}" title="{{.Path}}">
{{.Path}}
</a>
{{else}}
<div class="item disabled">{{ctx.Locale.Tr "none"}}</div>
{{end}}
</div>
</div>
<div class="twelve wide column">
{{if .SelectedPath}}
<iframe class="artifact-preview-frame" src="{{.PreviewRawURL}}/{{PathEscapeSegments .SelectedPath}}" sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe>
{{else}}
<div class="ui attached segment">{{ctx.Locale.Tr "none"}}</div>
{{end}}
</div>
</div>
</div>

View File

@ -133,12 +133,12 @@ async function deleteArtifact(name: string) {
<template v-for="artifact in artifacts" :key="artifact.name">
<li class="job-artifacts-item">
<template v-if="artifact.status !== 'expired'">
<a class="flex-text-inline" target="_blank" :href="artifactPreviewURL(artifact.name)">
<a class="flex-text-inline" :href="artifactPreviewURL(artifact.name)">
<SvgIcon name="octicon-file" class="tw-text-text"/>
<span class="gt-ellipsis">{{ artifact.name }}</span>
</a>
<span class="job-artifact-actions">
<a download target="_blank" :href="artifactDownloadURL(artifact.name)" :data-tooltip-content="locale.downloadFile">
<a download :href="artifactDownloadURL(artifact.name)" :data-tooltip-content="locale.downloadFile">
<SvgIcon name="octicon-download" class="tw-text-text"/>
</a>
<a v-if="run.canDeleteArtifact" @click="deleteArtifact(artifact.name)">