mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 02:33:01 +00:00
frontend server utility improvement
This commit is contained in:
@@ -20,12 +20,12 @@ const main = async () => {
|
|||||||
"/issue/create": withCors(withAuth(routes.issueCreate)),
|
"/issue/create": withCors(withAuth(routes.issueCreate)),
|
||||||
"/issue/update": withCors(withAuth(routes.issueUpdate)),
|
"/issue/update": withCors(withAuth(routes.issueUpdate)),
|
||||||
"/issue/delete": withCors(withAuth(routes.issueDelete)),
|
"/issue/delete": withCors(withAuth(routes.issueDelete)),
|
||||||
"/issues/:projectKey": withCors(withAuth(routes.issuesInProject)),
|
"/issues/by-project": withCors(withAuth(routes.issuesByProject)),
|
||||||
"/issues/all": withCors(withAuth(routes.issues)),
|
"/issues/all": withCors(withAuth(routes.issues)),
|
||||||
|
|
||||||
"/organisation/create": withCors(withAuth(routes.organisationCreate)),
|
"/organisation/create": withCors(withAuth(routes.organisationCreate)),
|
||||||
"/organisation/by-id": withCors(withAuth(routes.organisationById)),
|
"/organisation/by-id": withCors(withAuth(routes.organisationById)),
|
||||||
"/organisation/by-user": withCors(withAuth(routes.organisationByUser)),
|
"/organisations/by-user": withCors(withAuth(routes.organisationByUser)),
|
||||||
"/organisation/update": withCors(withAuth(routes.organisationUpdate)),
|
"/organisation/update": withCors(withAuth(routes.organisationUpdate)),
|
||||||
"/organisation/delete": withCors(withAuth(routes.organisationDelete)),
|
"/organisation/delete": withCors(withAuth(routes.organisationDelete)),
|
||||||
"/organisation/add-member": withCors(withAuth(routes.organisationAddMember)),
|
"/organisation/add-member": withCors(withAuth(routes.organisationAddMember)),
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import authRegister from "./auth/register";
|
|||||||
import issueCreate from "./issue/create";
|
import issueCreate from "./issue/create";
|
||||||
import issueDelete from "./issue/delete";
|
import issueDelete from "./issue/delete";
|
||||||
import issueUpdate from "./issue/update";
|
import issueUpdate from "./issue/update";
|
||||||
import issuesInProject from "./issues/[projectKey]";
|
|
||||||
import issues from "./issues/all";
|
import issues from "./issues/all";
|
||||||
|
import issuesByProject from "./issues/by-project";
|
||||||
import organisationAddMember from "./organisation/add-member";
|
import organisationAddMember from "./organisation/add-member";
|
||||||
import organisationById from "./organisation/by-id";
|
import organisationById from "./organisation/by-id";
|
||||||
import organisationByUser from "./organisation/by-user";
|
import organisationByUser from "./organisation/by-user";
|
||||||
@@ -29,7 +29,7 @@ export const routes = {
|
|||||||
issueDelete,
|
issueDelete,
|
||||||
issueUpdate,
|
issueUpdate,
|
||||||
|
|
||||||
issuesInProject,
|
issuesByProject,
|
||||||
issues,
|
issues,
|
||||||
|
|
||||||
organisationCreate,
|
organisationCreate,
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import type { BunRequest } from "bun";
|
|
||||||
import { getIssuesWithAssigneeByProject, getProjectByKey } from "../../db/queries";
|
|
||||||
|
|
||||||
export default async function issuesInProject(req: BunRequest<"/issues/:projectKey">) {
|
|
||||||
const { projectKey } = req.params;
|
|
||||||
|
|
||||||
const project = await getProjectByKey(projectKey);
|
|
||||||
if (!project) {
|
|
||||||
return new Response(`project not found: provided ${projectKey}`, { status: 404 });
|
|
||||||
}
|
|
||||||
const issues = await getIssuesWithAssigneeByProject(project.id);
|
|
||||||
|
|
||||||
return Response.json(issues);
|
|
||||||
}
|
|
||||||
15
packages/backend/src/routes/issues/by-project.ts
Normal file
15
packages/backend/src/routes/issues/by-project.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import type { AuthedRequest } from "../../auth/middleware";
|
||||||
|
import { getIssuesWithAssigneeByProject, getProjectByID } from "../../db/queries";
|
||||||
|
|
||||||
|
export default async function issuesByProject(req: AuthedRequest) {
|
||||||
|
const url = new URL(req.url);
|
||||||
|
const projectId = url.searchParams.get("projectId");
|
||||||
|
|
||||||
|
const project = await getProjectByID(Number(projectId));
|
||||||
|
if (!project) {
|
||||||
|
return new Response(`project not found: provided ${projectId}`, { status: 404 });
|
||||||
|
}
|
||||||
|
const issues = await getIssuesWithAssigneeByProject(project.id);
|
||||||
|
|
||||||
|
return Response.json(issues);
|
||||||
|
}
|
||||||
@@ -17,8 +17,9 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { ResizablePanel, ResizablePanelGroup, ResizableSeparator } from "@/components/ui/resizable";
|
||||||
|
import { issue, organisation, project } from "@/lib/server";
|
||||||
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
import { ResizablePanel, ResizablePanelGroup, ResizableSeparator } from "./components/ui/resizable";
|
|
||||||
|
|
||||||
function Index() {
|
function Index() {
|
||||||
const user = JSON.parse(localStorage.getItem("user") || "{}") as UserRecord;
|
const user = JSON.parse(localStorage.getItem("user") || "{}") as UserRecord;
|
||||||
@@ -35,16 +36,17 @@ function Index() {
|
|||||||
|
|
||||||
const refetchOrganisations = async (options?: { selectOrganisationId?: number }) => {
|
const refetchOrganisations = async (options?: { selectOrganisationId?: number }) => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${getServerURL()}/organisation/by-user?userId=${user.id}`, {
|
await organisation.byUser({
|
||||||
headers: getAuthHeaders(),
|
userId: user.id,
|
||||||
});
|
onSuccess: (data) => {
|
||||||
const data = (await res.json()) as Array<OrganisationResponse>;
|
const organisations = data as OrganisationResponse[];
|
||||||
|
setOrganisations(organisations);
|
||||||
setOrganisations(data);
|
|
||||||
|
|
||||||
// select newly created organisation
|
// select newly created organisation
|
||||||
if (options?.selectOrganisationId) {
|
if (options?.selectOrganisationId) {
|
||||||
const created = data.find((o) => o.Organisation.id === options.selectOrganisationId);
|
const created = organisations.find(
|
||||||
|
(o) => o.Organisation.id === options.selectOrganisationId,
|
||||||
|
);
|
||||||
if (created) {
|
if (created) {
|
||||||
setSelectedOrganisation(created);
|
setSelectedOrganisation(created);
|
||||||
return;
|
return;
|
||||||
@@ -53,9 +55,16 @@ function Index() {
|
|||||||
|
|
||||||
// preserve previously selected organisation
|
// preserve previously selected organisation
|
||||||
setSelectedOrganisation((prev) => {
|
setSelectedOrganisation((prev) => {
|
||||||
if (!prev) return data[0] || null;
|
if (!prev) return organisations[0] || null;
|
||||||
const stillExists = data.find((o) => o.Organisation.id === prev.Organisation.id);
|
const stillExists = organisations.find(
|
||||||
return stillExists || data[0] || null;
|
(o) => o.Organisation.id === prev.Organisation.id,
|
||||||
|
);
|
||||||
|
return stillExists || organisations[0] || null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error("error fetching organisations:", error);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("error fetching organisations:", err);
|
console.error("error fetching organisations:", err);
|
||||||
@@ -74,19 +83,15 @@ function Index() {
|
|||||||
|
|
||||||
const refetchProjects = async (organisationId: number, options?: { selectProjectId?: number }) => {
|
const refetchProjects = async (organisationId: number, options?: { selectProjectId?: number }) => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
await project.byOrganisation({
|
||||||
`${getServerURL()}/projects/by-organisation?organisationId=${organisationId}`,
|
organisationId,
|
||||||
{
|
onSuccess: (data) => {
|
||||||
headers: getAuthHeaders(),
|
const projects = data as ProjectResponse[];
|
||||||
},
|
setProjects(projects);
|
||||||
);
|
|
||||||
|
|
||||||
const data = (await res.json()) as ProjectResponse[];
|
|
||||||
setProjects(data);
|
|
||||||
|
|
||||||
// select newly created project
|
// select newly created project
|
||||||
if (options?.selectProjectId) {
|
if (options?.selectProjectId) {
|
||||||
const created = data.find((p) => p.Project.id === options.selectProjectId);
|
const created = projects.find((p) => p.Project.id === options.selectProjectId);
|
||||||
if (created) {
|
if (created) {
|
||||||
setSelectedProject(created);
|
setSelectedProject(created);
|
||||||
return;
|
return;
|
||||||
@@ -95,9 +100,14 @@ function Index() {
|
|||||||
|
|
||||||
// preserve previously selected project
|
// preserve previously selected project
|
||||||
setSelectedProject((prev) => {
|
setSelectedProject((prev) => {
|
||||||
if (!prev) return data[0] || null;
|
if (!prev) return projects[0] || null;
|
||||||
const stillExists = data.find((p) => p.Project.id === prev.Project.id);
|
const stillExists = projects.find((p) => p.Project.id === prev.Project.id);
|
||||||
return stillExists || data[0] || null;
|
return stillExists || projects[0] || null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error("error fetching projects:", error);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("error fetching projects:", err);
|
console.error("error fetching projects:", err);
|
||||||
@@ -124,11 +134,17 @@ function Index() {
|
|||||||
|
|
||||||
const refetchIssues = async (projectKey: string) => {
|
const refetchIssues = async (projectKey: string) => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${getServerURL()}/issues/${projectKey}`, {
|
await issue.byProject({
|
||||||
headers: getAuthHeaders(),
|
projectId: selectedProject?.Project.id || 0,
|
||||||
|
onSuccess: (data) => {
|
||||||
|
const issues = data as IssueResponse[];
|
||||||
|
setIssues(issues);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error("error fetching issues:", error);
|
||||||
|
setIssues([]);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const data = (await res.json()) as IssueResponse[];
|
|
||||||
setIssues(data);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("error fetching issues:", err);
|
console.error("error fetching issues:", err);
|
||||||
setIssues([]);
|
setIssues([]);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { OrganisationResponse, UserRecord } from "@issue/shared";
|
|||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { OrganisationSelect } from "@/components/organisation-select";
|
import { OrganisationSelect } from "@/components/organisation-select";
|
||||||
import { SettingsPageLayout } from "@/components/settings-page-layout";
|
import { SettingsPageLayout } from "@/components/settings-page-layout";
|
||||||
|
import { organisation } from "@/lib/server";
|
||||||
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
|
||||||
function Organisations() {
|
function Organisations() {
|
||||||
@@ -13,22 +14,16 @@ function Organisations() {
|
|||||||
const refetchOrganisations = useCallback(
|
const refetchOrganisations = useCallback(
|
||||||
async (options?: { selectOrganisationId?: number }) => {
|
async (options?: { selectOrganisationId?: number }) => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${getServerURL()}/organisation/by-user?userId=${user.id}`, {
|
await organisation.byUser({
|
||||||
headers: getAuthHeaders(),
|
userId: user.id,
|
||||||
});
|
onSuccess: (data) => {
|
||||||
|
const organisations = data as OrganisationResponse[];
|
||||||
if (!res.ok) {
|
setOrganisations(organisations);
|
||||||
console.error(await res.text());
|
|
||||||
setOrganisations([]);
|
|
||||||
setSelectedOrganisation(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = (await res.json()) as Array<OrganisationResponse>;
|
|
||||||
setOrganisations(data);
|
|
||||||
|
|
||||||
if (options?.selectOrganisationId) {
|
if (options?.selectOrganisationId) {
|
||||||
const created = data.find((o) => o.Organisation.id === options.selectOrganisationId);
|
const created = organisations.find(
|
||||||
|
(o) => o.Organisation.id === options.selectOrganisationId,
|
||||||
|
);
|
||||||
if (created) {
|
if (created) {
|
||||||
setSelectedOrganisation(created);
|
setSelectedOrganisation(created);
|
||||||
return;
|
return;
|
||||||
@@ -36,9 +31,18 @@ function Organisations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOrganisation((prev) => {
|
setSelectedOrganisation((prev) => {
|
||||||
if (!prev) return data[0] || null;
|
if (!prev) return organisations[0] || null;
|
||||||
const stillExists = data.find((o) => o.Organisation.id === prev.Organisation.id);
|
const stillExists = organisations.find(
|
||||||
return stillExists || data[0] || null;
|
(o) => o.Organisation.id === prev.Organisation.id,
|
||||||
|
);
|
||||||
|
return stillExists || organisations[0] || null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error(error);
|
||||||
|
setOrganisations([]);
|
||||||
|
setSelectedOrganisation(null);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("error fetching organisations:", err);
|
console.error("error fetching organisations:", err);
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { cn, getAuthHeaders, getServerURL } from "@/lib/utils";
|
import { issue } from "@/lib/server";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export function CreateIssue({
|
export function CreateIssue({
|
||||||
projectId,
|
projectId,
|
||||||
@@ -88,36 +89,24 @@ export function CreateIssue({
|
|||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = new URL(`${getServerURL()}/issue/create`);
|
await issue.create({
|
||||||
url.searchParams.set("projectId", `${projectId}`);
|
projectId,
|
||||||
url.searchParams.set("title", title.trim());
|
title,
|
||||||
url.searchParams.set("description", description.trim());
|
description,
|
||||||
|
onSuccess: async (data) => {
|
||||||
const res = await fetch(url.toString(), {
|
|
||||||
headers: getAuthHeaders(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const message = await res.text();
|
|
||||||
setError(message || `failed to create issue (${res.status})`);
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const issue = (await res.json()) as { id?: number };
|
|
||||||
if (!issue.id) {
|
|
||||||
setError("failed to create issue");
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
reset();
|
reset();
|
||||||
try {
|
try {
|
||||||
await completeAction?.(issue.id);
|
await completeAction?.(data.id);
|
||||||
} catch (actionErr) {
|
} catch (actionErr) {
|
||||||
console.error(actionErr);
|
console.error(actionErr);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onError: (message) => {
|
||||||
|
setError(message);
|
||||||
|
setSubmitting(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setError("failed to create issue");
|
setError("failed to create issue");
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { cn, getAuthHeaders, getServerURL } from "@/lib/utils";
|
import { organisation } from "@/lib/server";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const slugify = (value: string) =>
|
const slugify = (value: string) =>
|
||||||
value
|
value
|
||||||
@@ -88,39 +89,25 @@ export function CreateOrganisation({
|
|||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const url = new URL(`${getServerURL()}/organisation/create`);
|
await organisation.create({
|
||||||
url.searchParams.set("name", name.trim());
|
name,
|
||||||
url.searchParams.set("slug", slug.trim());
|
slug,
|
||||||
url.searchParams.set("userId", `${userId}`);
|
description,
|
||||||
if (description.trim() !== "") {
|
userId,
|
||||||
url.searchParams.set("description", description.trim());
|
onSuccess: async (data) => {
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
|
||||||
headers: getAuthHeaders(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const message = await res.text();
|
|
||||||
setError(message || `failed to create organisation (${res.status})`);
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const organisation = (await res.json()) as { id?: number };
|
|
||||||
if (!organisation.id) {
|
|
||||||
setError("failed to create organisation");
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
reset();
|
reset();
|
||||||
try {
|
try {
|
||||||
await completeAction?.(organisation.id);
|
await completeAction?.(data.id);
|
||||||
} catch (actionErr) {
|
} catch (actionErr) {
|
||||||
console.error(actionErr);
|
console.error(actionErr);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
setError(err || "failed to create organisation");
|
||||||
|
setSubmitting(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setError("failed to create organisation");
|
setError("failed to create organisation");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { ProjectRecord } from "@issue/shared";
|
||||||
import { type FormEvent, useMemo, useState } from "react";
|
import { type FormEvent, useMemo, useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -10,7 +11,8 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { cn, getAuthHeaders, getServerURL } from "@/lib/utils";
|
import { project } from "@/lib/server";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const keyify = (value: string) =>
|
const keyify = (value: string) =>
|
||||||
value
|
value
|
||||||
@@ -94,29 +96,13 @@ export function CreateProject({
|
|||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const url = new URL(`${getServerURL()}/project/create`);
|
await project.create({
|
||||||
url.searchParams.set("key", key);
|
key,
|
||||||
url.searchParams.set("name", name.trim());
|
name,
|
||||||
url.searchParams.set("creatorId", `${userId}`);
|
creatorId: userId,
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
organisationId,
|
||||||
|
onSuccess: async (data) => {
|
||||||
const res = await fetch(url.toString(), {
|
const project = data as ProjectRecord;
|
||||||
headers: getAuthHeaders(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const message = await res.text();
|
|
||||||
setError(message || `failed to create project (${res.status})`);
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const project = (await res.json()) as { id?: number };
|
|
||||||
if (!project.id) {
|
|
||||||
setError("failed to create project");
|
|
||||||
setSubmitting(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
reset();
|
reset();
|
||||||
@@ -125,6 +111,12 @@ export function CreateProject({
|
|||||||
} catch (actionErr) {
|
} catch (actionErr) {
|
||||||
console.error(actionErr);
|
console.error(actionErr);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onError: (message) => {
|
||||||
|
setError(message);
|
||||||
|
setSubmitting(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setError("failed to create project");
|
setError("failed to create project");
|
||||||
|
|||||||
8
packages/frontend/src/lib/server/index.ts
Normal file
8
packages/frontend/src/lib/server/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export * as issue from "./issue";
|
||||||
|
export * as organisation from "./organisation";
|
||||||
|
export * as project from "./project";
|
||||||
|
|
||||||
|
export type ServerQueryInput = {
|
||||||
|
onSuccess?: (data: any, res: Response) => void;
|
||||||
|
onError?: (error: any) => void;
|
||||||
|
};
|
||||||
26
packages/frontend/src/lib/server/issue/byProject.ts
Normal file
26
packages/frontend/src/lib/server/issue/byProject.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function byProject({
|
||||||
|
projectId,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
projectId: number;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/issues/by-project`);
|
||||||
|
url.searchParams.set("projectId", `${projectId}`);
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to get issues by project (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
packages/frontend/src/lib/server/issue/create.ts
Normal file
36
packages/frontend/src/lib/server/issue/create.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function create({
|
||||||
|
projectId,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
projectId: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/issue/create`);
|
||||||
|
url.searchParams.set("projectId", `${projectId}`);
|
||||||
|
url.searchParams.set("title", title.trim());
|
||||||
|
if (description.trim() !== "") url.searchParams.set("description", description.trim());
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to create issue (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.id) {
|
||||||
|
onError?.(`failed to create issue (${res.status})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/frontend/src/lib/server/issue/index.ts
Normal file
2
packages/frontend/src/lib/server/issue/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { byProject } from "./byProject";
|
||||||
|
export { create } from "./create";
|
||||||
30
packages/frontend/src/lib/server/organisation/byUser.ts
Normal file
30
packages/frontend/src/lib/server/organisation/byUser.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function byUser({
|
||||||
|
userId,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
userId: number;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/organisations/by-user`);
|
||||||
|
url.searchParams.set("userId", `${userId}`);
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to create organisation (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.id) {
|
||||||
|
onError?.(`failed to create organisation (${res.status})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
packages/frontend/src/lib/server/organisation/create.ts
Normal file
39
packages/frontend/src/lib/server/organisation/create.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function create({
|
||||||
|
name,
|
||||||
|
slug,
|
||||||
|
userId,
|
||||||
|
description,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
userId: number;
|
||||||
|
description: string;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/organisation/create`);
|
||||||
|
url.searchParams.set("name", name.trim());
|
||||||
|
url.searchParams.set("slug", slug.trim());
|
||||||
|
url.searchParams.set("userId", `${userId}`);
|
||||||
|
if (description.trim() !== "") url.searchParams.set("description", description.trim());
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to create organisation (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.id) {
|
||||||
|
onError?.(`failed to create organisation (${res.status})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/frontend/src/lib/server/organisation/index.ts
Normal file
2
packages/frontend/src/lib/server/organisation/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { byUser } from "./byUser";
|
||||||
|
export { create } from "./create";
|
||||||
26
packages/frontend/src/lib/server/project/byOrganisation.ts
Normal file
26
packages/frontend/src/lib/server/project/byOrganisation.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function byOrganisation({
|
||||||
|
organisationId,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
organisationId: number;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/projects/by-organisation`);
|
||||||
|
url.searchParams.set("organisationId", `${organisationId}`);
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to get projects by organisation (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
packages/frontend/src/lib/server/project/create.ts
Normal file
39
packages/frontend/src/lib/server/project/create.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { getAuthHeaders, getServerURL } from "@/lib/utils";
|
||||||
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
|
export async function create({
|
||||||
|
key,
|
||||||
|
name,
|
||||||
|
creatorId,
|
||||||
|
organisationId,
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
creatorId: number;
|
||||||
|
organisationId: number;
|
||||||
|
} & ServerQueryInput) {
|
||||||
|
const url = new URL(`${getServerURL()}/project/create`);
|
||||||
|
url.searchParams.set("key", key.trim());
|
||||||
|
url.searchParams.set("name", name.trim());
|
||||||
|
url.searchParams.set("creatorId", `${creatorId}`);
|
||||||
|
url.searchParams.set("organisationId", `${organisationId}`);
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = await res.text();
|
||||||
|
onError?.(error || `failed to create project (${res.status})`);
|
||||||
|
} else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.id) {
|
||||||
|
onError?.(`failed to create project (${res.status})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess?.(data, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/frontend/src/lib/server/project/index.ts
Normal file
2
packages/frontend/src/lib/server/project/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { byOrganisation } from "./byOrganisation";
|
||||||
|
export { create } from "./create";
|
||||||
Reference in New Issue
Block a user