fix: remove orphaned debug statements causing build errors
- Remove incomplete console.log cleanup artifacts across 17 files - Fix orphaned object literals left from previous debug removal - Prefix unused callback parameters with underscores - Update Drawfast shape to side-by-side INPUT/OUTPUT layout (900x500) - Remove unused overlay toggle from Drawfast controls Files fixed: AutomergeToTLStore, TLStoreToAutomerge, useAutomergeSyncRepo, FathomMeetingsPanel, NetworkGraphPanel, sessionPersistence, quartzSync, testClientConfig, useCollaboration, Board, DrawfastShapeUtil, FathomMeetingsBrowserShapeUtil, MapShapeUtil, FathomMeetingsTool, HolonTool, overrides, githubSetupValidator 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
771840605a
commit
0d6b62d1c7
|
|
@ -442,20 +442,6 @@ export function applyAutomergePatchesToTLStore(
|
||||||
// put / remove the records in the store
|
// put / remove the records in the store
|
||||||
// Log patch application for debugging
|
// Log patch application for debugging
|
||||||
|
|
||||||
// DEBUG: Log shape updates being applied to store
|
|
||||||
toPut.forEach(record => {
|
|
||||||
if (record.typeName === 'shape' && (record as any).props?.w) {
|
|
||||||
w: (record as any).props.w,
|
|
||||||
h: (record as any).props.h,
|
|
||||||
x: (record as any).x,
|
|
||||||
y: (record as any).y
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (failedRecords.length > 0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failedRecords.length > 0) {
|
if (failedRecords.length > 0) {
|
||||||
console.error("Failed to sanitize records:", failedRecords)
|
console.error("Failed to sanitize records:", failedRecords)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -462,44 +462,6 @@ export function applyTLStoreChangesToAutomerge(
|
||||||
originalX = (record as any).x
|
originalX = (record as any).x
|
||||||
originalY = (record as any).y
|
originalY = (record as any).y
|
||||||
}
|
}
|
||||||
// DEBUG: Log richText, meta.text, and Obsidian note properties before sanitization
|
|
||||||
if (record.typeName === 'shape') {
|
|
||||||
if (record.type === 'geo' && (record.props as any)?.richText) {
|
|
||||||
hasRichText: !!(record.props as any).richText,
|
|
||||||
richTextType: typeof (record.props as any).richText,
|
|
||||||
richTextContent: Array.isArray((record.props as any).richText) ? 'array' : (record.props as any).richText?.content ? 'object with content' : 'object without content'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (record.type === 'geo' && (record.meta as any)?.text !== undefined) {
|
|
||||||
hasMetaText: !!(record.meta as any).text,
|
|
||||||
metaTextValue: (record.meta as any).text,
|
|
||||||
metaTextType: typeof (record.meta as any).text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (record.type === 'note' && (record.props as any)?.richText) {
|
|
||||||
hasRichText: !!(record.props as any).richText,
|
|
||||||
richTextType: typeof (record.props as any).richText,
|
|
||||||
richTextContent: Array.isArray((record.props as any).richText) ? 'array' : (record.props as any).richText?.content ? 'object with content' : 'object without content',
|
|
||||||
richTextContentLength: Array.isArray((record.props as any).richText?.content) ? (record.props as any).richText.content.length : 'not array'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (record.type === 'arrow' && (record.props as any)?.text !== undefined) {
|
|
||||||
hasText: !!(record.props as any).text,
|
|
||||||
textValue: (record.props as any).text,
|
|
||||||
textType: typeof (record.props as any).text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (record.type === 'ObsNote') {
|
|
||||||
hasTitle: !!(record.props as any).title,
|
|
||||||
hasContent: !!(record.props as any).content,
|
|
||||||
hasTags: Array.isArray((record.props as any).tags),
|
|
||||||
title: (record.props as any).title,
|
|
||||||
contentLength: (record.props as any).content?.length || 0,
|
|
||||||
tagsCount: Array.isArray((record.props as any).tags) ? (record.props as any).tags.length : 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sanitizedRecord = sanitizeRecord(record)
|
const sanitizedRecord = sanitizeRecord(record)
|
||||||
|
|
||||||
// CRITICAL: Restore original coordinates if they were valid
|
// CRITICAL: Restore original coordinates if they were valid
|
||||||
|
|
@ -513,89 +475,11 @@ export function applyTLStoreChangesToAutomerge(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG: Log richText, meta.text, and Obsidian note properties after sanitization
|
|
||||||
if (sanitizedRecord.typeName === 'shape') {
|
|
||||||
if (sanitizedRecord.type === 'geo' && (sanitizedRecord.props as any)?.richText) {
|
|
||||||
hasRichText: !!(sanitizedRecord.props as any).richText,
|
|
||||||
richTextType: typeof (sanitizedRecord.props as any).richText,
|
|
||||||
richTextContent: Array.isArray((sanitizedRecord.props as any).richText) ? 'array' : (sanitizedRecord.props as any).richText?.content ? 'object with content' : 'object without content'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (sanitizedRecord.type === 'geo' && (sanitizedRecord.meta as any)?.text !== undefined) {
|
|
||||||
hasMetaText: !!(sanitizedRecord.meta as any).text,
|
|
||||||
metaTextValue: (sanitizedRecord.meta as any).text,
|
|
||||||
metaTextType: typeof (sanitizedRecord.meta as any).text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (sanitizedRecord.type === 'note' && (sanitizedRecord.props as any)?.richText) {
|
|
||||||
hasRichText: !!(sanitizedRecord.props as any).richText,
|
|
||||||
richTextType: typeof (sanitizedRecord.props as any).richText,
|
|
||||||
richTextContent: Array.isArray((sanitizedRecord.props as any).richText) ? 'array' : (sanitizedRecord.props as any).richText?.content ? 'object with content' : 'object without content',
|
|
||||||
richTextContentLength: Array.isArray((sanitizedRecord.props as any).richText?.content) ? (sanitizedRecord.props as any).richText.content.length : 'not array'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (sanitizedRecord.type === 'arrow' && (sanitizedRecord.props as any)?.text !== undefined) {
|
|
||||||
hasText: !!(sanitizedRecord.props as any).text,
|
|
||||||
textValue: (sanitizedRecord.props as any).text,
|
|
||||||
textType: typeof (sanitizedRecord.props as any).text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (sanitizedRecord.type === 'ObsNote') {
|
|
||||||
hasTitle: !!(sanitizedRecord.props as any).title,
|
|
||||||
hasContent: !!(sanitizedRecord.props as any).content,
|
|
||||||
hasTags: Array.isArray((sanitizedRecord.props as any).tags),
|
|
||||||
title: (sanitizedRecord.props as any).title,
|
|
||||||
contentLength: (sanitizedRecord.props as any).content?.length || 0,
|
|
||||||
tagsCount: Array.isArray((sanitizedRecord.props as any).tags) ? (sanitizedRecord.props as any).tags.length : 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRITICAL: Create a deep copy to ensure all properties (including richText and text) are preserved
|
// CRITICAL: Create a deep copy to ensure all properties (including richText and text) are preserved
|
||||||
// This prevents Automerge from treating the object as read-only
|
// This prevents Automerge from treating the object as read-only
|
||||||
// Note: sanitizedRecord.props is already a deep copy from sanitizeRecord, but we need to deep copy the entire record
|
// Note: sanitizedRecord.props is already a deep copy from sanitizeRecord, but we need to deep copy the entire record
|
||||||
const recordToSave = JSON.parse(JSON.stringify(sanitizedRecord))
|
const recordToSave = JSON.parse(JSON.stringify(sanitizedRecord))
|
||||||
|
|
||||||
// DEBUG: Log richText, meta.text, and Obsidian note properties after deep copy
|
|
||||||
if (recordToSave.typeName === 'shape') {
|
|
||||||
if (recordToSave.type === 'geo' && recordToSave.props?.richText) {
|
|
||||||
hasRichText: !!recordToSave.props.richText,
|
|
||||||
richTextType: typeof recordToSave.props.richText,
|
|
||||||
richTextContent: Array.isArray(recordToSave.props.richText) ? 'array' : recordToSave.props.richText?.content ? 'object with content' : 'object without content',
|
|
||||||
richTextContentLength: Array.isArray(recordToSave.props.richText?.content) ? recordToSave.props.richText.content.length : 'not array'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (recordToSave.type === 'geo' && recordToSave.meta?.text !== undefined) {
|
|
||||||
hasMetaText: !!recordToSave.meta.text,
|
|
||||||
metaTextValue: recordToSave.meta.text,
|
|
||||||
metaTextType: typeof recordToSave.meta.text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (recordToSave.type === 'note' && recordToSave.props?.richText) {
|
|
||||||
hasRichText: !!recordToSave.props.richText,
|
|
||||||
richTextType: typeof recordToSave.props.richText,
|
|
||||||
richTextContent: Array.isArray(recordToSave.props.richText) ? 'array' : recordToSave.props.richText?.content ? 'object with content' : 'object without content',
|
|
||||||
richTextContentLength: Array.isArray(recordToSave.props.richText?.content) ? recordToSave.props.richText.content.length : 'not array'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (recordToSave.type === 'arrow' && recordToSave.props?.text !== undefined) {
|
|
||||||
hasText: !!recordToSave.props.text,
|
|
||||||
textValue: recordToSave.props.text,
|
|
||||||
textType: typeof recordToSave.props.text
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (recordToSave.type === 'ObsNote') {
|
|
||||||
hasTitle: !!recordToSave.props.title,
|
|
||||||
hasContent: !!recordToSave.props.content,
|
|
||||||
hasTags: Array.isArray(recordToSave.props.tags),
|
|
||||||
title: recordToSave.props.title,
|
|
||||||
contentLength: recordToSave.props.content?.length || 0,
|
|
||||||
tagsCount: Array.isArray(recordToSave.props.tags) ? recordToSave.props.tags.length : 0,
|
|
||||||
allPropsKeys: Object.keys(recordToSave.props || {})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the entire record - Automerge will handle merging with concurrent changes
|
// Replace the entire record - Automerge will handle merging with concurrent changes
|
||||||
doc.store[record.id] = recordToSave
|
doc.store[record.id] = recordToSave
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -158,19 +158,6 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
|
||||||
const deletedRecordIds = data.deleted || []
|
const deletedRecordIds = data.deleted || []
|
||||||
const deletedShapes = deletedRecordIds.filter(id => id.startsWith('shape:'))
|
const deletedShapes = deletedRecordIds.filter(id => id.startsWith('shape:'))
|
||||||
|
|
||||||
// Log incoming sync data for debugging
|
|
||||||
if (shapeRecords.length > 0) {
|
|
||||||
shapeRecords.forEach((shape: any) => {
|
|
||||||
x: shape.x,
|
|
||||||
y: shape.y,
|
|
||||||
w: shape.props?.w,
|
|
||||||
h: shape.props?.h
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (deletedShapes.length > 0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply changes to the Automerge document
|
// Apply changes to the Automerge document
|
||||||
// This will trigger patches which will update the TLDraw store
|
// This will trigger patches which will update the TLDraw store
|
||||||
// NOTE: We do NOT increment pendingLocalChanges here because these are REMOTE changes
|
// NOTE: We do NOT increment pendingLocalChanges here because these are REMOTE changes
|
||||||
|
|
@ -621,17 +608,6 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log significant changes for debugging
|
|
||||||
const shapePatches = payload.patches.filter((p: any) => {
|
|
||||||
const id = p.path?.[1]
|
|
||||||
return id && typeof id === 'string' && id.startsWith('shape:')
|
|
||||||
})
|
|
||||||
|
|
||||||
if (shapePatches.length > 0) {
|
|
||||||
patchCount: patchCount,
|
|
||||||
shapePatches: shapePatches.length
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.on('change', changeHandler)
|
handle.on('change', changeHandler)
|
||||||
|
|
|
||||||
|
|
@ -149,12 +149,6 @@ export function FathomMeetingsPanel({ onClose, onMeetingSelect, shapeMode = fals
|
||||||
|
|
||||||
// Handler for individual data type buttons - creates shapes directly
|
// Handler for individual data type buttons - creates shapes directly
|
||||||
const handleDataButtonClick = async (meeting: FathomMeeting, dataType: 'summary' | 'transcript' | 'actionItems' | 'video') => {
|
const handleDataButtonClick = async (meeting: FathomMeeting, dataType: 'summary' | 'transcript' | 'actionItems' | 'video') => {
|
||||||
// Log to verify the correct meeting is being used
|
|
||||||
recording_id: meeting.recording_id,
|
|
||||||
title: meeting.title,
|
|
||||||
dataType
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!onMeetingSelect) {
|
if (!onMeetingSelect) {
|
||||||
// Fallback for non-browser mode
|
// Fallback for non-browser mode
|
||||||
const options = {
|
const options = {
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ export function NetworkGraphPanel({ onExpand }: NetworkGraphPanelProps) {
|
||||||
}, [disconnect]);
|
}, [disconnect]);
|
||||||
|
|
||||||
// Handle node click
|
// Handle node click
|
||||||
const handleNodeClick = useCallback((node: any) => {
|
const handleNodeClick = useCallback((_node: any) => {
|
||||||
// Could open a profile modal or navigate to user
|
// Could open a profile modal or navigate to user
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,6 @@ export const loadSession = (): StoredSession | null => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed = JSON.parse(stored) as StoredSession;
|
const parsed = JSON.parse(stored) as StoredSession;
|
||||||
username: parsed.username,
|
|
||||||
authed: parsed.authed,
|
|
||||||
timestamp: new Date(parsed.timestamp).toISOString()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if session is not too old (7 days)
|
// Check if session is not too old (7 days)
|
||||||
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
|
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
|
||||||
|
|
|
||||||
|
|
@ -102,20 +102,4 @@ export function logGitHubSetupStatus(): void {
|
||||||
const status = validateGitHubSetup()
|
const status = validateGitHubSetup()
|
||||||
|
|
||||||
|
|
||||||
if (status.isValid) {
|
|
||||||
} else {
|
|
||||||
status.issues.forEach(issue => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.warnings.length > 0) {
|
|
||||||
status.warnings.forEach(warning => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.suggestions.length > 0) {
|
|
||||||
status.suggestions.forEach(suggestion => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!status.isValid) {
|
|
||||||
getGitHubSetupInstructions().forEach(instruction => {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,6 @@ export class QuartzSync {
|
||||||
const { githubToken, githubRepo } = this.config
|
const { githubToken, githubRepo } = this.config
|
||||||
const [owner, repo] = githubRepo.split('/')
|
const [owner, repo] = githubRepo.split('/')
|
||||||
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
noteTitle: note.title,
|
|
||||||
noteFilePath: note.filePath
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get the current file content to check if it exists
|
// Get the current file content to check if it exists
|
||||||
const filePath = `content/${note.filePath}`
|
const filePath = `content/${note.filePath}`
|
||||||
let sha: string | undefined
|
let sha: string | undefined
|
||||||
|
|
@ -225,13 +219,6 @@ ${note.content}`
|
||||||
* Prioritizes GitHub integration for Quartz sites
|
* Prioritizes GitHub integration for Quartz sites
|
||||||
*/
|
*/
|
||||||
async smartSync(note: QuartzNote): Promise<boolean> {
|
async smartSync(note: QuartzNote): Promise<boolean> {
|
||||||
hasGitHubToken: !!this.config.githubToken,
|
|
||||||
hasGitHubRepo: !!this.config.githubRepo,
|
|
||||||
hasCloudflareApiKey: !!this.config.cloudflareApiKey,
|
|
||||||
hasCloudflareAccountId: !!this.config.cloudflareAccountId,
|
|
||||||
hasQuartzUrl: !!this.config.quartzUrl
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check if GitHub integration is available and preferred
|
// Check if GitHub integration is available and preferred
|
||||||
if (this.config.githubToken && this.config.githubRepo) {
|
if (this.config.githubToken && this.config.githubRepo) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -241,12 +228,7 @@ ${note.content}`
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('⚠️ GitHub sync failed, trying other methods:', error)
|
console.warn('⚠️ GitHub sync failed, trying other methods:', error)
|
||||||
console.warn('⚠️ GitHub sync error details:', {
|
|
||||||
message: error instanceof Error ? error.message : 'Unknown error',
|
|
||||||
stack: error instanceof Error ? error.stack : 'No stack trace'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to other methods
|
// Fallback to other methods
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,8 @@
|
||||||
import { getClientConfig, isGitHubConfigured, getGitHubConfig } from './clientConfig'
|
import { getClientConfig, isGitHubConfigured, getGitHubConfig } from './clientConfig'
|
||||||
|
|
||||||
export function testClientConfig() {
|
export function testClientConfig() {
|
||||||
|
|
||||||
const config = getClientConfig()
|
const config = getClientConfig()
|
||||||
hasGithubToken: !!config.githubToken,
|
|
||||||
hasQuartzRepo: !!config.quartzRepo,
|
|
||||||
githubTokenLength: config.githubToken?.length || 0,
|
|
||||||
quartzRepo: config.quartzRepo
|
|
||||||
})
|
|
||||||
|
|
||||||
const isConfigured = isGitHubConfigured()
|
const isConfigured = isGitHubConfigured()
|
||||||
|
|
||||||
const githubConfig = getGitHubConfig()
|
const githubConfig = getGitHubConfig()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,13 @@ export function useCollaboration({
|
||||||
};
|
};
|
||||||
}, [sessionId, serverUrl]);
|
}, [sessionId, serverUrl]);
|
||||||
|
|
||||||
const createSession = useCallback(async (name: string): Promise<string> => {
|
const createSession = useCallback(async (_name: string): Promise<string> => {
|
||||||
// TODO: Create new Y.js document and return session ID
|
// TODO: Create new Y.js document and return session ID
|
||||||
const newSessionId = `session-${Date.now()}`;
|
const newSessionId = `session-${Date.now()}`;
|
||||||
return newSessionId;
|
return newSessionId;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const joinSession = useCallback(async (sessionIdToJoin: string): Promise<void> => {
|
const joinSession = useCallback(async (_sessionIdToJoin: string): Promise<void> => {
|
||||||
// TODO: Join existing Y.js session
|
// TODO: Join existing Y.js session
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -96,15 +96,15 @@ export function useCollaboration({
|
||||||
// awareness.setLocalStateField('cursor', coordinate);
|
// awareness.setLocalStateField('cursor', coordinate);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const broadcastRouteChange = useCallback((route: Route) => {
|
const broadcastRouteChange = useCallback((_route: Route) => {
|
||||||
// TODO: Update Y.js shared route array
|
// TODO: Update Y.js shared route array
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const broadcastWaypointChange = useCallback((waypoint: Waypoint) => {
|
const broadcastWaypointChange = useCallback((_waypoint: Waypoint) => {
|
||||||
// TODO: Update Y.js shared waypoint array
|
// TODO: Update Y.js shared waypoint array
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const broadcastLayerChange = useCallback((layer: MapLayer) => {
|
const broadcastLayerChange = useCallback((_layer: MapLayer) => {
|
||||||
// TODO: Update Y.js shared layer array
|
// TODO: Update Y.js shared layer array
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,25 +376,6 @@ export function Board() {
|
||||||
? false // Don't restrict while loading/transitioning - assume can edit
|
? false // Don't restrict while loading/transitioning - assume can edit
|
||||||
: permission === 'view' // Only restrict if explicitly view (protected board)
|
: permission === 'view' // Only restrict if explicitly view (protected board)
|
||||||
|
|
||||||
// Debug logging for permission issues
|
|
||||||
permission,
|
|
||||||
permissionLoading,
|
|
||||||
sessionAuthed: session.authed,
|
|
||||||
sessionLoading: session.loading,
|
|
||||||
sessionUsername: session.username,
|
|
||||||
authJustChanged,
|
|
||||||
isReadOnly,
|
|
||||||
reason: session.loading
|
|
||||||
? 'auth loading - allowing edit temporarily'
|
|
||||||
: authJustChanged
|
|
||||||
? 'auth just changed - allowing edit until effects run'
|
|
||||||
: permissionLoading
|
|
||||||
? 'permission loading - allowing edit temporarily'
|
|
||||||
: permission === 'view'
|
|
||||||
? 'protected board - user not an editor (view-only)'
|
|
||||||
: 'open board or user is editor (can edit)'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Handler for when user tries to edit in read-only mode
|
// Handler for when user tries to edit in read-only mode
|
||||||
const handleEditAttempt = () => {
|
const handleEditAttempt = () => {
|
||||||
if (isReadOnly) {
|
if (isReadOnly) {
|
||||||
|
|
@ -681,29 +662,6 @@ export function Board() {
|
||||||
// Debug: Log page information
|
// Debug: Log page information
|
||||||
const allPages = store.store.allRecords().filter((r: any) => r.typeName === 'page')
|
const allPages = store.store.allRecords().filter((r: any) => r.typeName === 'page')
|
||||||
|
|
||||||
// CRITICAL DEBUG: Check if shapes exist in editor but aren't returned by getCurrentPageShapes
|
|
||||||
if (storeShapesOnCurrentPage.length > 0 && editorShapes.length === 0) {
|
|
||||||
const sampleShape = storeShapesOnCurrentPage[0]
|
|
||||||
const shapeInEditor = editor.getShape(sampleShape.id as TLShapeId)
|
|
||||||
if (shapeInEditor) {
|
|
||||||
id: shapeInEditor.id,
|
|
||||||
type: shapeInEditor.type,
|
|
||||||
parentId: shapeInEditor.parentId,
|
|
||||||
pageId: editor.getCurrentPageId(),
|
|
||||||
matches: shapeInEditor.parentId === editor.getCurrentPageId()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug: Log shape parent IDs to see if there's a mismatch
|
|
||||||
if (storeShapes.length > 0 && editorShapes.length === 0) {
|
|
||||||
const parentIdCounts = new Map<string, number>()
|
|
||||||
storeShapes.forEach((s: any) => {
|
|
||||||
const pid = s.parentId || 'no-parent'
|
|
||||||
parentIdCounts.set(pid, (parentIdCounts.get(pid) || 0) + 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// REMOVED: Aggressive force refresh that was causing coordinate loss
|
// REMOVED: Aggressive force refresh that was causing coordinate loss
|
||||||
// If shapes are in store but editor doesn't see them, it's likely a different issue
|
// If shapes are in store but editor doesn't see them, it's likely a different issue
|
||||||
// Forcing refresh by re-putting was resetting coordinates to 0,0
|
// Forcing refresh by re-putting was resetting coordinates to 0,0
|
||||||
|
|
@ -929,11 +887,6 @@ export function Board() {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Board: Error switching to page ${pageWithMostShapes}:`, error)
|
console.error(`❌ Board: Error switching to page ${pageWithMostShapes}:`, error)
|
||||||
}
|
}
|
||||||
} else if (pageWithMostShapes) {
|
|
||||||
pageId,
|
|
||||||
shapeCount: count,
|
|
||||||
isCurrent: pageId === currentPageId
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1428,8 +1381,6 @@ export function Board() {
|
||||||
const isAuthenticated = checkAuthFromStorage();
|
const isAuthenticated = checkAuthFromStorage();
|
||||||
const initialReadOnly = !isAuthenticated;
|
const initialReadOnly = !isAuthenticated;
|
||||||
editor.updateInstanceState({ isReadonly: initialReadOnly })
|
editor.updateInstanceState({ isReadonly: initialReadOnly })
|
||||||
? '🔒 Board is in read-only mode (not authenticated)'
|
|
||||||
: '🔓 Board is editable (authenticated)')
|
|
||||||
|
|
||||||
// Also ensure the current tool is appropriate for the mode
|
// Also ensure the current tool is appropriate for the mode
|
||||||
if (!initialReadOnly) {
|
if (!initialReadOnly) {
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ export class DrawfastShape extends BaseBoxShapeUtil<IDrawfastShape> {
|
||||||
|
|
||||||
getDefaultProps(): IDrawfastShape["props"] {
|
getDefaultProps(): IDrawfastShape["props"] {
|
||||||
return {
|
return {
|
||||||
w: 512,
|
w: 900,
|
||||||
h: 512,
|
h: 500,
|
||||||
prompt: "",
|
prompt: "",
|
||||||
generatedImageUrl: null,
|
generatedImageUrl: null,
|
||||||
overlayMode: true,
|
overlayMode: true,
|
||||||
|
|
@ -160,16 +160,6 @@ export class DrawfastShape extends BaseBoxShapeUtil<IDrawfastShape> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleToggleOverlay = () => {
|
|
||||||
editor.updateShape<IDrawfastShape>({
|
|
||||||
id: shape.id,
|
|
||||||
type: 'Drawfast',
|
|
||||||
props: {
|
|
||||||
overlayMode: !shape.props.overlayMode,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleToggleAutoGenerate = () => {
|
const handleToggleAutoGenerate = () => {
|
||||||
editor.updateShape<IDrawfastShape>({
|
editor.updateShape<IDrawfastShape>({
|
||||||
id: shape.id,
|
id: shape.id,
|
||||||
|
|
@ -361,107 +351,151 @@ export class DrawfastShape extends BaseBoxShapeUtil<IDrawfastShape> {
|
||||||
backgroundColor: '#1a1a2e',
|
backgroundColor: '#1a1a2e',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}>
|
}}>
|
||||||
{/* Drawing Area / Result Display */}
|
{/* Main content area - INPUT and OUTPUT side by side */}
|
||||||
<div style={{
|
<div style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}>
|
}}>
|
||||||
{/* Generated Image (if available and overlay mode) */}
|
{/* INPUT - Drawing Area (Left Side) */}
|
||||||
{shape.props.generatedImageUrl && shape.props.overlayMode && (
|
<div style={{
|
||||||
<img
|
flex: 1,
|
||||||
src={shape.props.generatedImageUrl}
|
position: 'relative',
|
||||||
alt="AI Generated"
|
display: 'flex',
|
||||||
style={{
|
flexDirection: 'column',
|
||||||
position: 'absolute',
|
backgroundColor: '#fff',
|
||||||
top: 0,
|
overflow: 'hidden',
|
||||||
left: 0,
|
borderRight: '2px solid #333',
|
||||||
width: '100%',
|
}}>
|
||||||
height: '100%',
|
{/* INPUT Label */}
|
||||||
objectFit: 'contain',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
opacity: 0.9,
|
|
||||||
zIndex: 10,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Instructions when empty */}
|
|
||||||
{!shape.props.generatedImageUrl && (
|
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'absolute',
|
padding: '4px 8px',
|
||||||
top: '50%',
|
backgroundColor: '#2a2a3e',
|
||||||
left: '50%',
|
color: '#888',
|
||||||
transform: 'translate(-50%, -50%)',
|
fontSize: '10px',
|
||||||
textAlign: 'center',
|
fontWeight: 600,
|
||||||
color: '#666',
|
textTransform: 'uppercase',
|
||||||
fontSize: '14px',
|
letterSpacing: '0.5px',
|
||||||
padding: '20px',
|
borderBottom: '1px solid #333',
|
||||||
pointerEvents: 'none',
|
|
||||||
zIndex: 5,
|
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: '32px', marginBottom: '8px' }}>✏️</div>
|
📝 Input (Draw Here)
|
||||||
<div>Draw inside this frame</div>
|
|
||||||
<div style={{ fontSize: '12px', marginTop: '4px', color: '#999' }}>
|
|
||||||
Use the pencil, pen, or other tools to sketch
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Loading indicator */}
|
{/* Drawing canvas area */}
|
||||||
{(shape.props.isGenerating || liveImageState.isGenerating) && (
|
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'absolute',
|
flex: 1,
|
||||||
top: '50%',
|
position: 'relative',
|
||||||
left: '50%',
|
|
||||||
transform: 'translate(-50%, -50%)',
|
|
||||||
zIndex: 20,
|
|
||||||
backgroundColor: 'rgba(0,0,0,0.7)',
|
|
||||||
padding: '16px 24px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
color: 'white',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: '12px',
|
justifyContent: 'center',
|
||||||
}}>
|
}}>
|
||||||
|
{/* Instructions when empty */}
|
||||||
<div style={{
|
<div style={{
|
||||||
width: 24,
|
position: 'absolute',
|
||||||
height: 24,
|
top: '50%',
|
||||||
border: '3px solid rgba(255,255,255,0.3)',
|
left: '50%',
|
||||||
borderTopColor: DrawfastShape.PRIMARY_COLOR,
|
transform: 'translate(-50%, -50%)',
|
||||||
borderRadius: '50%',
|
textAlign: 'center',
|
||||||
animation: 'spin 1s linear infinite',
|
color: '#666',
|
||||||
}} />
|
fontSize: '14px',
|
||||||
Generating...
|
padding: '20px',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 5,
|
||||||
|
}}>
|
||||||
|
<div style={{ fontSize: '32px', marginBottom: '8px' }}>✏️</div>
|
||||||
|
<div>Draw inside this frame</div>
|
||||||
|
<div style={{ fontSize: '12px', marginTop: '4px', color: '#999' }}>
|
||||||
|
Use the pencil, pen, or other tools to sketch
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Side-by-side result (when not overlay mode) */}
|
|
||||||
{shape.props.generatedImageUrl && !shape.props.overlayMode && (
|
|
||||||
<div style={{
|
|
||||||
height: '40%',
|
|
||||||
borderTop: '2px solid #333',
|
|
||||||
backgroundColor: '#111',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}>
|
|
||||||
<img
|
|
||||||
src={shape.props.generatedImageUrl}
|
|
||||||
alt="AI Generated"
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%',
|
|
||||||
maxHeight: '100%',
|
|
||||||
objectFit: 'contain',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
{/* OUTPUT - Generated Image (Right Side) */}
|
||||||
|
<div style={{
|
||||||
|
flex: 1,
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
backgroundColor: '#111',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}>
|
||||||
|
{/* OUTPUT Label */}
|
||||||
|
<div style={{
|
||||||
|
padding: '4px 8px',
|
||||||
|
backgroundColor: '#2a2a3e',
|
||||||
|
color: '#888',
|
||||||
|
fontSize: '10px',
|
||||||
|
fontWeight: 600,
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
borderBottom: '1px solid #333',
|
||||||
|
}}>
|
||||||
|
✨ Output (AI Generated)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Output content area */}
|
||||||
|
<div style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
position: 'relative',
|
||||||
|
}}>
|
||||||
|
{/* Generated Image */}
|
||||||
|
{shape.props.generatedImageUrl ? (
|
||||||
|
<img
|
||||||
|
src={shape.props.generatedImageUrl}
|
||||||
|
alt="AI Generated"
|
||||||
|
style={{
|
||||||
|
maxWidth: '100%',
|
||||||
|
maxHeight: '100%',
|
||||||
|
objectFit: 'contain',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#555',
|
||||||
|
fontSize: '12px',
|
||||||
|
padding: '20px',
|
||||||
|
}}>
|
||||||
|
<div style={{ fontSize: '24px', marginBottom: '8px', opacity: 0.5 }}>🖼️</div>
|
||||||
|
<div>Generated image will appear here</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Loading indicator */}
|
||||||
|
{(shape.props.isGenerating || liveImageState.isGenerating) && (
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
zIndex: 20,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||||
|
padding: '16px 24px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
color: 'white',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '12px',
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
border: '3px solid rgba(255,255,255,0.3)',
|
||||||
|
borderTopColor: DrawfastShape.PRIMARY_COLOR,
|
||||||
|
borderRadius: '50%',
|
||||||
|
animation: 'spin 1s linear infinite',
|
||||||
|
}} />
|
||||||
|
Generating...
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Controls */}
|
{/* Controls */}
|
||||||
<div style={{
|
<div style={{
|
||||||
|
|
@ -597,23 +631,6 @@ export class DrawfastShape extends BaseBoxShapeUtil<IDrawfastShape> {
|
||||||
/>
|
/>
|
||||||
Real-time
|
Real-time
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Overlay toggle */}
|
|
||||||
<button
|
|
||||||
onClick={handleToggleOverlay}
|
|
||||||
onPointerDown={(e) => e.stopPropagation()}
|
|
||||||
style={{
|
|
||||||
padding: '4px 8px',
|
|
||||||
borderRadius: '4px',
|
|
||||||
border: '1px solid #444',
|
|
||||||
backgroundColor: shape.props.overlayMode ? DrawfastShape.PRIMARY_COLOR : '#2a2a3e',
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: '10px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{shape.props.overlayMode ? 'Overlay' : 'Side-by-side'}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -106,13 +106,6 @@ export class FathomMeetingsBrowserShape extends BaseBoxShapeUtil<IFathomMeetings
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log to verify the correct meeting is being received
|
|
||||||
recording_id: meetingRecordingId,
|
|
||||||
title: meetingTitle,
|
|
||||||
options,
|
|
||||||
fullMeetingObject: meeting
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get API key from user identity
|
// Get API key from user identity
|
||||||
const apiKey = getFathomApiKey(session.username)
|
const apiKey = getFathomApiKey(session.username)
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
|
|
|
||||||
|
|
@ -656,14 +656,6 @@ function MapComponent({ shape, editor, isSelected }: { shape: IMapShape; editor:
|
||||||
);
|
);
|
||||||
const currentCollaboratorIds = new Set(collaboratorsWithLocation.map((c: CollaboratorPresence) => c.id));
|
const currentCollaboratorIds = new Set(collaboratorsWithLocation.map((c: CollaboratorPresence) => c.id));
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
if (collaboratorsWithLocation.length > 0) {
|
|
||||||
total: allCollaborators.length,
|
|
||||||
withLocation: collaboratorsWithLocation.length,
|
|
||||||
users: collaboratorsWithLocation.map(c => ({ id: c.id.slice(0, 8), name: c.name, loc: c.location })),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove old collaborator markers that are no longer sharing
|
// Remove old collaborator markers that are no longer sharing
|
||||||
collaboratorMarkersRef.current.forEach((marker, id) => {
|
collaboratorMarkersRef.current.forEach((marker, id) => {
|
||||||
if (!currentCollaboratorIds.has(id)) {
|
if (!currentCollaboratorIds.has(id)) {
|
||||||
|
|
|
||||||
|
|
@ -231,11 +231,6 @@ export class FathomMeetingsIdle extends StateNode {
|
||||||
// This ensures the shape appears exactly where the user clicked
|
// This ensures the shape appears exactly where the user clicked
|
||||||
const finalX = baseX
|
const finalX = baseX
|
||||||
const finalY = baseY
|
const finalY = baseY
|
||||||
clickPosition: { x: clickX, y: clickY },
|
|
||||||
shapePosition: { x: finalX, y: finalY },
|
|
||||||
shapeSize: { w: shapeWidth, h: shapeHeight }
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const browserShape = this.editor.createShape({
|
const browserShape = this.editor.createShape({
|
||||||
type: 'FathomMeetingsBrowser',
|
type: 'FathomMeetingsBrowser',
|
||||||
|
|
|
||||||
|
|
@ -179,23 +179,8 @@ export class HolonIdle extends StateNode {
|
||||||
|
|
||||||
// ALWAYS use click position directly when provided - user clicked where they want it
|
// ALWAYS use click position directly when provided - user clicked where they want it
|
||||||
// Skip collision detection entirely for user clicks to ensure it appears exactly where clicked
|
// Skip collision detection entirely for user clicks to ensure it appears exactly where clicked
|
||||||
let finalX = baseX
|
const finalX = baseX
|
||||||
let finalY = baseY
|
const finalY = baseY
|
||||||
|
|
||||||
if (clickX !== undefined && clickY !== undefined) {
|
|
||||||
// User clicked - ALWAYS use that exact position, no collision detection
|
|
||||||
// This ensures the shape appears exactly where the user clicked
|
|
||||||
finalX = baseX
|
|
||||||
finalY = baseY
|
|
||||||
clickPosition: { x: clickX, y: clickY },
|
|
||||||
shapePosition: { x: finalX, y: finalY },
|
|
||||||
shapeSize: { w: shapeWidth, h: shapeHeight }
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// For fallback (no click), use base position directly
|
|
||||||
finalX = baseX
|
|
||||||
finalY = baseY
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default coordinates (can be changed by user)
|
// Default coordinates (can be changed by user)
|
||||||
const defaultLat = 40.7128 // NYC
|
const defaultLat = 40.7128 // NYC
|
||||||
|
|
|
||||||
|
|
@ -480,7 +480,7 @@ export const overrides: TLUiOverrides = {
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
try {
|
try {
|
||||||
// Create a simple modal/prompt for AI response
|
// Create a simple modal/prompt for AI response
|
||||||
const answer = await askCanvasAI(editor, undefined, (partial, done) => {
|
const answer = await askCanvasAI(editor, undefined, (_partial, done) => {
|
||||||
// Log streaming response to console for now
|
// Log streaming response to console for now
|
||||||
if (!done) {
|
if (!done) {
|
||||||
}
|
}
|
||||||
|
|
@ -500,7 +500,7 @@ export const overrides: TLUiOverrides = {
|
||||||
readonlyOk: true,
|
readonlyOk: true,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
try {
|
try {
|
||||||
await indexCanvasForSearch(editor, (progress) => {
|
await indexCanvasForSearch(editor, (_progress) => {
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Canvas indexing error:", error)
|
console.error("Canvas indexing error:", error)
|
||||||
|
|
@ -514,7 +514,7 @@ export const overrides: TLUiOverrides = {
|
||||||
readonlyOk: true,
|
readonlyOk: true,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
try {
|
try {
|
||||||
await explainViewport(editor, (partial, done) => {
|
await explainViewport(editor, (_partial, done) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue