diff --git a/packages/noodl-editor/src/editor/src/utils/LocalProjectsModel.ts b/packages/noodl-editor/src/editor/src/utils/LocalProjectsModel.ts index 244549d..3f92d33 100644 --- a/packages/noodl-editor/src/editor/src/utils/LocalProjectsModel.ts +++ b/packages/noodl-editor/src/editor/src/utils/LocalProjectsModel.ts @@ -16,6 +16,7 @@ import { projectFromDirectory, unzipIntoDirectory } from '../models/projectmodel import FileSystem from './filesystem'; import { tracker } from './tracker'; import { guid } from './utils'; +import { getTopLevelWorkingDirectory } from '@noodl/git/src/core/open'; export interface ProjectItem { id: string; @@ -267,12 +268,15 @@ export class LocalProjectsModel extends Model { }); } - isGitProject(project: ProjectModel): boolean { - // TODO: check if there's is git in any parent folder too - - // Check if the git folder exists. - const gitPath = filesystem.join(project._retainedProjectDirectory, '.git'); - return filesystem.exists(gitPath); + /** + * Check if this project is in a git repository. + * + * @param project + * @returns + */ + async isGitProject(project: ProjectModel): Promise { + const gitPath = await getTopLevelWorkingDirectory(project._retainedProjectDirectory); + return gitPath !== null; } setCurrentGlobalGitAuth(projectId: string) { diff --git a/packages/noodl-editor/src/editor/src/utils/projectmerger.diff.ts b/packages/noodl-editor/src/editor/src/utils/projectmerger.diff.ts index 4f32005..c5df4d2 100644 --- a/packages/noodl-editor/src/editor/src/utils/projectmerger.diff.ts +++ b/packages/noodl-editor/src/editor/src/utils/projectmerger.diff.ts @@ -11,6 +11,14 @@ export interface ArrayDiff { changed: T[]; unchanged: T[]; } +export function createEmptyArrayDiff(): ArrayDiff { + return { + deleted: [], + created: [], + changed: [], + unchanged: [], + } +} export interface ProjectDiffItem { graph: TSFixme; diff --git a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/VersionControlPanel.tsx b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/VersionControlPanel.tsx index a5a5854..1e84528 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/VersionControlPanel.tsx +++ b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/VersionControlPanel.tsx @@ -199,6 +199,7 @@ function BaseVersionControlPanel() { export function VersionControlPanel() { const [git, setGit] = useState(null); + const [state, setState] = useState<'loading' | 'loaded' | 'not-git'>('loading'); async function createGit() { const gitClient = new Git(mergeProject); @@ -206,12 +207,18 @@ export function VersionControlPanel() { setGit(gitClient); } - const isGitProject = git === null ? LocalProjectsModel.instance.isGitProject(ProjectModel.instance) : true; useEffect(() => { - if (isGitProject) { - createGit(); - } - }, [isGitProject]); + LocalProjectsModel.instance + .isGitProject(ProjectModel.instance) + .then(async (isGitProject) => { + if (isGitProject) { + await createGit(); + setState('loaded'); + } else { + setState('not-git'); + } + }); + }, []); async function setupGit() { const gitClient = new Git(mergeProject); @@ -220,7 +227,7 @@ export function VersionControlPanel() { setGit(gitClient); } - if (git === null && !isGitProject) { + if (git === null && state === 'not-git') { return ( diff --git a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/CommitChangesDiff.tsx b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/CommitChangesDiff.tsx index 3b5f6d9..5f4b8a0 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/CommitChangesDiff.tsx +++ b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/CommitChangesDiff.tsx @@ -6,11 +6,13 @@ import { Commit } from '@noodl/git/src/core/models/snapshot'; import { FileChange } from '@noodl/git/src/core/models/status'; import { revRange } from '@noodl/git/src/core/rev-list'; +import { ProjectModel } from '@noodl-models/projectmodel'; import { applyPatches } from '@noodl-models/ProjectPatches/applypatches'; import { mergeProject } from '@noodl-utils/projectmerger'; import { ProjectDiff, diffProject } from '@noodl-utils/projectmerger.diff'; import { useVersionControlContext } from '../context'; +import { getProjectFilePath } from '../context/DiffUtils'; import { DiffList } from './DiffList'; //Kind: @@ -124,7 +126,10 @@ async function getMergeDiff(repositoryPath: string, commit: Commit, refToDiffTo: } async function getProjectFile(commit: Commit) { - const projectContent = JSON.parse(await commit.getFileAsString('project.json')); + const projectFilePath = getProjectFilePath(commit.repositoryDir, ProjectModel.instance._retainedProjectDirectory); + + const projectContentRaw = await commit.getFileAsString(projectFilePath); + const projectContent = JSON.parse(projectContentRaw); applyPatches(projectContent); return projectContent; } diff --git a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/DiffList.tsx b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/DiffList.tsx index 106f9e7..e8c5429 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/DiffList.tsx +++ b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/DiffList.tsx @@ -61,7 +61,7 @@ export function DiffList({ diff, fileChanges, componentDiffTitle, actions, commi const [imageDiff, setImageDiff] = useState(null); const components = diff?.components ? getChangedComponents(diff.components) : []; - const files = (fileChanges || [])?.filter((f) => f.path !== 'project.json') || []; + const files = (fileChanges || [])?.filter((f) => !f.path.endsWith('project.json')) || []; const settings = diff?.settings ? getChangedObjectProperties(diff.settings) : []; const colorStyles = diff?.styles.colors ? getChangedObjectProperties(diff.styles.colors) : []; const textStyles = diff?.styles.text ? getChangedObjectProperties(diff.styles.text) : []; diff --git a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/DiffUtils.ts b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/DiffUtils.ts index cd7dc8e..08f0729 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/DiffUtils.ts +++ b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/DiffUtils.ts @@ -1,21 +1,24 @@ +import path from 'path'; +import { getCommit } from '@noodl/git/src/core/logs'; +import { FileStatusKind } from '@noodl/git/src/core/models/status'; + +import { FeedbackType } from '@noodl-constants/FeedbackType'; +import { applyPatches } from '@noodl-models/ProjectPatches/applypatches'; import { ProjectDiff, ProjectDiffItem, ProjectBasicDiffItem, ArrayDiff, - diffProject + diffProject, + createEmptyArrayDiff } from '@noodl-utils/projectmerger.diff'; +import { IconName } from '@noodl-core-ui/components/common/Icon'; +import { ListItemProps } from '@noodl-core-ui/components/layout/ListItem'; + import { ProjectModel } from '../../../../models/projectmodel'; -import { applyPatches } from '@noodl-models/ProjectPatches/applypatches'; -import { FileStatusKind } from '@noodl/git/src/core/models/status'; -import { IconName } from '@noodl-core-ui/components/common/Icon'; -import { ListItemProps } from '@noodl-core-ui/components/layout/ListItem'; -import { FeedbackType } from '@noodl-constants/FeedbackType'; -import { getCommit } from '@noodl/git/src/core/logs'; - -export interface ProjectLocalDiff extends ProjectDiff{ +export interface ProjectLocalDiff extends ProjectDiff { baseProject: TSFixme; //Project model as an object from raw json commitShaDiffedTo: string; } @@ -84,17 +87,49 @@ export function getFileStatusIconProps(status: FileStatusKind): Partial { - const baseCommit = await getCommit(repositoryPath, headCommitId); - const baseProjectJson = await baseCommit.getFileAsString('project.json'); - const baseProject = JSON.parse(baseProjectJson); - applyPatches(baseProject); - - const diff = diffProject(baseProject, ProjectModel.instance.toJSON()); - - return { - ...diff, - baseProject, - commitShaDiffedTo: headCommitId - }; +export function getProjectFilePath(repositoryPath: string, projectPath: string) { + const relativePath = path.relative(repositoryPath, projectPath); + const projectFilePath = path.join(relativePath, 'project.json').replaceAll('\\', '/'); + return projectFilePath; +} + +export async function doLocalDiff( + repositoryPath: string, + projectPath: string, + headCommitId: string +): Promise { + const projectFilePath = getProjectFilePath(repositoryPath, projectPath); + + try { + const baseCommit = await getCommit(projectPath, headCommitId); + const baseProjectJson = await baseCommit.getFileAsString(projectFilePath); + const baseProject = JSON.parse(baseProjectJson); + applyPatches(baseProject); + + const diff = diffProject(baseProject, ProjectModel.instance.toJSON()); + + return { + ...diff, + baseProject, + commitShaDiffedTo: headCommitId + }; + } catch (error) { + if (error.toString().includes('exists on disk, but not in')) { + console.warn('project.json does not exist in this commit.'); + } + + // Return empty state + return { + baseProject: {}, + commitShaDiffedTo: headCommitId, + components: createEmptyArrayDiff(), + variants: createEmptyArrayDiff(), + settings: createEmptyArrayDiff(), + styles: { + colors: createEmptyArrayDiff(), + text: createEmptyArrayDiff() + }, + cloudservices: createEmptyArrayDiff() + }; + } } diff --git a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/index.tsx b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/index.tsx index f3da908..143c0f5 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/index.tsx +++ b/packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/context/index.tsx @@ -8,6 +8,7 @@ import { Slot } from '@noodl-core-ui/types/global'; import { doLocalDiff, ProjectLocalDiff } from './DiffUtils'; import { useVersionControlFetch } from './fetch.context'; import { BranchStatus, IVersionControlContext } from './types'; +import { ProjectModel } from '@noodl-models/projectmodel'; const VersionControlContext = createContext({ git: null, @@ -57,7 +58,8 @@ export function VersionControlProvider({ git, children }: { git: Git; children: (async () => { const currentCommitSha = await git.getHeadCommitId(); if (currentCommitSha) { - const diff = await doLocalDiff(git.repositoryPath, currentCommitSha); + const projectPath = ProjectModel.instance._retainedProjectDirectory; + const diff = await doLocalDiff(git.repositoryPath, projectPath, currentCommitSha); setLocalDiff(diff); } })(); diff --git a/packages/noodl-git/src/core/open.ts b/packages/noodl-git/src/core/open.ts index ef45600..4dedee2 100644 --- a/packages/noodl-git/src/core/open.ts +++ b/packages/noodl-git/src/core/open.ts @@ -22,7 +22,11 @@ export async function open(basePath: string): Promise { // console.log("VCS error when opening project: " + e); // } - return basePath; + + // Find the relative git repository path + const repositoryPath = await getTopLevelWorkingDirectory(basePath); + + return repositoryPath; } /**