Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion models/actions/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ type ActionArtifactMeta struct {
ArtifactName string
FileSize int64
Status ArtifactStatus
ExpiredUnix timeutil.TimeStamp
}

// ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run
Expand All @@ -191,7 +192,7 @@ func ListUploadedArtifactsMeta(ctx context.Context, repoID, runID int64) ([]*Act
return arts, db.GetEngine(ctx).Table("action_artifact").
Where("repo_id=? AND run_id=? AND (status=? OR status=?)", repoID, runID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired).
GroupBy("artifact_name").
Select("artifact_name, sum(file_size) as file_size, max(status) as status").
Select("artifact_name, sum(file_size) as file_size, max(status) as status, max(expired_unix) as expired_unix").
Find(&arts)
}

Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
"unpin": "Unpin",
"artifacts": "Artifacts",
"expired": "Expired",
"artifact_expires_at": "Expires at %s",
"confirm_delete_artifact": "Are you sure you want to delete the artifact '%s'?",
"archived": "Archived",
"concept_system_global": "Global",
Expand Down
28 changes: 16 additions & 12 deletions routers/web/devtest/mock_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,28 @@ func MockActionsRunsJobs(ctx *context.Context) {
},
}
resp.Artifacts = append(resp.Artifacts, &actions.ArtifactsViewItem{
Name: "artifact-a",
Size: 100 * 1024,
Status: "expired",
Name: "artifact-a",
Size: 100 * 1024,
Status: "expired",
ExpiresUnix: time.Now().Add(-24 * time.Hour).Unix(),
})
resp.Artifacts = append(resp.Artifacts, &actions.ArtifactsViewItem{
Name: "artifact-b",
Size: 1024 * 1024,
Status: "completed",
Name: "artifact-b",
Size: 1024 * 1024,
Status: "completed",
ExpiresUnix: time.Now().Add(24 * time.Hour).Unix(),
})
resp.Artifacts = append(resp.Artifacts, &actions.ArtifactsViewItem{
Name: "artifact-very-loooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
Size: 100 * 1024,
Status: "expired",
Name: "artifact-very-loooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
Size: 100 * 1024,
Status: "expired",
ExpiresUnix: time.Now().Add(-24 * time.Hour).Unix(),
})
resp.Artifacts = append(resp.Artifacts, &actions.ArtifactsViewItem{
Name: "artifact-really-loooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
Size: 1024 * 1024,
Status: "completed",
Name: "artifact-really-loooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
Size: 1024 * 1024,
Status: "completed",
ExpiresUnix: time.Now().Add(24 * time.Hour).Unix(),
})

resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
Expand Down
14 changes: 8 additions & 6 deletions routers/web/repo/actions/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,10 @@ type ViewRequest struct {
}

type ArtifactsViewItem struct {
Name string `json:"name"`
Size int64 `json:"size"`
Status string `json:"status"`
Name string `json:"name"`
Size int64 `json:"size"`
Status string `json:"status"`
ExpiresUnix int64 `json:"expiresUnix"`
}

