From 93514fd11ad02b5ec50e26a3268a42a3f757c5f6 Mon Sep 17 00:00:00 2001 From: Ailin Luca Date: Thu, 21 Sep 2023 14:55:51 -0400 Subject: [PATCH] Completed general infrastructure --- .../demo-react/src/dashboard/Dashboard.tsx | 9 +++-- .../demo-react/src/dashboard/UploadButton.tsx | 13 ------- packages/demo-react/src/index.tsx | 6 +-- packages/demo-react/src/media/MediaPage.tsx | 14 ++++--- packages/demo-react/src/media/MediaPost.tsx | 37 +++++++++++++++++-- packages/demo-react/src/media/PostedBy.tsx | 16 ++++++++ packages/solid-react/src/useResource.ts | 1 + .../src/util/TrackingProxyContext.ts | 21 ++++++----- packages/solid/src/resource/Container.ts | 9 +++-- packages/solid/src/resource/Resource.ts | 4 ++ 10 files changed, 89 insertions(+), 41 deletions(-) create mode 100644 packages/demo-react/src/media/PostedBy.tsx diff --git a/packages/demo-react/src/dashboard/Dashboard.tsx b/packages/demo-react/src/dashboard/Dashboard.tsx index 4f06bd1..7144f2a 100644 --- a/packages/demo-react/src/dashboard/Dashboard.tsx +++ b/packages/demo-react/src/dashboard/Dashboard.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { Fragment } from "react"; import type { FunctionComponent } from "react"; import type { BuildMainContainerChildProps } from "./BuildMainContainer"; import { useResource } from "@ldo/solid-react"; @@ -9,7 +9,7 @@ export const Dashboard: FunctionComponent = ({ mainContainerUri, }) => { const mainContainer = useResource(mainContainerUri); - if (mainContainer.isLoading()) { + if (mainContainer.isDoingInitialFetch()) { return

Loading Main Container

; } @@ -20,7 +20,10 @@ export const Dashboard: FunctionComponent = ({
{mainContainer.children().map((child) => ( - + + +
+
))} ); diff --git a/packages/demo-react/src/dashboard/UploadButton.tsx b/packages/demo-react/src/dashboard/UploadButton.tsx index e0830d0..46edfc7 100644 --- a/packages/demo-react/src/dashboard/UploadButton.tsx +++ b/packages/demo-react/src/dashboard/UploadButton.tsx @@ -4,7 +4,6 @@ import type { Container, Leaf, LeafUri } from "@ldo/solid"; import { v4 } from "uuid"; import { useLdo, useSolidAuth } from "@ldo/solid-react"; import { PostShShapeType } from "../.ldo/post.shapeTypes"; -import { transactionChanges } from "@ldo/ldo"; export const UploadButton: FunctionComponent<{ mainContainer: Container }> = ({ mainContainer, @@ -51,12 +50,6 @@ export const UploadButton: FunctionComponent<{ mainContainer: Container }> = ({ indexResource.uri, indexResource, ); - console.log("Created Data"); - const changes = transactionChanges(post); - console.log("added"); - console.log(changes.added?.toString()); - console.log("removed"); - console.log(changes.removed?.toString()); post.articleBody = message; if (uploadedImage) { post.image = { "@id": uploadedImage.uri }; @@ -64,12 +57,6 @@ export const UploadButton: FunctionComponent<{ mainContainer: Container }> = ({ if (session.webId) { post.publisher = { "@id": session.webId }; } - console.log("Created Data 2"); - const changes2 = transactionChanges(post); - console.log("added"); - console.log(changes2.added?.toString()); - console.log("removed"); - console.log(changes2.removed?.toString()); post.type = { "@id": "SocialMediaPosting" }; post.uploadDate = new Date().toISOString(); const result = await commitData(post); diff --git a/packages/demo-react/src/index.tsx b/packages/demo-react/src/index.tsx index 46075e1..d701043 100644 --- a/packages/demo-react/src/index.tsx +++ b/packages/demo-react/src/index.tsx @@ -5,8 +5,4 @@ import App from "./App"; const root = ReactDOM.createRoot( document.getElementById("root") as HTMLElement, ); -root.render( - - - , -); +root.render(); diff --git a/packages/demo-react/src/media/MediaPage.tsx b/packages/demo-react/src/media/MediaPage.tsx index fc113f1..ad446ce 100644 --- a/packages/demo-react/src/media/MediaPage.tsx +++ b/packages/demo-react/src/media/MediaPage.tsx @@ -1,12 +1,16 @@ import React from "react"; import type { FunctionComponent } from "react"; -import { useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import { MediaPost } from "./MediaPost"; export const MediaPage: FunctionComponent = () => { + const navigate = useNavigate(); const { uri } = useParams(); - if (!uri) { - return

No URI present

; - } - return ; + + return ( +
+ + {uri ? :

No URI Present

} +
+ ); }; diff --git a/packages/demo-react/src/media/MediaPost.tsx b/packages/demo-react/src/media/MediaPost.tsx index 32fb4ab..c92ddad 100644 --- a/packages/demo-react/src/media/MediaPost.tsx +++ b/packages/demo-react/src/media/MediaPost.tsx @@ -1,11 +1,42 @@ -import React from "react"; +import React, { useCallback } from "react"; import type { FunctionComponent } from "react"; +import { useLdo, useResource, useSubject } from "@ldo/solid-react"; +import { PostShShapeType } from "../.ldo/post.shapeTypes"; +import { useNavigate } from "react-router-dom"; +import { PostedBy } from "./PostedBy"; export const MediaPost: FunctionComponent<{ uri: string }> = ({ uri }) => { + const navigate = useNavigate(); + const mediaResource = useResource(`${uri}index.ttl`); + const post = useSubject(PostShShapeType, mediaResource.uri); + const { getResource } = useLdo(); + const deletePost = useCallback(async () => { + const postContainer = getResource(uri); + const result = await postContainer.delete(); + if (result.isError) { + alert(result.message); + } + }, [uri]); + + if (mediaResource.isReading()) { + return

Loading Post...

; + } else if (mediaResource.status.isError) { + return

Error: {mediaResource.status.message}

; + } else if (mediaResource.isAbsent()) { + return

Post does not exist.

; + } + return (
-

Media: {uri}

-
+ {post.publisher?.["@id"] && } +
navigate(`/media/${encodeURIComponent(uri)}`)} + style={{ cursor: "pointer" }} + > + {post.articleBody &&

{post.articleBody}

} + {post.image && } +
+
); }; diff --git a/packages/demo-react/src/media/PostedBy.tsx b/packages/demo-react/src/media/PostedBy.tsx new file mode 100644 index 0000000..e11fda1 --- /dev/null +++ b/packages/demo-react/src/media/PostedBy.tsx @@ -0,0 +1,16 @@ +import type { FunctionComponent } from "react"; +import React from "react"; +import { useResource, useSubject } from "@ldo/solid-react"; +import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; + +export const PostedBy: FunctionComponent<{ webId: string }> = ({ webId }) => { + const webIdResource = useResource(webId); + const profile = useSubject(SolidProfileShapeShapeType, webId); + + if (webIdResource.isReading()) { + return

Loading Profile...

; + } else if (webIdResource.status.isError) { + return

Error: {webIdResource.status.message}

; + } + return

Posted By: {profile.fn}

; +}; diff --git a/packages/solid-react/src/useResource.ts b/packages/solid-react/src/useResource.ts index 53fde3c..f5904ef 100644 --- a/packages/solid-react/src/useResource.ts +++ b/packages/solid-react/src/useResource.ts @@ -29,6 +29,7 @@ export function useResource( ): Leaf | Container { const { getResource } = useLdo(); const resource = useMemo(() => { + console.log(uri); const resource = getResource(uri); if (!options?.suppressInitialRead) { if (options?.reloadOnMount) { diff --git a/packages/solid-react/src/util/TrackingProxyContext.ts b/packages/solid-react/src/util/TrackingProxyContext.ts index a27a130..d354a13 100644 --- a/packages/solid-react/src/util/TrackingProxyContext.ts +++ b/packages/solid-react/src/util/TrackingProxyContext.ts @@ -4,6 +4,7 @@ import type { ProxyContextOptions, } from "@ldo/jsonld-dataset-proxy"; import { ProxyContext } from "@ldo/jsonld-dataset-proxy"; +import type { QuadMatch } from "@ldo/rdf-utils"; import type { SubscribableDataset } from "@ldo/subscribable-dataset"; import { namedNode } from "@rdfjs/data-model"; import type { Quad } from "@rdfjs/types"; @@ -22,6 +23,14 @@ export class TrackingProxyContext extends ProxyContext { this.listener = listener; } + // Adds the listener to the subscribable dataset while ensuring deduping of the listener + private addListener(eventName: QuadMatch) { + const listeners = this.subscribableDataset.listeners(eventName); + if (!listeners.includes(this.listener)) { + this.subscribableDataset.on(eventName, this.listener); + } + } + protected createSubjectHandler(): ProxyHandler { const baseHandler = super.createSubjectHandler(); const oldGetFunction = baseHandler.get; @@ -34,13 +43,10 @@ export class TrackingProxyContext extends ProxyContext { if (typeof key === "symbol") { // Do Nothing } else if (key === "@id") { - this.subscribableDataset.on([subject, null, null, null], this.listener); + this.addListener([subject, null, null, null]); } else if (!this.contextUtil.isArray(key)) { const predicate = namedNode(this.contextUtil.keyToIri(key)); - this.subscribableDataset.on( - [subject, predicate, null, null], - this.listener, - ); + this.addListener([subject, predicate, null, null]); } return oldGetFunction && oldGetFunction(target, key, receiver); }; @@ -63,10 +69,7 @@ export class TrackingProxyContext extends ProxyContext { receiver, ) => { if (qualifiedArrayMethods.has(key)) { - this.subscribableDataset.on( - [target[0][0], target[0][1], target[0][2], null], - this.listener, - ); + this.addListener([target[0][0], target[0][1], target[0][2], null]); } return oldGetFunction && oldGetFunction(target, key, receiver); }; diff --git a/packages/solid/src/resource/Container.ts b/packages/solid/src/resource/Container.ts index 7758d7c..d83092d 100644 --- a/packages/solid/src/resource/Container.ts +++ b/packages/solid/src/resource/Container.ts @@ -60,6 +60,7 @@ export class Container extends Resource { protected updateWithReadSuccess( result: ContainerReadSuccess | AbsentReadSuccess, ): void { + super.updateWithReadSuccess(result); if (result.type === "containerReadSuccess") { this.rootContainer = result.isRootContainer; } @@ -113,9 +114,11 @@ export class Container extends Resource { } async getRootContainer(): Promise { - const checkResult = await this.checkIfIsRootContainer(); - if (checkResult.isError) return checkResult; - if (this.rootContainer) { + if (this.rootContainer === undefined) { + const checkResult = await this.checkIfIsRootContainer(); + if (checkResult.isError) return checkResult; + } + if (this.rootContainer === true) { return this; } const parentUri = getParentUri(this.uri); diff --git a/packages/solid/src/resource/Resource.ts b/packages/solid/src/resource/Resource.ts index 394b9d2..6c7f4f3 100644 --- a/packages/solid/src/resource/Resource.ts +++ b/packages/solid/src/resource/Resource.ts @@ -64,6 +64,9 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ isDoingInitialFetch(): boolean { return this.isReading() && !this.isFetched(); } + isReloading(): boolean { + return this.isReading() && this.isFetched(); + } // Checkers isFetched(): boolean { @@ -116,6 +119,7 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ async readIfUnfetched(): Promise< ResourceResult > { + console.log("didInitialFetch", this.didInitialFetch); if (this.didInitialFetch) { const readResult = this.toReadResult(); this.status = readResult;