Session 2026-05-30: tasks/projects unification, code consolidation, file renames
- Unified Tasks page: 3 role render blocks → 1, normalized row shape, single renderRow/sort/tabs - Fixed role scoping: external = all tasks in member projects, client = all tasks in company projects - Fixed client bug: was scoped by submitted_by, now company→project→tasks - Aligned dashboard client scope to match tasks page - Hot tasks dashboard: now filters to active statuses only (not completed/invoiced/paid) - Removed Projects.jsx (dead), fixed /project/ → /projects/ links - Renamed all page files to match folder path (Team*, External*, Client* prefixes) - Renamed: RequestsPage→Tasks, Settings→Profile, CompaniesPage→Companies, ProjectDetailPage→ProjectDetail - Dropped dead fetches from Tasks page (invoices, invoice_items, subcontractor_invoice_items) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+22
-2
@@ -1,6 +1,6 @@
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
const FB_SOURCE = 'files';
|
||||
const FB_SOURCE = 'srv';
|
||||
|
||||
function json(res, status, body) {
|
||||
res.status(status).setHeader('Content-Type', 'application/json');
|
||||
@@ -263,7 +263,8 @@ function toListResponse(vPath, entries, { readOnly = false } = {}) {
|
||||
|
||||
export default async function handler(req, res) {
|
||||
try {
|
||||
const authHeader = req.headers.authorization || '';
|
||||
const queryToken = String(req.query?.sb_access_token || req.body?.sb_access_token || '').trim();
|
||||
const authHeader = req.headers.authorization || (queryToken ? `Bearer ${queryToken}` : '');
|
||||
if (!authHeader) return json(res, 401, { error: 'No authorization header' });
|
||||
|
||||
const auth = await requirePortalUser(authHeader);
|
||||
@@ -333,6 +334,25 @@ export default async function handler(req, res) {
|
||||
return json(res, 200, { url: downloadUrl, token });
|
||||
}
|
||||
|
||||
if (req.method === 'GET' && action === 'download-blob') {
|
||||
const resolved = toFbPath();
|
||||
if (resolved.virtual) return json(res, 400, { error: 'Cannot download virtual directory' });
|
||||
const token = getToken(config);
|
||||
const downloadUrl = `${config.url}/api/resources/download?source=${FB_SOURCE}&file=${encodeURIComponent(resolved.fbPath)}&auth=${encodeURIComponent(token)}`;
|
||||
const upstream = await fetch(downloadUrl);
|
||||
if (!upstream.ok) {
|
||||
const text = await upstream.text();
|
||||
return json(res, upstream.status, { error: text || `Download failed (${upstream.status})` });
|
||||
}
|
||||
|
||||
res.status(upstream.status);
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
res.setHeader('Content-Type', upstream.headers.get('content-type') || 'application/octet-stream');
|
||||
res.setHeader('Content-Disposition', upstream.headers.get('content-disposition') || `attachment; filename="${basename(resolved.fbPath) || 'download'}"`);
|
||||
const arrayBuffer = await upstream.arrayBuffer();
|
||||
return res.send(Buffer.from(arrayBuffer));
|
||||
}
|
||||
|
||||
if (req.method === 'POST' && action === 'upload-token') {
|
||||
const resolved = toFbPath();
|
||||
if (resolved.virtual) return json(res, 400, { error: 'Cannot upload to virtual directory' });
|
||||
|
||||
Reference in New Issue
Block a user