type ViewResponse struct {
Expand Down Expand Up @@ -344,9 +345,10 @@ func getActionsViewArtifacts(ctx context.Context, repoID, runID int64) (artifact
}
for _, art := range artifacts {
artifactsViewItems = append(artifactsViewItems, &ArtifactsViewItem{
Name: art.ArtifactName,
Size: art.FileSize,
Status: util.Iif(art.Status == actions_model.ArtifactStatusExpired, "expired", "completed"),
Name: art.ArtifactName,
Size: art.FileSize,
Status: util.Iif(art.Status == actions_model.ArtifactStatusExpired, "expired", "completed"),
ExpiresUnix: int64(art.ExpiredUnix),
})
}
return artifactsViewItems, nil
Expand Down
1 change: 1 addition & 0 deletions templates/devtest/relative-time.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<div>numeric: <relative-time datetime="2024-03-11" threshold="P0Y" prefix="" weekday="" year="" day="numeric" month="numeric"></relative-time></div>
<div>weekday: <relative-time datetime="2024-03-11" threshold="P0Y" prefix="" weekday="long" year="" month="numeric"></relative-time></div>
<div>with time: <relative-time datetime="2024-03-11T19:00:00-05:00" threshold="P0Y" prefix="" weekday="long" year="" month="numeric"></relative-time></div>
<div>minutes: <relative-time datetime="2024-03-11T19:30:45-05:00" threshold="P0Y" prefix="" weekday="" year="numeric" month="short" hour="numeric" minute="numeric"></relative-time></div>
</div>
<div>
<h2>Threshold</h2>
Expand Down
2 changes: 2 additions & 0 deletions templates/repo/actions/view_component.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
data-locale-status-blocked="{{ctx.Locale.Tr "actions.status.blocked"}}"
data-locale-artifacts-title="{{ctx.Locale.Tr "artifacts"}}"
data-locale-artifact-expired="{{ctx.Locale.Tr "expired"}}"
data-locale-artifact-expires-at="{{ctx.Locale.Tr "artifact_expires_at"}}"
data-locale-artifact-size="{{ctx.Locale.Tr "repo.diff.file_byte_size"}}"
data-locale-confirm-delete-artifact="{{ctx.Locale.Tr "confirm_delete_artifact"}}"
data-locale-show-timestamps="{{ctx.Locale.Tr "show_timestamps"}}"
data-locale-show-log-seconds="{{ctx.Locale.Tr "show_log_seconds"}}"
Expand Down
39 changes: 39 additions & 0 deletions web_src/js/components/ActionRunArtifacts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {createArtifactTooltipContent, formatArtifactSize, formatArtifactTimestamp} from './ActionRunArtifacts.ts';

test('createArtifactTooltipContent', () => {
document.documentElement.lang = 'en-US';
const locale = {
artifactExpired: 'Expired',
artifactExpiresAt: 'Expires at %s',
artifactSize: 'Size',
status: {
unknown: 'Unknown',
},
};

expect(createArtifactTooltipContent({
name: 'artifact.zip',
size: 1536,
status: 'completed',
expiresUnix: Date.UTC(2026, 2, 20, 12, 0, 0) / 1000,
}, locale)).toContain('Expires at Mar 20, 2026');

expect(createArtifactTooltipContent({
name: 'artifact.zip',
size: 0,
status: 'expired',
expiresUnix: 0,
}, locale)).toBe('Expired | Size: 0 B');
});

test('formatArtifactTimestamp', () => {
document.documentElement.lang = 'en-US';
expect(formatArtifactTimestamp(0)).toBeNull();
expect(formatArtifactTimestamp(Number.NaN)).toBeNull();
expect(formatArtifactTimestamp(Date.UTC(2024, 2, 12, 1, 30, 45) / 1000)).toMatch(/^Mar 12, 2024, /);
});

test('formatArtifactSize', () => {
expect(formatArtifactSize(0)).toBe('0 B');
expect(formatArtifactSize(1536)).toBe('1.5 KiB');
});
55 changes: 55 additions & 0 deletions web_src/js/components/ActionRunArtifacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type {ActionsArtifact} from '../modules/gitea-actions.ts';

export type ArtifactTooltipLocale = {
artifactExpired: string;
artifactExpiresAt: string;
artifactSize: string;
status: {
unknown: string;
};
};

const sizeUnits = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];
let artifactDateFormat: Intl.DateTimeFormat;

export function formatArtifactSize(size: number): string {
let value = size;
let unitIndex = 0;

while (value >= 1024 && unitIndex < sizeUnits.length - 1) {
value /= 1024;
unitIndex++;
}

const formattedValue = unitIndex === 0 ? String(Math.round(value)) : value.toFixed(value >= 10 ? 0 : 1);
return `${formattedValue} ${sizeUnits[unitIndex]}`;
}

function getArtifactDateFormat(): Intl.DateTimeFormat {
return artifactDateFormat ??= new Intl.DateTimeFormat(document.documentElement.lang || undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
hourCycle: new Intl.DateTimeFormat(undefined, {hour: 'numeric'}).resolvedOptions().hourCycle,
});
}

