Skip to content
Closed
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 .github/scripts/release/github/stable-notes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ cat > "$notes_file" <<EOF
- branch: $BRANCH_NAME
- commit: $GITHUB_SHA

See [CHANGELOG.md](https://github.com/${GITHUB_REPOSITORY}/blob/$VERSION_TAG/CHANGELOG.md) for the full release notes.
See [docs/CHANGELOG/v$RELEASE_VERSION/en.md](https://github.com/${GITHUB_REPOSITORY}/blob/$VERSION_TAG/docs/CHANGELOG/v$RELEASE_VERSION/en.md) for the English release notes.
Updater release notes are published at $public_origin/$RELEASE_CHANNEL/versions/$RELEASE_VERSION/release-notes/en.md.

This stable release ships mac arm64/x64 DMG and ZIP assets, Windows x64 NSIS installer assets, checksums, updater feed files, and a zipped packaged e2e spec report. Linux AppImage packaging remains optional through the stable Linux lane.
EOF
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/release-beta-s.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ on:
required: false
type: string
default: ""
force_latest:
description: "Allow this run to move betas latest metadata backward. Use only for release metadata recovery."
required: true
type: boolean
default: false
release_origin:
description: "Release storage origin."
required: true
Expand Down Expand Up @@ -192,6 +197,10 @@ on:
required: false
type: string
default: ""
force_latest:
required: false
type: boolean
default: false
release_origin:
required: false
type: string
Expand Down Expand Up @@ -473,6 +482,7 @@ jobs:
env:
GITHUB_REF_NAME: ${{ inputs.ref != '' && inputs.ref || github.ref_name }}
GITHUB_SHA: ${{ steps.checkout.outputs.commit }}
OPEN_DESIGN_RELEASE_FORCE_LATEST: ${{ inputs.force_latest }}
run: |
set -euo pipefail
if ! command -v rehash >/dev/null 2>&1; then
Expand Down Expand Up @@ -953,6 +963,7 @@ jobs:
MAC_ARM64_RESULT: ${{ needs.build_mac_arm64.result }}
MAC_X64_RESULT: skipped
RELEASE_LATEST_CAS_REQUIRED: "true"
RELEASE_LATEST_FORCE: ${{ inputs.force_latest }}
RELEASE_ASSET_SUFFIX: auto
RELEASE_CHANNEL: betas
RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ on:
required: false
type: string
default: ""
force_latest:
description: "Allow this run to move beta latest metadata backward. Use only for release metadata recovery."
required: true
type: boolean
default: false
release_origin:
description: "Release storage origin."
required: true
Expand Down Expand Up @@ -184,6 +189,10 @@ on:
required: false
type: string
default: ""
force_latest:
required: false
type: boolean
default: false
release_origin:
required: false
type: string
Expand Down Expand Up @@ -387,6 +396,7 @@ jobs:
env:
GITHUB_SHA: ${{ env.BUILT_SHA }}
GITHUB_REF_NAME: ${{ inputs.ref != '' && inputs.ref || github.ref_name }}
OPEN_DESIGN_RELEASE_FORCE_LATEST: ${{ inputs.force_latest }}
run: pnpm exec tools-release prepare beta

build_mac_arm64:
Expand Down Expand Up @@ -1409,6 +1419,7 @@ jobs:
MAC_X64_RESULT: ${{ needs.build_mac_x64.result }}
RELEASE_ASSET_SUFFIX: ${{ needs.metadata.outputs.asset_version_suffix }}
RELEASE_CHANNEL: beta
RELEASE_LATEST_FORCE: ${{ inputs.force_latest }}
RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests
RELEASE_METADATA_DIR: ${{ runner.temp }}/release-metadata
RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-metadata/outputs.json
Expand Down
18 changes: 12 additions & 6 deletions .github/workflows/release-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ on:
workflow_dispatch:
inputs:
prerelease_version:
description: "Exact validated prerelease version to promote, for example 0.5.1-prerelease.3."
required: true
description: "Exact validated prerelease version to promote, for example 0.5.1-prerelease.3. Optional only for release-dryrun/vX.Y.Z prepublish validation."
required: false
type: string
default: ""
dry_run:
description: "Release mode. metadata stops after promotion metadata; prepublish runs build/smoke/report/plan without publishing; publish performs the stable release."
required: false
Expand All @@ -17,7 +18,7 @@ on:
- publish
default: metadata
ref:
description: "Stable release branch to build, for example release/v0.5.1. Empty builds the dispatch ref, which must also be release/vX.Y.Z."
description: "Stable release branch to build, for example release/v0.5.1. Prepublish-only validation may use release-dryrun/v0.5.1. Empty builds the dispatch ref."
required: false
type: string
default: ""
Expand All @@ -43,16 +44,17 @@ on:
workflow_call:
inputs:
prerelease_version:
description: "Exact validated prerelease version to promote."
required: true
description: "Exact validated prerelease version to promote. Optional only for release-dryrun/vX.Y.Z prepublish validation."
required: false
type: string
default: ""
dry_run:
description: "Release mode: metadata, prepublish, or publish. The legacy false value is also accepted for callers."
required: false
type: string
default: "metadata"
ref:
description: "Stable release branch to build. Empty builds the caller's ref, which must also be release/vX.Y.Z."
description: "Stable release branch to build. Empty builds the caller's ref. Prepublish-only validation may use release-dryrun/vX.Y.Z."
required: false
type: string
default: ""
Expand Down Expand Up @@ -300,6 +302,7 @@ jobs:
runs-on: macos-14
env:
GH_TOKEN: ${{ github.token }}
RELEASE_PUBLISH_SIDE_EFFECTS: ${{ needs.metadata.outputs.publish_side_effects_enabled }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
Expand Down Expand Up @@ -557,6 +560,7 @@ jobs:
runs-on: macos-15-intel
env:
GH_TOKEN: ${{ github.token }}
RELEASE_PUBLISH_SIDE_EFFECTS: ${{ needs.metadata.outputs.publish_side_effects_enabled }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
Expand Down Expand Up @@ -671,6 +675,7 @@ jobs:
runs-on: windows-latest
env:
GH_TOKEN: ${{ github.token }}
RELEASE_PUBLISH_SIDE_EFFECTS: ${{ needs.metadata.outputs.publish_side_effects_enabled }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
Expand Down Expand Up @@ -927,6 +932,7 @@ jobs:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
RELEASE_PUBLISH_SIDE_EFFECTS: ${{ needs.metadata.outputs.publish_side_effects_enabled }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
Expand Down
54 changes: 51 additions & 3 deletions apps/web/src/components/UpdaterPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import {
deriveUpdaterModel,
openUpdaterInstaller,
quitAfterUpdaterInstallerOpen,
releaseNotesJumpToFromStatus,
readUpdaterStatus,
subscribeToUpdaterStatus,
type UpdaterModel,
} from '../lib/updater';
import { useT } from '../i18n';
import { useI18n } from '../i18n';
import type { Dict } from '../i18n/types';
import { useAnalytics, useAppVersion } from '../analytics/provider';
import {
Expand All @@ -21,6 +22,7 @@ import {
trackUpdateInstallResult,
trackUpdatePromptSurfaceView,
} from '../analytics/events';
import { openExternalUrl } from '../providers/registry';

const INSTALL_HANDOFF_WATCHDOG_MS = 10_000;

Expand Down Expand Up @@ -69,12 +71,13 @@ function updaterErrorCode(model: UpdaterModel): string | undefined {
}

export function UpdaterPopup() {
const t = useT();
const { t } = useI18n();
const wrapRef = useRef<HTMLDivElement | null>(null);
const actionInFlightRef = useRef(false);
const handoffWatchdogRef = useRef<number | null>(null);
const [model, setModel] = useState<UpdaterModel>(() => deriveUpdaterModel(null));
const [panelOpen, setPanelOpen] = useState(false);
const [panelExpanded, setPanelExpanded] = useState(true);
const [installState, setInstallState] = useState<InstallState>('idle');

const clearHandoffWatchdog = useCallback(() => {
Expand All @@ -87,6 +90,7 @@ export function UpdaterPopup() {
handoffWatchdogRef.current = null;
actionInFlightRef.current = false;
setInstallState('recoverable');
setPanelExpanded(true);
setPanelOpen(true);
}, []);

Expand Down Expand Up @@ -132,6 +136,10 @@ export function UpdaterPopup() {
() => updateVersionProps(model, appVersionBefore),
[appVersionBefore, model.availableVersion],
);
const releaseNotesJumpTo = useMemo(
() => releaseNotesJumpToFromStatus(model.status),
[model.status],
);

const indicatorSurfaceKey = `${model.currentVersion ?? 'unknown'}->${model.availableVersion ?? 'unknown'}:${model.status?.downloadPath ?? 'unknown'}`;
const lastIndicatorSurfaceKeyRef = useRef<string | null>(null);
Expand Down Expand Up @@ -200,6 +208,7 @@ export function UpdaterPopup() {
actionInFlightRef.current = true;
clearHandoffWatchdog();
setInstallState('opening');
setPanelExpanded(true);
setPanelOpen(true);
trackUpdateIndicatorClick(analytics.track, {
page_name: 'home',
Expand Down Expand Up @@ -264,6 +273,18 @@ export function UpdaterPopup() {
}
};

const openReleaseNotes = useCallback(() => {
if (releaseNotesJumpTo == null) return;
trackUpdateIndicatorClick(analytics.track, {
page_name: 'home',
area: 'update_prompt',
element: 'release_notes',
action: 'open_link',
...versionProps,
});
void openExternalUrl(releaseNotesJumpTo.url);
}, [analytics.track, releaseNotesJumpTo, versionProps]);

if (!showControl) return null;

return (
Expand All @@ -290,6 +311,7 @@ export function UpdaterPopup() {
action: 'open_prompt',
...versionProps,
});
setPanelExpanded(true);
setPanelOpen(true);
}}
>
Expand All @@ -301,7 +323,7 @@ export function UpdaterPopup() {
{panelOpen ? (
<motion.section
aria-labelledby="updater-popup-title"
className="updater-popup is-ready"
className={`updater-popup is-ready${panelExpanded ? ' updater-popup--expanded' : ' updater-popup--compact'}`}
data-testid="updater-popup"
role="dialog"
variants={popoverIn}
Expand All @@ -312,10 +334,36 @@ export function UpdaterPopup() {
<div className="updater-popup__icon">
<Icon name="arrow-up" size={20} strokeWidth={2.2} />
</div>
<div className="updater-popup__tools">
<button
aria-label={panelExpanded ? t('updater.compactDetails') : t('updater.expandDetails')}
className="updater-popup__icon-button"
data-testid="updater-popup-size-button"
title={panelExpanded ? t('updater.compactDetails') : t('updater.expandDetails')}
type="button"
onClick={() => setPanelExpanded((current) => !current)}
>
<Icon name={panelExpanded ? 'minimize' : 'maximize'} size={15} strokeWidth={1.9} />
</button>
</div>
<div className="updater-popup__body">
<h2 id="updater-popup-title">{t('updater.ready')}</h2>
<p>{versionText(t, model)}</p>
{channelLabel != null ? <span className="updater-popup__badge">{channelLabel}</span> : null}
<div className="updater-popup__release-notes" data-testid="updater-release-notes">
<p>{t('updater.releaseNotesPreview')}</p>
{releaseNotesJumpTo != null ? (
<button
className="updater-popup__release-notes-jump"
data-testid="updater-release-notes-jump"
type="button"
onClick={openReleaseNotes}
>
{t('updater.viewFullReleaseNotes')}
<Icon name="external-link" size={12} strokeWidth={2} />
</button>
) : null}
</div>
</div>
<div className="updater-popup__actions">
<button className="updater-popup__button" disabled={installBusy} type="button" onClick={close}>
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/i18n/locales/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3546,6 +3546,8 @@ export const ar: Dict = {
'updater.downloading': 'جارٍ تنزيل التحديث',
'updater.downloadingPercent': 'جارٍ تنزيل التحديث {percent}%',
'updater.done': 'تم',
'updater.expandDetails': 'توسيع تفاصيل التحديث',
'updater.compactDetails': 'إظهار مطالبة التحديث المصغرة',
'updater.failed': 'فشل التحديث',
'updater.installerOpenBody': 'المثبت مفتوح. يتم الآن إنهاء Open Design لتتمكن من إكمال التحديث.',
'updater.installerOpened': 'تم فتح المثبت',
Expand All @@ -3564,6 +3566,8 @@ export const ar: Dict = {
'updater.ready': 'التحديث جاهز',
'updater.readyGeneric': 'إصدار جديد جاهز. سيتم إغلاق Open Design وفتح المثبت.',
'updater.readyVersion': 'Open Design {version} جاهز. سيتم إغلاق Open Design وفتح المثبت.',
'updater.releaseNotesPreview': 'معاينة ملاحظات الإصدار\n\nتعرض هذه المطالبة نصًا محليًا ثابتًا أثناء التحقق من واجهة التحديث الموسعة.\n\nما زال إجراء التثبيت يستخدم تسليم محدّث الحزمة. يتم تجاوز ملاحظات الإصدار البعيدة بصيغتي HTML وMarkdown مؤقتًا.',
'updater.viewFullReleaseNotes': 'عرض ملاحظات الإصدار كاملة',
'updater.upToDate': 'أنت تستخدم أحدث إصدار بالفعل.',
'newsletter.label': 'النشرة (اختياري)',
'newsletter.placeholder': 'you@studio.com',
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/i18n/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3546,6 +3546,8 @@ export const de: Dict = {
'updater.downloading': 'Update wird heruntergeladen',
'updater.downloadingPercent': 'Update wird heruntergeladen {percent}%',
'updater.done': 'Fertig',
'updater.expandDetails': 'Update-Details erweitern',
'updater.compactDetails': 'Kompakte Update-Meldung anzeigen',
'updater.failed': 'Update fehlgeschlagen',
'updater.installerOpenBody': 'Der Installer ist geöffnet. Open Design wird beendet, damit Sie das Update abschließen können.',
'updater.installerOpened': 'Installer geöffnet',
Expand All @@ -3564,6 +3566,8 @@ export const de: Dict = {
'updater.ready': 'Update bereit',
'updater.readyGeneric': 'Eine neue Version ist bereit. Open Design wird geschlossen und der Installer geöffnet.',
'updater.readyVersion': 'Open Design {version} ist bereit. Open Design wird geschlossen und der Installer geöffnet.',
'updater.releaseNotesPreview': 'Vorschau der Versionshinweise\n\nDiese Meldung zeigt lokalen konstanten Text, während die erweiterte Updater-Oberfläche validiert wird.\n\nDie Installationsaktion nutzt weiterhin die Übergabe des paketierten Updaters. Entfernte HTML- und Markdown-Versionshinweise werden vorerst bewusst umgangen.',
'updater.viewFullReleaseNotes': 'Vollständige Versionshinweise',
'updater.upToDate': 'Sie verwenden bereits die neueste Version.',
'newsletter.label': 'Newsletter (optional)',
'newsletter.placeholder': 'you@studio.com',
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3622,6 +3622,8 @@ export const en: Dict = {
'updater.downloading': 'Downloading update',
'updater.downloadingPercent': 'Downloading update {percent}%',
'updater.done': 'Done',
'updater.expandDetails': 'Expand update details',
'updater.compactDetails': 'Show compact update prompt',
'updater.failed': 'Update failed',
'updater.installerOpenBody': 'The installer is open. Open Design is quitting so you can finish the update.',
'updater.installerOpened': 'Installer opened',
Expand All @@ -3640,6 +3642,8 @@ export const en: Dict = {
'updater.ready': 'Update ready',
'updater.readyGeneric': 'A new version is ready. Open Design will close and open the installer.',
'updater.readyVersion': 'Open Design {version} is ready. Open Design will close and open the installer.',
'updater.releaseNotesPreview': 'Release notes preview\n\nThis prompt is rendering local constant text while the expanded updater UI is validated.\n\nThe install action still uses the packaged updater handoff. Remote HTML and Markdown release notes are intentionally bypassed here for now.',
'updater.viewFullReleaseNotes': 'View full release notes',
'updater.upToDate': 'You\'re already on the latest version.',
'newsletter.label': 'Newsletter (optional)',
'newsletter.placeholder': 'you@studio.com',
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/i18n/locales/es-ES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3546,6 +3546,8 @@ export const esES: Dict = {
'updater.downloading': 'Descargando actualización',
'updater.downloadingPercent': 'Descargando actualización {percent}%',
'updater.done': 'Listo',
'updater.expandDetails': 'Expandir detalles de la actualización',
'updater.compactDetails': 'Mostrar aviso de actualización compacto',
'updater.failed': 'Error de actualización',
'updater.installerOpenBody': 'El instalador está abierto. Open Design se está cerrando para que puedas completar la actualización.',
'updater.installerOpened': 'Instalador abierto',
Expand All @@ -3564,6 +3566,8 @@ export const esES: Dict = {
'updater.ready': 'Actualización lista',
'updater.readyGeneric': 'Hay una nueva versión lista. Open Design se cerrará y abrirá el instalador.',
'updater.readyVersion': 'Open Design {version} está listo. Open Design se cerrará y abrirá el instalador.',
'updater.releaseNotesPreview': 'Vista previa de las notas de la versión\n\nEste aviso muestra texto constante local mientras se valida la interfaz ampliada del actualizador.\n\nLa acción de instalación sigue usando la entrega del actualizador empaquetado. Las notas remotas en HTML y Markdown se omiten intencionalmente por ahora.',
'updater.viewFullReleaseNotes': 'Ver notas completas',
'updater.upToDate': 'Ya tienes la versión más reciente.',
'newsletter.label': 'Newsletter (opcional)',
'newsletter.placeholder': 'you@studio.com',
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/i18n/locales/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3474,6 +3474,8 @@ export const fa: Dict = {
'updater.downloading': 'در حال دانلود به‌روزرسانی',
'updater.downloadingPercent': 'در حال دانلود به‌روزرسانی {percent}%',
'updater.done': 'انجام شد',
'updater.expandDetails': 'باز کردن جزئیات به‌روزرسانی',
'updater.compactDetails': 'نمایش اعلان فشرده به‌روزرسانی',
'updater.failed': 'به‌روزرسانی ناموفق بود',
'updater.installerOpenBody': 'نصب‌کننده باز است. Open Design در حال بسته شدن است تا بتوانید به‌روزرسانی را کامل کنید.',
'updater.installerOpened': 'نصب‌کننده باز شد',
Expand All @@ -3492,6 +3494,8 @@ export const fa: Dict = {
'updater.ready': 'به‌روزرسانی آماده است',
'updater.readyGeneric': 'نسخه جدید آماده است. Open Design بسته می‌شود و نصب‌کننده را باز می‌کند.',
'updater.readyVersion': 'Open Design {version} آماده است. Open Design بسته می‌شود و نصب‌کننده را باز می‌کند.',
'updater.releaseNotesPreview': 'پیش‌نمایش یادداشت‌های انتشار\n\nاین اعلان هنگام اعتبارسنجی رابط بزرگ‌شده به‌روزرسان، متن ثابت محلی را نمایش می‌دهد.\n\nاقدام نصب همچنان از تحویل به‌روزرسان بسته‌بندی‌شده استفاده می‌کند. یادداشت‌های انتشار راه‌دور HTML و Markdown فعلاً عمداً نادیده گرفته می‌شوند.',
'updater.viewFullReleaseNotes': 'مشاهده یادداشت‌های کامل',
'updater.upToDate': 'شما هم‌اکنون آخرین نسخه را دارید.',
'newsletter.label': 'Newsletter (optional)',
'newsletter.placeholder': 'you@studio.com',
Expand Down
Loading
Loading