Skip to content

Commit

Permalink
Merge pull request #124 from zetkin/issue-25/data-access-layer
Browse files Browse the repository at this point in the history
Extract data access layer
  • Loading branch information
WULCAN authored Aug 21, 2024
2 parents a915370 + 034bc7e commit 0159801
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 64 deletions.
51 changes: 18 additions & 33 deletions webapp/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Cache } from '@/Cache';
import { accessProjects } from '@/dataAccess';
import { Promises } from '@/utils/Promises';
import HomeDashboard from '@/components/HomeDashboard';
import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory';
import { ProjectCardProps } from '@/components/ProjectCard';
import { RepoGit } from '@/RepoGit';
import { ServerConfig } from '@/utils/serverConfig';

// Force dynamic rendering for this page. By default Next.js attempts to render
// this page statically. That means that it tries to render the page at build
Expand All @@ -19,39 +16,27 @@ import { ServerConfig } from '@/utils/serverConfig';
export const dynamic = 'force-dynamic';

export default async function Home() {
const serverConfig = await ServerConfig.read();
const projects = await Promise.all(
serverConfig.projects.map<Promise<ProjectCardProps>>(async (project) => {
await RepoGit.cloneIfNotExist(project);
const repoGit = await RepoGit.getRepoGit(project);
const lyraConfig = await repoGit.getLyraConfig();
const projectConfig = lyraConfig.getProjectConfigByPath(
project.projectPath,
);
const msgAdapter = MessageAdapterFactory.createAdapter(projectConfig);
const messages = await msgAdapter.getMessages();
const store = await Cache.getProjectStore(projectConfig);
const languages = await Promise.all(
projectConfig.languages.map(async (lang) => {
const translations = await store.getTranslations(lang);
return {
href: `/projects/${project.name}/${lang}`,
language: lang,
progress: translations
? (Object.keys(translations).length / messages.length) * 100
: 0,
};
}),
);
const projectData = await accessProjects();
const projects = await Promises.of(projectData)
.map(async ({ name, messages, languagesWithTranslations }) => {
const languages = await Promises.of(languagesWithTranslations)
.map(({ lang, translations }) => ({
href: `/projects/${name}/${lang}`,
language: lang,
progress: translations
? (Object.keys(translations).length / messages.length) * 100
: 0,
}))
.all();

return {
href: `/projects/${project.name}`,
href: `/projects/${name}`,
languages,
messageCount: messages.length,
name: project.name,
name,
};
}),
);
})
.all();

return <HomeDashboard projects={projects} />;
}
46 changes: 15 additions & 31 deletions webapp/src/app/projects/[projectName]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,34 @@
import { NextPage } from 'next';
import { notFound } from 'next/navigation';

import { Cache } from '@/Cache';
import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory';
import { accessProject } from '@/dataAccess';
import { Promises } from '@/utils/Promises';
import ProjectDashboard from '@/components/ProjectDashboard';
import { RepoGit } from '@/RepoGit';
import { ServerConfig } from '@/utils/serverConfig';

const ProjectPage: NextPage<{
params: { projectName: string };
}> = async ({ params }) => {
const serverConfig = await ServerConfig.read();
const project = serverConfig.projects.find(
(project) => project.name === params.projectName,
);

const project = await accessProject(params.projectName);
if (!project) {
return notFound();
}

await RepoGit.cloneIfNotExist(project);
const repoGit = await RepoGit.getRepoGit(project);
const lyraConfig = await repoGit.getLyraConfig();
const projectConfig = lyraConfig.getProjectConfigByPath(project.projectPath);
const msgAdapter = MessageAdapterFactory.createAdapter(projectConfig);
const messages = await msgAdapter.getMessages();
const store = await Cache.getProjectStore(projectConfig);
const languages = await Promise.all(
projectConfig.languages.map(async (lang) => {
const translations = await store.getTranslations(lang);
return {
href: `/projects/${project.name}/${lang}`,
language: lang,
messagesLeft: messages.length - Object.keys(translations).length,
progress: translations
? (Object.keys(translations).length / messages.length) * 100
: 0,
};
}),
);
const { name, messages, languagesWithTranslations } = project;
const languages = await Promises.of(languagesWithTranslations)
.map(({ lang, translations }) => ({
href: `/projects/${name}/${lang}`,
language: lang,
messagesLeft: messages.length - Object.keys(translations).length,
progress: translations
? (Object.keys(translations).length / messages.length) * 100
: 0,
}))
.all();

return (
<ProjectDashboard
languages={languages}
messageCount={messages.length}
project={project.name}
project={name}
/>
);
};
Expand Down
41 changes: 41 additions & 0 deletions webapp/src/dataAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Cache } from '@/Cache';
import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory';
import { RepoGit } from '@/RepoGit';
import { ServerConfig, ServerProjectConfig } from '@/utils/serverConfig';

export async function accessProjects() {
const serverConfig = await ServerConfig.read();
return serverConfig.projects.map(async (project) => {
return await readProject(project);
});
}

export async function accessProject(name: string) {
const serverConfig = await ServerConfig.read();
const project = serverConfig.projects.find(
(project) => project.name === name,
);

if (!project) {
return null;
}

return readProject(project);
}

async function readProject(project: ServerProjectConfig) {
await RepoGit.cloneIfNotExist(project);
const repoGit = await RepoGit.getRepoGit(project);
const lyraConfig = await repoGit.getLyraConfig();
const projectConfig = lyraConfig.getProjectConfigByPath(project.projectPath);
const msgAdapter = MessageAdapterFactory.createAdapter(projectConfig);
const messages = await msgAdapter.getMessages();
const store = await Cache.getProjectStore(projectConfig);
const languagesWithTranslations = projectConfig.languages.map(
async (lang) => {
const translations = await store.getTranslations(lang);
return { lang, translations };
},
);
return { languagesWithTranslations, messages, name: project.name };
}
15 changes: 15 additions & 0 deletions webapp/src/utils/Promises.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class Promises<T> {
private constructor(private array: Array<Promise<T>>) {}

static of<T>(array: Array<Promise<T>>) {
return new Promises(array);
}

map<U>(callbackFn: (value: T) => U | Promise<U>): Promises<U> {
return new Promises(this.array.map((p) => p.then(callbackFn)));
}

all() {
return Promise.all(this.array);
}
}

0 comments on commit 0159801

Please sign in to comment.