export function formatArtifactTimestamp(expiresUnix: number): string | null {
if (expiresUnix === null || !Number.isFinite(expiresUnix) || expiresUnix <= 0) return null;
return getArtifactDateFormat().format(new Date(expiresUnix * 1000));
}

export function createArtifactTooltipContent(artifact: ActionsArtifact, locale: ArtifactTooltipLocale): string {
const details = [];

if (artifact.status === 'expired') {
details.push(locale.artifactExpired);
} else {
details.push(locale.artifactExpiresAt.replace('%s', formatArtifactTimestamp(artifact.expiresUnix) ?? locale.status.unknown));
}
details.push(`${locale.artifactSize}: ${formatArtifactSize(artifact.size)}`);

return details.join(' | ');
}
13 changes: 9 additions & 4 deletions web_src/js/components/RepoActionView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {toRefs} from 'vue';
import {POST, DELETE} from '../modules/fetch.ts';
import ActionRunSummaryView from './ActionRunSummaryView.vue';
import ActionRunJobView from './ActionRunJobView.vue';
import {createActionRunViewStore} from "./ActionRunView.ts";
import {createActionRunViewStore} from './ActionRunView.ts';
import {createArtifactTooltipContent, type ArtifactTooltipLocale} from './ActionRunArtifacts.ts';

defineOptions({
name: 'RepoActionView',
Expand All @@ -20,7 +21,11 @@ const props = defineProps<{

const locale = props.locale;
const store = createActionRunViewStore(props.actionsUrl, props.runId);
const {currentRun: run , runArtifacts: artifacts} = toRefs(store.viewData);
const {currentRun: run, runArtifacts: artifacts} = toRefs(store.viewData);

function artifactTooltip(artifact: typeof artifacts.value[number]) {
return createArtifactTooltipContent(artifact, locale as ArtifactTooltipLocale);
}

function cancelRun() {
POST(`${run.value.link}/cancel`);
Expand Down Expand Up @@ -120,15 +125,15 @@ async function deleteArtifact(name: string) {
<ul class="ui relaxed list flex-items-block">
<li class="item" v-for="artifact in artifacts" :key="artifact.name">
<template v-if="artifact.status !== 'expired'">
<a class="tw-flex-1 flex-text-block" target="_blank" :href="run.link+'/artifacts/'+artifact.name">
<a class="tw-flex-1 flex-text-block" target="_blank" :href="run.link+'/artifacts/'+artifact.name" :data-tooltip-content="artifactTooltip(artifact)">
<SvgIcon name="octicon-file" class="tw-text-text"/>
<span class="tw-flex-1 gt-ellipsis">{{ artifact.name }}</span>
</a>
<a v-if="run.canDeleteArtifact" @click="deleteArtifact(artifact.name)">
<SvgIcon name="octicon-trash" class="tw-text-text"/>
</a>
</template>
<span v-else class="flex-text-block tw-flex-1 tw-text-grey-light">
<span v-else class="flex-text-block tw-flex-1 tw-text-grey-light" :data-tooltip-content="artifactTooltip(artifact)">
<SvgIcon name="octicon-file"/>
<span class="tw-flex-1 gt-ellipsis">{{ artifact.name }}</span>
<span class="ui label tw-text-grey-light tw-flex-shrink-0">{{ locale.artifactExpired }}</span>
Expand Down
2 changes: 2 additions & 0 deletions web_src/js/features/repo-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export function initRepositoryActionView() {
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
areYouSure: el.getAttribute('data-locale-are-you-sure'),
artifactExpired: el.getAttribute('data-locale-artifact-expired'),
artifactExpiresAt: el.getAttribute('data-locale-artifact-expires-at'),
artifactSize: el.getAttribute('data-locale-artifact-size'),
confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'),
showTimeStamps: el.getAttribute('data-locale-show-timestamps'),
showLogSeconds: el.getAttribute('data-locale-show-log-seconds'),
Expand Down
2 changes: 2 additions & 0 deletions web_src/js/modules/gitea-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ export type ActionsJob = {

export type ActionsArtifact = {
name: string;
size: number;
status: string;
expiresUnix: number;
};