Skip to content
Merged
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/user-profile.cy.ts/no-profile-section.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
"^layouts/(.*)": `<rootDir>/src/layouts/$1`,
"^core/(.*)": `<rootDir>/src/core/$1`,
"^components/(.*)": `<rootDir>/src/components/$1`,
"^libs/(.*)": `<rootDir>/src/libs/$1`,
"^providers/(.*)": `<rootDir>/src/providers/$1`,
"^containers/(.*)": `<rootDir>/src/containers/$1`,
"^design-system/(.*)": `<rootDir>/src/design-system/$1`,
Expand Down
3 changes: 3 additions & 0 deletions meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export const meta = {
ytVideoTutorialUrl: `https://www.youtube.com/watch?v=t3Ve0em65rY`,
mdCheatsheet: `https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet`,
routes: {
accessGroups: {
management: `/access-groups/`,
},
mindmaps: {
mindmap: `/mindmap/`,
creator: `/mindmap-creator/`,
Expand Down
1 change: 1 addition & 0 deletions seo-plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const disallowedPaths = [
meta.routes.creator.preview,
meta.routes.sandbox,
meta.routes.mindmaps.preview,
meta.routes.accessGroups.management,
legacyRoutes.documents.preview,
legacyRoutes.documents.browse,
];
Expand Down
32 changes: 24 additions & 8 deletions src/acts/update-mindmap-visibility.act.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getAPI, parseError, setCache } from "api-4markdown";
import type { MindmapDto } from "api-4markdown-contracts";
import type { AccessGroupId, MindmapDto } from "api-4markdown-contracts";
import { AsyncResult } from "development-kit/utility-types";
import { useMindmapCreatorState } from "store/mindmap-creator";
import {
readyMindmapsSelector,
Expand All @@ -8,7 +9,8 @@ import {

const updateMindmapVisibilityAct = async (
visibility: MindmapDto["visibility"],
): Promise<void> => {
sharedForGroups?: AccessGroupId[],
): AsyncResult => {
try {
useMindmapCreatorState.set({ operation: { is: `busy` } });

Expand All @@ -17,17 +19,27 @@ const updateMindmapVisibilityAct = async (
const activeMindmap = safeActiveMindmapSelector(mindmapCreatorState);
const yourMindmaps = readyMindmapsSelector(mindmapCreatorState.mindmaps);

const response = await getAPI().call(`updateMindmapVisibility`)({
mdate: activeMindmap.mdate,
id: activeMindmap.id,
visibility,
});
const response = await getAPI().call(`updateMindmapVisibility`)(
Array.isArray(sharedForGroups)
? {
mdate: activeMindmap.mdate,
id: activeMindmap.id,
visibility,
sharedForGroups,
}
: {
mdate: activeMindmap.mdate,
id: activeMindmap.id,
visibility,
},
);

const newMindmaps = yourMindmaps.data.map((mindmap) =>
mindmap.id === activeMindmap.id
? {
...mindmap,
mdate: response.mdate,
sharedForGroups,
visibility,
}
: mindmap,
Expand All @@ -45,10 +57,14 @@ const updateMindmapVisibilityAct = async (
mindmaps: newMindmaps,
mindmapsCount: newMindmaps.length,
});

return { is: "ok" };
} catch (error: unknown) {
const parsed = parseError(error);
useMindmapCreatorState.set({
operation: { is: `fail`, error: parseError(error) },
operation: { is: `fail`, error: parsed },
});
return { is: `fail`, error: parsed };
}
};

Expand Down
19 changes: 18 additions & 1 deletion src/api-4markdown-contracts/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ type Id = string;
type Name = string;
type MarkdownCode = string;
type Date = string;
type UTCDate = Brand<string, `UTCDate`>;
type Etag = Brand<string, `Etag`>;
type Tags = string[];
type Path = string;
type MarkdownContent = string;
Expand All @@ -19,13 +21,24 @@ type DocumentId = Brand<Id, `DocumentId`>;
type MindmapNodeId = Brand<SUID, `MindmapNodeId`>;
type MindmapId = Brand<Id, `MindmapId`>;

type AccessGroupId = Brand<Id, `AccessGroupId`>;

type ResourceId = DocumentId | MindmapNodeId | MindmapId;

const RESOURCE_VISIBILITIES = [
"private",
"public",
"permanent",
"manual",
] as const;

type ResourceVisibility = (typeof RESOURCE_VISIBILITIES)[number];

const RESOURCE_TYPES = ["document", "mindmap", "mindmap-node"] as const;

type ResourceType = (typeof RESOURCE_TYPES)[number];

export { RESOURCE_TYPES };
export { RESOURCE_TYPES, RESOURCE_VISIBILITIES };
export type {
Id,
Name,
Expand All @@ -45,4 +58,8 @@ export type {
MindmapId,
MindmapNodeId,
ResourceType,
AccessGroupId,
Etag,
UTCDate,
ResourceVisibility,
};
87 changes: 85 additions & 2 deletions src/api-4markdown-contracts/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Brand, type Prettify } from "development-kit/utility-types";
import type {
AccessGroupId,
Base64,
Date,
DocumentId,
Etag,
Id,
MindmapId,
MindmapNodeId,
Expand All @@ -27,6 +29,7 @@ import type {
CommentDto,
ResourceCompletionDto,
} from "../dtos";
import { AccessGroupDto } from "../dtos/access-group.dto";
// @TODO[PRIO=1]: [Add better error handling and throwing custom errors].

type Contract<TKey extends string, TDto, TPayload = undefined> = {
Expand Down Expand Up @@ -111,7 +114,7 @@ type DeleteMindmapContract = Contract<
type UpdateMindmapVisibilityContract = Contract<
`updateMindmapVisibility`,
Pick<MindmapDto, "mdate">,
Pick<MindmapDto, "mdate" | "id" | "visibility">
Pick<MindmapDto, "mdate" | "id" | "visibility" | "sharedForGroups">
>;

type UpdateMindmapContract = Contract<
Expand Down Expand Up @@ -269,6 +272,78 @@ type SetUserResourceCompletionContract = Contract<
}
>;

type GetYourAccessGroupsContract = Contract<
"getYourAccessGroups",
{
hasMore: boolean;
nextCursor: Pick<AccessGroupDto, "mdate" | "name"> | null;
accessGroups: AccessGroupDto[];
},
{
limit: number | null;
cursor: Pick<AccessGroupDto, "mdate" | "name"> | null;
}
>;

type CreateAccessGroupContract = Contract<
"createAccessGroup",
AccessGroupDto,
{ name: string; description: string | null }
>;

type EditAccessGroupContract = Contract<
"editAccessGroup",
Pick<AccessGroupDto, "mdate" | "etag" | "id" | "name" | "description">,
{
name: string;
etag: Etag;
description: string | null;
id: AccessGroupId;
}
>;

type GetAccessGroupContract = Contract<
"getAccessGroup",
Pick<
AccessGroupDto,
"cdate" | "description" | "etag" | "id" | "mdate" | "name"
> & { members: UserProfileDto[] },
{ id: AccessGroupId }
>;

type FindUserProfilesContract = Contract<
"findUserProfiles",
{
hasMore: boolean;
userProfiles: UserProfileDto[];
},
{ query: string; by: "displayName" | "id"; limit?: number }
>;

type AddAccessGroupMemberContract = Contract<
"addAccessGroupMember",
Pick<
AccessGroupDto,
"mdate" | "etag" | "id" | "cdate" | "description" | "name"
> & { member: UserProfileDto },
{ id: AccessGroupId; memberProfileId: UserProfileId; etag: Etag }
>;

type RemoveAccessGroupMemberContract = Contract<
"removeAccessGroupMember",
Pick<
AccessGroupDto,
"mdate" | "etag" | "id" | "cdate" | "description" | "name"
> & { member: UserProfileDto },
{ id: AccessGroupId; memberProfileId: UserProfileId; etag: Etag }
>;

type RemoveAccessGroupContract = Contract<
"removeAccessGroup",
null,
{ id: AccessGroupId }
>;

type API4MarkdownContracts =
| CreateMindmapContract
| GetYourDocumentsContract
Expand Down Expand Up @@ -298,7 +373,15 @@ type API4MarkdownContracts =
| GetUserProfileContract
| AddUserProfileCommentContract
| GetUserResourceCompletionsContract
| SetUserResourceCompletionContract;
| SetUserResourceCompletionContract
| GetYourAccessGroupsContract
| CreateAccessGroupContract
| EditAccessGroupContract
| GetAccessGroupContract
| FindUserProfilesContract
| AddAccessGroupMemberContract
| RemoveAccessGroupMemberContract
| RemoveAccessGroupContract;

type API4MarkdownContractKey = API4MarkdownContracts["key"];
type API4MarkdownDto<TKey extends API4MarkdownContractKey> = Extract<
Expand Down
13 changes: 13 additions & 0 deletions src/api-4markdown-contracts/dtos/access-group.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AccessGroupId, Etag, UserProfileId, UTCDate } from "../atoms";

type AccessGroupDto = {
id: AccessGroupId;
cdate: UTCDate;
etag: Etag;
mdate: UTCDate;
name: string;
description: string | null;
members: UserProfileId[];
};

export type { AccessGroupDto };
12 changes: 11 additions & 1 deletion src/api-4markdown-contracts/dtos/document.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
Description,
Tags,
Path,
AccessGroupId,
} from "../atoms";
import type { RatingDto } from "./rating.dto";
import type { UserProfileDto } from "./user-profile.dto";
Expand All @@ -16,6 +17,7 @@ type Base = {
code: MarkdownCode;
mdate: Date;
cdate: Date;
sharedForGroups?: AccessGroupId[];
path: Path;
};
// @TODO[PRIO=2]: [Re-design contracts to be atomic, instead of creating huge shared objects...].
Expand All @@ -37,14 +39,22 @@ type PermanentDocumentDto = Base & {
rating: RatingDto;
};

type ManualDocumentDto = Base & {
visibility: "manual";
author: UserProfileDto | null;
rating: RatingDto;
};

type DocumentDto =
| PrivateDocumentDto
| PublicDocumentDto
| PermanentDocumentDto;
| PermanentDocumentDto
| ManualDocumentDto;

export type {
PrivateDocumentDto,
PublicDocumentDto,
PermanentDocumentDto,
DocumentDto,
ManualDocumentDto,
};
1 change: 1 addition & 0 deletions src/api-4markdown-contracts/dtos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./rewrite-assistant.dto";
export * from "./your-account.dto";
export * from "./comment.dto";
export * from "./resource-completion.dto";
export * from "./access-group.dto";
5 changes: 4 additions & 1 deletion src/api-4markdown-contracts/dtos/mindmap.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type {
AccessGroupId,
Date,
Id,
MarkdownContent,
Path,
ResourceVisibility,
Tags,
Url,
} from "api-4markdown-contracts";
Expand Down Expand Up @@ -53,11 +55,12 @@ type MindmapDto = {
cdate: Date;
mdate: Date;
name: string;
sharedForGroups?: AccessGroupId[];
orientation: `x` | `y`;
path: Path;
nodes: MindmapNode[];
edges: MindmapEdge[];
visibility: `private` | `public` | `permanent`;
visibility: ResourceVisibility;
description: string | null;
tags: Tags | null;
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/meta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const Meta = ({
{/* Ogs */}
<meta property="og:description" content={description} />
<meta property="og:site_name" content={appName} />
<meta property="og:title" content={description} />
<meta property="og:title" content={title} />
<meta property="og:type" content="website" />
<meta property="og:url" content={url} />
{/* Other */}
Expand Down
43 changes: 43 additions & 0 deletions src/components/resource-visibility-tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { Tabs2 } from "design-system/tabs-2";
import { VisibilityIcon } from "./visibility-icon";
import {
RESOURCE_VISIBILITIES,
ResourceVisibility,
} from "api-4markdown-contracts";

type ResourceVisibilityTabsProps = {
className?: string;
disabled: boolean;
visibility: ResourceVisibility;
title: (visibility: ResourceVisibility) => string;
onChange: (visibility: ResourceVisibility) => void;
};

const ResourceVisibilityTabs = ({
className,
visibility,
title,
onChange,
disabled,
}: ResourceVisibilityTabsProps) => {
return (
<Tabs2 className={className}>
{RESOURCE_VISIBILITIES.map((type) => (
<Tabs2.Item
key={type}
title={title(type)}
className="capitalize"
active={visibility === type}
onClick={() => onChange(type)}
disabled={disabled}
>
<VisibilityIcon className="size-6 shrink-0" visibility={type} />
<Tabs2.ItemText>{type}</Tabs2.ItemText>
</Tabs2.Item>
))}
</Tabs2>
);
};

export { ResourceVisibilityTabs };
Loading
Loading