feat: save photo-only captures as drafts (Closes #939)
CI / lint (pull_request) Successful in 2m9s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 1m2s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-16 04:59:08 +00:00
1 parent 8a85b344f8
commit caa0fbc2fd
7 files changed
+118 -14

No files matched your search

+7 -2
View File
@@ -2651,7 +2651,8 @@
function listDrafts() {
const unfiled = unfiledCaptures.list().map(item => ({
id:'unfiled:' + item.id, capture_id:item.id, kind:'unfiled-issue', ...unfiledDraftSummary(item),
title:item.title, preview:item.body + (item.hasAttachment ? ' · Screenshot attached' : ''),
title:unfiledDraftDisplayTitle(item),
preview:[item.body, item.hasAttachment ? 'Photo evidence attached' : ''].filter(Boolean).join(' · '),
hasAttachment:item.hasAttachment, copy_text:[item.title, item.body].filter(Boolean).join('\n\n'),
updated_at:item.savedAt, quarantined:item.quarantined,
ownership:item.quarantined ? 'Saved by ' + item.ownerLogin +
@@ -4315,7 +4316,11 @@
}
clearSharedLaunchUrl();
}
qs('#create-issue-title').focus();
const mobileCapture = window.matchMedia?.('(max-width: 600px)').matches === true;
const continuingCapture = Boolean(rUC || captureDraft.title || captureDraft.body || captureDraft.repository);
if (unfiledShouldFocusTitle({mobile:mobileCapture, continuing:continuingCapture})) {
qs('#create-issue-title').focus();
}
}
function setIssueFilingMode(enabled) {
+17 -6
View File
@@ -18,6 +18,14 @@ function unfiledDraftSummary(item) {
};
}
function unfiledDraftDisplayTitle(item) {
return String(item?.title || '').trim() || (item?.hasAttachment ? 'Untitled photo draft' : 'Untitled draft');
}
function unfiledShouldFocusTitle({mobile = false, continuing = false} = {}) {
return !mobile || continuing;
}
function unfiledSavedMessage(item) {
return item.repository ? 'Saved planned Draft. Resume on any signed-in device.' :
'Saved to Drafts. Choose a repository when you’re ready to file it.';
@@ -49,7 +57,8 @@ function createUnfiledCaptures({
if (record?.version !== 1 || !Array.isArray(record.items)) return [];
return record.items.filter(item =>
item && typeof item.id === 'string' && typeof item.ownerLogin === 'string' &&
typeof item.title === 'string' && item.title.trim() && typeof item.body === 'string'
typeof item.title === 'string' && (item.title.trim() || item.hasAttachment === true) &&
typeof item.body === 'string'
);
} catch (_error) { return []; }
}
@@ -122,9 +131,6 @@ function createUnfiledCaptures({
function prepare(note) {
const title = String(note?.title || '').trim().slice(0, 255);
const body = String(note?.body || '').trim().slice(0, 10000);
if (!title) throw new Error('Add a title before saving.');
const ownerLogin = String(getCaptureLogin() || '').trim();
if (!ownerLogin) throw new Error('Offline identity is unavailable. Reconnect once before saving private work.');
const attachment = note?.attachment;
const attachments = note?.attachments;
if (Array.isArray(attachments) && attachments.length > 5) {
@@ -139,6 +145,9 @@ function createUnfiledCaptures({
const hasAttachment = Boolean(attachment?.blob && attachment?.filename &&
['image/png', 'image/jpeg', 'image/webp'].includes(String(attachment?.contentType || '')));
if (attachment && !hasAttachment) throw new Error('The screenshot is unavailable. Choose it again before saving.');
if (!title && !hasAttachment && !validAttachments) throw new Error('Add a title or photo before saving.');
const ownerLogin = String(getCaptureLogin() || '').trim();
if (!ownerLogin) throw new Error('Offline identity is unavailable. Reconnect once before saving private work.');
if ((hasAttachment || validAttachments) && !attachmentStore) {
throw new Error('Screenshot storage is unavailable. Your capture is still open; retry after reloading.');
}
@@ -344,7 +353,7 @@ function createUnfiledCaptures({
} : {}),
...(evidence.length ? {hasAttachment:true, attachmentCount:evidence.length} : {}),
};
if (!item.id || !item.title.trim() || !Number.isFinite(item.savedAt)) continue;
if (!item.id || (!item.title.trim() && !evidence.length) || !Number.isFinite(item.savedAt)) continue;
if (evidence.length) {
await attachmentStore.put(item.id, {attachments:evidence.map(entry => ({
filename:String(entry.filename), contentType:String(entry.content_type),
@@ -382,7 +391,7 @@ function createUnfiledCaptures({
} : {}),
...(evidence.length ? {hasAttachment:true, attachmentCount:evidence.length} : {}),
};
if (!item.id || !item.title.trim() || !Number.isFinite(item.savedAt)) continue;
if (!item.id || (!item.title.trim() && !evidence.length) || !Number.isFinite(item.savedAt)) continue;
if (evidence.length) {
stagedEvidence.set(item.id, {attachments:evidence.map(entry => ({
filename:String(entry.filename), contentType:String(entry.content_type),
@@ -422,4 +431,6 @@ function createUnfiledCaptures({
if (typeof module !== 'undefined' && module.exports) {
module.exports = createUnfiledCaptures;
module.exports.summary = unfiledDraftSummary;
module.exports.displayTitle = unfiledDraftDisplayTitle;
module.exports.shouldFocusTitle = unfiledShouldFocusTitle;
}