polish: cleanup unused code, i18n gaps, a11y, error handling
- Removed unused ApproverMultiSelect imports (ArtefactDetailPanel, TranslationDetailPanel) - Removed stale editProjectId/editCampaignId state from ArtefactDetailPanel - Added 3 missing i18n keys (selectVersionFirst, pendingReviewInfo, noReviewInfo) - Added error toast on link picker API failure (PostDetail) - Added ARIA attributes to PortalSelect (role=combobox, aria-expanded, listbox, option) - Deleted test screenshots from project root - Simplified artefact creation modal: title + type only (removed brand/project/campaign/approver/description) - Cleaned up ArtefactDetailPanel props (removed unused projects/campaigns) - Translation submit-review: requires source_content before allowing review - Artefact submit-review: requires at least one attachment for design/video - Translation reviewer moved to Review tab (single select, mandatory) - Server blocks translation submit without reviewer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+25
-2
@@ -4205,6 +4205,22 @@ app.post('/api/artefacts/:id/submit-review', requireAuth, async (req, res) => {
|
||||
return res.status(403).json({ error: 'You can only submit your own artefacts' });
|
||||
}
|
||||
|
||||
// Design/video must have at least one attachment uploaded
|
||||
if (existing.type === 'design' || existing.type === 'video') {
|
||||
const versions = await nocodb.list('ArtefactVersions', {
|
||||
where: `(artefact_id,eq,${sanitizeWhereValue(existing.Id)})`,
|
||||
sort: '-version_number', limit: 1,
|
||||
});
|
||||
if (versions.length > 0) {
|
||||
const attachments = await nocodb.list('ArtefactAttachments', {
|
||||
where: `(version_id,eq,${versions[0].Id})`, limit: 1,
|
||||
});
|
||||
if (attachments.length === 0) {
|
||||
return res.status(400).json({ error: 'Upload at least one file before submitting for review' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const approverIds = parseApproverIds(existing.approver_ids);
|
||||
if (approverIds.length === 0) {
|
||||
return res.status(400).json({ error: 'Select a reviewer before submitting for review' });
|
||||
@@ -4995,8 +5011,6 @@ app.get('/api/translations/:id', requireAuth, async (req, res) => {
|
||||
app.post('/api/translations', requireAuth, async (req, res) => {
|
||||
const { title, source_language, source_content, brand_id, post_id, approver_ids, copy_type } = req.body;
|
||||
if (!title) return res.status(400).json({ error: 'Title is required' });
|
||||
if (!source_language) return res.status(400).json({ error: 'Source language is required' });
|
||||
if (!source_content) return res.status(400).json({ error: 'Source content is required' });
|
||||
|
||||
try {
|
||||
const created = await nocodb.create('Translations', {
|
||||
@@ -5286,6 +5300,15 @@ app.post('/api/translations/:id/submit-review', requireAuth, async (req, res) =>
|
||||
return res.status(403).json({ error: 'You can only submit your own translations' });
|
||||
}
|
||||
|
||||
if (!existing.source_content || !existing.source_content.trim()) {
|
||||
return res.status(400).json({ error: 'Add content before submitting for review' });
|
||||
}
|
||||
|
||||
const approverIds = parseApproverIds(existing.approver_ids);
|
||||
if (approverIds.length === 0) {
|
||||
return res.status(400).json({ error: 'Select a reviewer before submitting for review' });
|
||||
}
|
||||
|
||||
const token = require('crypto').randomUUID();
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setDate(expiresAt.getDate() + DEFAULTS.tokenExpiryDays);
|
||||
|
||||
Reference in New Issue
Block a user