mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-09 10:49:29 +00:00
fix(downloads): harden duplicate resolution and row controls
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
commonMediaFormatsForRows,
|
||||
canSubmitMetadataRows,
|
||||
commonMediaQualitiesForRows,
|
||||
durableDownloadUrl,
|
||||
mediaFormatSelectorForRow,
|
||||
mediaFileNameForSelectedFormat,
|
||||
mediaFormatForFormat,
|
||||
@@ -35,6 +36,14 @@ const row = (
|
||||
});
|
||||
|
||||
describe('add download metadata workflow', () => {
|
||||
it('keeps the stable source URL instead of persisting a resolved redirect', () => {
|
||||
const sourceUrl = 'https://github.com/example/project/releases/download/v1/file.zip';
|
||||
const signedRedirect = 'https://release-assets.githubusercontent.com/github-production-release-asset/asset?se=2099-01-01T00%3A00%3A00Z&sig=redacted';
|
||||
|
||||
expect(durableDownloadUrl(sourceUrl)).toBe(sourceUrl);
|
||||
expect(durableDownloadUrl(sourceUrl)).not.toBe(signedRedirect);
|
||||
});
|
||||
|
||||
it('preserves rows by normalized source URL and creates only new rows', () => {
|
||||
const existing = row({ file: 'server-name.zip' });
|
||||
let nextId = 0;
|
||||
|
||||
@@ -54,6 +54,13 @@ export interface AddDownloadDraftRow {
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect targets are request-time details, not durable download identity.
|
||||
* Providers such as GitHub sign those targets with short-lived credentials,
|
||||
* so retries must start from the source URL and resolve a fresh target.
|
||||
*/
|
||||
export const durableDownloadUrl = (sourceUrl: string): string => sourceUrl.trim();
|
||||
|
||||
const ALLOWED_SCHEMES = new Set(['http:', 'https:', 'ftp:', 'sftp:']);
|
||||
|
||||
type ParsedInput = {
|
||||
|
||||
@@ -73,7 +73,18 @@ describe('download table column preferences', () => {
|
||||
800
|
||||
)).toMatchObject({
|
||||
right: 8,
|
||||
height: 30,
|
||||
height: 28,
|
||||
visibility: 'visible',
|
||||
});
|
||||
|
||||
expect(getDownloadActionPosition(
|
||||
{ top: 40, right: 400, bottom: 72, left: 100 },
|
||||
viewport,
|
||||
viewport,
|
||||
800,
|
||||
16
|
||||
)).toMatchObject({
|
||||
right: 416,
|
||||
visibility: 'visible',
|
||||
});
|
||||
|
||||
|
||||
@@ -14,11 +14,10 @@ export const DEFAULT_COLUMN_ORDER = [
|
||||
|
||||
export const DEFAULT_COLUMN_WIDTHS = [340, 100, 220, 100, 80, 170] as const;
|
||||
export const COLUMN_MINIMUMS = [160, 58, 92, 58, 48, 144] as const;
|
||||
// Width of the compact action rail shown while hovering or focusing a row.
|
||||
export const DOWNLOAD_ACTIONS_COLUMN_WIDTH = 64;
|
||||
// Keep the viewport-anchored rail clear of the window edge and scrollbar.
|
||||
export const DOWNLOAD_ACTIONS_VIEWPORT_INSET = 8;
|
||||
export const DOWNLOAD_ACTIONS_MAX_HEIGHT = 30;
|
||||
// Match the 28px master-control group height.
|
||||
export const DOWNLOAD_ACTIONS_MAX_HEIGHT = 28;
|
||||
export const DOWNLOAD_ACTIONS_VIEWPORT_TOLERANCE = 1;
|
||||
|
||||
export interface DownloadActionViewportRect {
|
||||
@@ -40,7 +39,8 @@ export const getDownloadActionPosition = (
|
||||
rowRect: DownloadActionViewportRect,
|
||||
horizontalViewportRect: DownloadActionViewportRect,
|
||||
verticalViewportRect: DownloadActionViewportRect,
|
||||
windowWidth: number
|
||||
windowWidth: number,
|
||||
actionInset = DOWNLOAD_ACTIONS_VIEWPORT_INSET
|
||||
): DownloadActionPosition => {
|
||||
const visibleTop = Math.max(rowRect.top, verticalViewportRect.top);
|
||||
const visibleBottom = Math.min(rowRect.bottom, verticalViewportRect.bottom);
|
||||
@@ -52,10 +52,13 @@ export const getDownloadActionPosition = (
|
||||
visibleWidth > DOWNLOAD_ACTIONS_VIEWPORT_TOLERANCE;
|
||||
const actionHeight = Math.min(DOWNLOAD_ACTIONS_MAX_HEIGHT, rowRect.bottom - rowRect.top, visibleHeight);
|
||||
const actionRightEdge = Math.min(rowRect.right, horizontalViewportRect.right);
|
||||
const safeActionInset = Number.isFinite(actionInset)
|
||||
? Math.max(0, actionInset)
|
||||
: DOWNLOAD_ACTIONS_VIEWPORT_INSET;
|
||||
|
||||
return {
|
||||
top: visibleTop + Math.max(0, (visibleHeight - actionHeight) / 2),
|
||||
right: Math.max(0, windowWidth - actionRightEdge) + DOWNLOAD_ACTIONS_VIEWPORT_INSET,
|
||||
right: Math.max(0, windowWidth - actionRightEdge) + safeActionInset,
|
||||
height: actionHeight,
|
||||
overflow: actionHeight < rowRect.bottom - rowRect.top ? 'hidden' : 'visible',
|
||||
visibility: isVisible ? 'visible' : 'hidden',
|
||||
|
||||
Reference in New Issue
Block a user