@semapps/activitypub-components 0.6.7 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +413 -545
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +215 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +420 -552
- package/dist/index.es.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs.js
CHANGED
|
@@ -8,10 +8,10 @@ var $583VT$muistylesmakeStyles = require("@mui/styles/makeStyles");
|
|
|
8
8
|
var $583VT$muiiconsmaterialSend = require("@mui/icons-material/Send");
|
|
9
9
|
var $583VT$semappssemanticdataprovider = require("@semapps/semantic-data-provider");
|
|
10
10
|
var $583VT$semappsauthprovider = require("@semapps/auth-provider");
|
|
11
|
+
var $583VT$reactquery = require("react-query");
|
|
11
12
|
var $583VT$tiptapcore = require("@tiptap/core");
|
|
12
13
|
var $583VT$tiptapextensionmention = require("@tiptap/extension-mention");
|
|
13
14
|
var $583VT$semappsfieldcomponents = require("@semapps/field-components");
|
|
14
|
-
var $583VT$reactquery = require("react-query");
|
|
15
15
|
var $583VT$tiptapreact = require("@tiptap/react");
|
|
16
16
|
var $583VT$tippyjs = require("tippy.js");
|
|
17
17
|
|
|
@@ -28,9 +28,9 @@ $parcel$export(module.exports, "CommentsField", () => $2e5504cc4159ca8d$export$2
|
|
|
28
28
|
$parcel$export(module.exports, "CollectionList", () => $505d598a33288aad$export$2e2bcd8739ae039);
|
|
29
29
|
$parcel$export(module.exports, "ReferenceCollectionField", () => $b0c94a9bdea99da5$export$2e2bcd8739ae039);
|
|
30
30
|
$parcel$export(module.exports, "useCollection", () => $5ca5f7e9fc1c3544$export$2e2bcd8739ae039);
|
|
31
|
-
$parcel$export(module.exports, "useInbox", () => $
|
|
32
|
-
$parcel$export(module.exports, "useNodeinfo", () => $
|
|
33
|
-
$parcel$export(module.exports, "useOutbox", () => $
|
|
31
|
+
$parcel$export(module.exports, "useInbox", () => $486f741c94cd8f74$export$2e2bcd8739ae039);
|
|
32
|
+
$parcel$export(module.exports, "useNodeinfo", () => $59fc2d2cba62bd8e$export$2e2bcd8739ae039);
|
|
33
|
+
$parcel$export(module.exports, "useOutbox", () => $456aea3814dded7d$export$2e2bcd8739ae039);
|
|
34
34
|
$parcel$export(module.exports, "useWebfinger", () => $5b61553556e35016$export$2e2bcd8739ae039);
|
|
35
35
|
$parcel$export(module.exports, "useMentions", () => $968ea07fb81eda0b$export$2e2bcd8739ae039);
|
|
36
36
|
$parcel$export(module.exports, "ACTIVITY_TYPES", () => $ebea823cebb2f44b$export$1ec8e53e7d982d22);
|
|
@@ -108,102 +108,400 @@ const $ebea823cebb2f44b$export$4d8d554031975581 = "https://www.w3.org/ns/activit
|
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
const $03510abb28fd3d8a$export$e57ff0f701c44363 = (value)=>{
|
|
115
|
+
// If the field is null-ish, we suppose there are no values.
|
|
116
|
+
if (value === null || value === undefined) return [];
|
|
117
|
+
// Return as is.
|
|
118
|
+
if (Array.isArray(value)) return value;
|
|
119
|
+
// Single value is made an array.
|
|
120
|
+
return [
|
|
121
|
+
value
|
|
122
|
+
];
|
|
123
|
+
};
|
|
124
|
+
var $03510abb28fd3d8a$export$2e2bcd8739ae039 = {
|
|
125
|
+
arrayOf: $03510abb28fd3d8a$export$e57ff0f701c44363
|
|
126
|
+
};
|
|
127
|
+
const $03510abb28fd3d8a$export$34aed805e991a647 = (iterable, predicate)=>{
|
|
128
|
+
const seen = new Set();
|
|
129
|
+
return iterable.filter((item)=>{
|
|
130
|
+
const key = predicate(item);
|
|
131
|
+
if (seen.has(key)) return false;
|
|
132
|
+
seen.add(key);
|
|
133
|
+
return true;
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
const $5ca5f7e9fc1c3544$var$useItemsFromPages = (pages, dereferenceItems)=>{
|
|
139
|
+
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
140
|
+
const items = (0, $583VT$react.useMemo)(()=>pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
|
|
141
|
+
pages
|
|
142
|
+
]);
|
|
143
|
+
// We will force dereference, if some items are not URI string references.
|
|
144
|
+
const shouldDereference = (0, $583VT$react.useMemo)(()=>{
|
|
145
|
+
return dereferenceItems || items.some((item)=>typeof item !== "string");
|
|
146
|
+
}, [
|
|
147
|
+
dereferenceItems,
|
|
148
|
+
items
|
|
149
|
+
]);
|
|
150
|
+
// Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
|
|
151
|
+
const itemQueries = (0, $583VT$reactquery.useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
152
|
+
queryKey: [
|
|
153
|
+
"resource",
|
|
154
|
+
itemUri
|
|
155
|
+
],
|
|
156
|
+
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
157
|
+
staleTime: Infinity
|
|
158
|
+
})));
|
|
159
|
+
if (!shouldDereference) return {
|
|
160
|
+
loadedItems: items,
|
|
161
|
+
isLoading: false,
|
|
162
|
+
isFetching: false
|
|
163
|
+
};
|
|
164
|
+
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
165
|
+
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
166
|
+
return itemQuery.isSuccess && itemQuery.data || [];
|
|
167
|
+
}));
|
|
168
|
+
const errors = itemQueries.filter((q)=>q.error);
|
|
169
|
+
return {
|
|
170
|
+
loadedItems: loadedItems,
|
|
171
|
+
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
172
|
+
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
173
|
+
errors: errors.length > 0 ? errors : undefined
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Subscribe a collection. Supports pagination.
|
|
178
|
+
* @param predicateOrUrl The collection URI or the predicate to get the collection URI from the identity (webId).
|
|
179
|
+
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
180
|
+
*/ const $5ca5f7e9fc1c3544$var$useCollection = (predicateOrUrl, options = {})=>{
|
|
181
|
+
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
112
182
|
const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
|
|
113
|
-
const
|
|
114
|
-
|
|
183
|
+
const [totalItems, setTotalItems] = (0, $583VT$react.useState)();
|
|
184
|
+
const queryClient = (0, $583VT$reactquery.useQueryClient)();
|
|
185
|
+
const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
|
|
186
|
+
status: "connecting"
|
|
187
|
+
});
|
|
188
|
+
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
189
|
+
const webSocketRef = (0, $583VT$react.useRef)(null);
|
|
190
|
+
// Get collectionUrl from webId predicate or URL.
|
|
191
|
+
const collectionUrl = (0, $583VT$react.useMemo)(()=>{
|
|
192
|
+
if (predicateOrUrl) {
|
|
193
|
+
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
194
|
+
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
115
198
|
}, [
|
|
116
|
-
identity
|
|
199
|
+
identity,
|
|
200
|
+
predicateOrUrl
|
|
117
201
|
]);
|
|
118
|
-
|
|
119
|
-
|
|
202
|
+
// Fetch page of collection item references (if pageParam provided)
|
|
203
|
+
// or default to `collectionUrl` (which should give you the first page).
|
|
204
|
+
const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
205
|
+
// Fetch page or first page (collectionUrl)
|
|
206
|
+
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
207
|
+
if (json.totalItems) setTotalItems(json.totalItems);
|
|
208
|
+
// If first page, handle this here.
|
|
209
|
+
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
210
|
+
if (json.first?.items) {
|
|
211
|
+
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
212
|
+
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
213
|
+
else json = json.first;
|
|
214
|
+
} else // Fetch the first page
|
|
215
|
+
({ json: json } = await dataProvider.fetch(json.first));
|
|
216
|
+
}
|
|
217
|
+
return json;
|
|
120
218
|
}, [
|
|
121
|
-
|
|
219
|
+
dataProvider,
|
|
220
|
+
collectionUrl,
|
|
221
|
+
identity,
|
|
222
|
+
setTotalItems
|
|
122
223
|
]);
|
|
123
|
-
//
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
224
|
+
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
225
|
+
const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
|
|
226
|
+
"collection",
|
|
227
|
+
{
|
|
228
|
+
collectionUrl: collectionUrl
|
|
229
|
+
}
|
|
230
|
+
], fetchCollection, {
|
|
231
|
+
enabled: !!(collectionUrl && identity?.id),
|
|
232
|
+
getNextPageParam: (lastPage)=>lastPage.next,
|
|
233
|
+
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
234
|
+
});
|
|
235
|
+
// Put all items together in a list (and dereference, if required).
|
|
236
|
+
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $5ca5f7e9fc1c3544$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
|
|
237
|
+
const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
|
|
238
|
+
const addItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
|
|
239
|
+
queryClient.setQueryData([
|
|
240
|
+
"collection",
|
|
241
|
+
{
|
|
242
|
+
collectionUrl: collectionUrl
|
|
243
|
+
}
|
|
244
|
+
], (oldData)=>{
|
|
245
|
+
if (!oldData) return oldData;
|
|
246
|
+
setTotalItems(totalItems && totalItems + 1);
|
|
247
|
+
// Destructure, so react knows, it needs to re-render the pages.
|
|
248
|
+
const pages = [
|
|
249
|
+
...oldData.pages
|
|
250
|
+
];
|
|
251
|
+
const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
|
|
252
|
+
firstPageItems.unshift(item);
|
|
253
|
+
oldData.pages = pages;
|
|
254
|
+
return oldData;
|
|
137
255
|
});
|
|
138
|
-
|
|
256
|
+
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
257
|
+
"collection",
|
|
258
|
+
{
|
|
259
|
+
collectionUrl: collectionUrl
|
|
260
|
+
}
|
|
261
|
+
], {
|
|
262
|
+
active: true,
|
|
263
|
+
exact: true
|
|
264
|
+
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
139
265
|
}, [
|
|
140
|
-
|
|
266
|
+
queryClient,
|
|
267
|
+
collectionUrl
|
|
141
268
|
]);
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
269
|
+
const removeItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
|
|
270
|
+
queryClient.setQueryData([
|
|
271
|
+
"collection",
|
|
272
|
+
{
|
|
273
|
+
collectionUrl: collectionUrl
|
|
274
|
+
}
|
|
275
|
+
], (oldData)=>{
|
|
276
|
+
if (!oldData) return oldData;
|
|
277
|
+
setTotalItems(totalItems && totalItems - 1);
|
|
278
|
+
// Destructure, so react knows, it needs to re-render the pages array.
|
|
279
|
+
const pages = [
|
|
280
|
+
...oldData.pages
|
|
281
|
+
];
|
|
282
|
+
// Find the item in all pages and remove the item to be removed (either item.id or just item)
|
|
283
|
+
pages.forEach((page)=>{
|
|
284
|
+
if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
|
|
285
|
+
else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
|
|
286
|
+
});
|
|
287
|
+
oldData.pages = pages;
|
|
288
|
+
return oldData;
|
|
289
|
+
});
|
|
290
|
+
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
291
|
+
"collection",
|
|
292
|
+
{
|
|
293
|
+
collectionUrl: collectionUrl
|
|
294
|
+
}
|
|
295
|
+
], {
|
|
296
|
+
active: true,
|
|
297
|
+
exact: true
|
|
298
|
+
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
299
|
+
}, [
|
|
300
|
+
queryClient,
|
|
301
|
+
collectionUrl
|
|
302
|
+
]);
|
|
303
|
+
// Live Updates
|
|
304
|
+
(0, $583VT$react.useEffect)(()=>{
|
|
305
|
+
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
306
|
+
(0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((ws)=>{
|
|
307
|
+
webSocketRef.current = ws; // Keep a ref to the webSocket so that it can be used elsewhere
|
|
308
|
+
webSocketRef.current.addEventListener("message", (e)=>{
|
|
309
|
+
const data = JSON.parse(e.data);
|
|
310
|
+
if (data.type === "Add") addItem(data.object, true);
|
|
311
|
+
else if (data.type === "Remove") removeItem(data.object, true);
|
|
312
|
+
});
|
|
313
|
+
webSocketRef.current.addEventListener("error", (e)=>{
|
|
314
|
+
setHasLiveUpdates({
|
|
315
|
+
status: "error",
|
|
316
|
+
error: e
|
|
317
|
+
});
|
|
318
|
+
// TODO: Retry after a while
|
|
319
|
+
});
|
|
320
|
+
webSocketRef.current.addEventListener("close", (e)=>{
|
|
321
|
+
if (!hasLiveUpdates.error) setHasLiveUpdates({
|
|
322
|
+
...hasLiveUpdates,
|
|
323
|
+
status: "closed"
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
setHasLiveUpdates({
|
|
327
|
+
status: "connected"
|
|
328
|
+
});
|
|
329
|
+
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
330
|
+
}, [
|
|
331
|
+
collectionUrl,
|
|
332
|
+
liveUpdates,
|
|
333
|
+
dataProvider,
|
|
334
|
+
webSocketRef
|
|
335
|
+
]);
|
|
336
|
+
const awaitWebSocketConnection = (0, $583VT$react.useCallback)((options = {})=>{
|
|
337
|
+
const { timeout: timeout = 30000 } = options;
|
|
338
|
+
return new Promise((resolve, reject)=>{
|
|
339
|
+
if (webSocketRef?.current) resolve(webSocketRef);
|
|
340
|
+
else {
|
|
341
|
+
const timeoutId = setTimeout(()=>{
|
|
342
|
+
reject(`No WebSocket connection found within ${Math.round(timeout / 1000)}s`);
|
|
343
|
+
}, timeout);
|
|
344
|
+
const intervalId = setInterval(()=>{
|
|
345
|
+
if (webSocketRef?.current) {
|
|
346
|
+
clearInterval(intervalId);
|
|
347
|
+
clearTimeout(timeoutId);
|
|
348
|
+
resolve(webSocketRef);
|
|
349
|
+
} else console.log("WebSocket is not initialized yet, waiting...");
|
|
350
|
+
}, 100);
|
|
351
|
+
}
|
|
167
352
|
});
|
|
168
|
-
if (json["@graph"]) return json["@graph"];
|
|
169
|
-
return null;
|
|
170
353
|
}, [
|
|
171
|
-
|
|
172
|
-
outboxUrl
|
|
354
|
+
webSocketRef
|
|
173
355
|
]);
|
|
174
356
|
return {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
357
|
+
items: items,
|
|
358
|
+
totalItems: totalItems,
|
|
359
|
+
error: allErrors.length > 0 && allErrors,
|
|
360
|
+
refetch: refetch,
|
|
361
|
+
fetchNextPage: fetchNextPage,
|
|
362
|
+
addItem: addItem,
|
|
363
|
+
removeItem: removeItem,
|
|
364
|
+
hasNextPage: hasNextPage,
|
|
365
|
+
isLoading: isLoadingPage || isLoadingItems,
|
|
366
|
+
isFetching: isFetchingPage || isFetchingItems,
|
|
367
|
+
isFetchingNextPage: isFetchingNextPage,
|
|
368
|
+
url: collectionUrl,
|
|
369
|
+
hasLiveUpdates: hasLiveUpdates,
|
|
370
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
371
|
+
webSocketRef: webSocketRef
|
|
180
372
|
};
|
|
181
373
|
};
|
|
182
|
-
var $
|
|
374
|
+
var $5ca5f7e9fc1c3544$export$2e2bcd8739ae039 = $5ca5f7e9fc1c3544$var$useCollection;
|
|
183
375
|
|
|
184
376
|
|
|
185
377
|
|
|
186
378
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
206
|
-
}
|
|
379
|
+
/**
|
|
380
|
+
* Hook used internally by useInbox and useOutbox. This is not exported.
|
|
381
|
+
* @param awaitWebSocketConnection Promise returning the WebSocket which allow to listen to the inbox or outbox
|
|
382
|
+
* @param existingActivities Partial list of activities already received in the inbox and outbox
|
|
383
|
+
*/ const $5e70f9d0635e25dd$var$useAwaitActivity = (awaitWebSocketConnection, existingActivities)=>{
|
|
384
|
+
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
385
|
+
// TODO Allow to pass an object, and automatically dereference it if required, like on the @semapps/activitypub matchActivity util
|
|
386
|
+
return (0, $583VT$react.useCallback)((matchActivity, options = {})=>{
|
|
387
|
+
const { timeout: timeout = 30000, checkExistingActivities: checkExistingActivities = false } = options;
|
|
388
|
+
return new Promise((resolve, reject)=>{
|
|
389
|
+
awaitWebSocketConnection().then((webSocketRef)=>{
|
|
390
|
+
const onMessage = (event)=>{
|
|
391
|
+
const data = JSON.parse(event.data);
|
|
392
|
+
if (data.type === "Add") dataProvider.fetch(data.object).then(({ json: json })=>{
|
|
393
|
+
if (matchActivity(json)) {
|
|
394
|
+
removeListeners();
|
|
395
|
+
return resolve(json);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
};
|
|
399
|
+
const onError = (e)=>{
|
|
400
|
+
// TODO reconnect if connection closed
|
|
401
|
+
removeListeners();
|
|
402
|
+
reject(e);
|
|
403
|
+
};
|
|
404
|
+
const onClose = (e)=>{
|
|
405
|
+
removeListeners();
|
|
406
|
+
reject(new Error(`${e.reason} (Code: ${e.code})`));
|
|
407
|
+
};
|
|
408
|
+
const removeListeners = ()=>{
|
|
409
|
+
webSocketRef.current?.removeEventListener("message", onMessage);
|
|
410
|
+
webSocketRef.current?.removeEventListener("error", onError);
|
|
411
|
+
webSocketRef.current?.removeEventListener("close", onClose);
|
|
412
|
+
};
|
|
413
|
+
webSocketRef.current?.addEventListener("message", onMessage);
|
|
414
|
+
webSocketRef.current?.addEventListener("error", onError);
|
|
415
|
+
webSocketRef.current?.addEventListener("close", onClose);
|
|
416
|
+
// If a list of activities is already loaded, verify if there is a match
|
|
417
|
+
if (existingActivities && checkExistingActivities) for (const a of existingActivities){
|
|
418
|
+
if (typeof a !== "string") {
|
|
419
|
+
if (matchActivity(a)) {
|
|
420
|
+
removeListeners();
|
|
421
|
+
return resolve(a);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
setTimeout(()=>{
|
|
426
|
+
removeListeners();
|
|
427
|
+
reject(new Error("Timeout"));
|
|
428
|
+
}, timeout);
|
|
429
|
+
}).catch((e)=>{
|
|
430
|
+
reject(e);
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
}, [
|
|
434
|
+
awaitWebSocketConnection,
|
|
435
|
+
existingActivities,
|
|
436
|
+
dataProvider
|
|
437
|
+
]);
|
|
438
|
+
};
|
|
439
|
+
var $5e70f9d0635e25dd$export$2e2bcd8739ae039 = $5e70f9d0635e25dd$var$useAwaitActivity;
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Hook to fetch and post to the outbox of the logged user.
|
|
444
|
+
* Returns the same data as the useCollection hooks, plus:
|
|
445
|
+
* - `post`: a function to post a new activity in the user's outbox
|
|
446
|
+
* - `awaitActivity`: a function to wait for a certain activity to be posted
|
|
447
|
+
* - `owner`: the WebID of the outbox's owner
|
|
448
|
+
* See https://semapps.org/docs/frontend/activitypub-components#useoutbox for usage
|
|
449
|
+
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
450
|
+
*/ const $456aea3814dded7d$var$useOutbox = (options = {})=>{
|
|
451
|
+
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
452
|
+
const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
|
|
453
|
+
const { url: url, items: items, awaitWebSocketConnection: awaitWebSocketConnection, ...rest } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)("outbox", options);
|
|
454
|
+
const awaitActivity = (0, $5e70f9d0635e25dd$export$2e2bcd8739ae039)(awaitWebSocketConnection, items);
|
|
455
|
+
// Post an activity to the logged user's outbox and return its URI
|
|
456
|
+
const post = (0, $583VT$react.useCallback)(async (activity)=>{
|
|
457
|
+
if (!url) throw new Error("Cannot post to outbox before user identity is loaded. Please use the isLoading argument of useOutbox");
|
|
458
|
+
const { headers: headers } = await dataProvider.fetch(url, {
|
|
459
|
+
method: "POST",
|
|
460
|
+
body: JSON.stringify({
|
|
461
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
462
|
+
...activity
|
|
463
|
+
})
|
|
464
|
+
});
|
|
465
|
+
return headers.get("Location");
|
|
466
|
+
}, [
|
|
467
|
+
url,
|
|
468
|
+
dataProvider
|
|
469
|
+
]);
|
|
470
|
+
return {
|
|
471
|
+
url: url,
|
|
472
|
+
items: items,
|
|
473
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
474
|
+
post: post,
|
|
475
|
+
awaitActivity: awaitActivity,
|
|
476
|
+
owner: identity?.id,
|
|
477
|
+
...rest
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
var $456aea3814dded7d$export$2e2bcd8739ae039 = $456aea3814dded7d$var$useOutbox;
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
// Fix a bug in the current version of the mention extension
|
|
486
|
+
// (The { id, label } object is located inside the id property)
|
|
487
|
+
// See https://github.com/ueberdosis/tiptap/pull/1322
|
|
488
|
+
const $9b1343b281972d72$var$CustomMention = (0, ($parcel$interopDefault($583VT$tiptapextensionmention))).extend({
|
|
489
|
+
renderHTML ({ node: node, HTMLAttributes: HTMLAttributes }) {
|
|
490
|
+
return [
|
|
491
|
+
"span",
|
|
492
|
+
(0, $583VT$tiptapcore.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
|
|
493
|
+
`@${node.attrs.id.label}`
|
|
494
|
+
];
|
|
495
|
+
},
|
|
496
|
+
addAttributes () {
|
|
497
|
+
return {
|
|
498
|
+
label: {
|
|
499
|
+
default: null,
|
|
500
|
+
parseHTML: (element)=>{
|
|
501
|
+
return {
|
|
502
|
+
label: element.getAttribute("data-mention-label")
|
|
503
|
+
};
|
|
504
|
+
},
|
|
207
505
|
renderHTML: (attributes)=>{
|
|
208
506
|
if (!attributes.id.label) return {};
|
|
209
507
|
return {
|
|
@@ -284,7 +582,7 @@ const $703eba3e46be7ee5$var$PostCommentForm = ({ context: context, placeholder:
|
|
|
284
582
|
const userDataModel = (0, $583VT$semappssemanticdataprovider.useDataModel)(userResource);
|
|
285
583
|
const classes = $703eba3e46be7ee5$var$useStyles();
|
|
286
584
|
const notify = (0, $583VT$reactadmin.useNotify)();
|
|
287
|
-
const outbox = (0, $
|
|
585
|
+
const outbox = (0, $456aea3814dded7d$export$2e2bcd8739ae039)();
|
|
288
586
|
const [expanded, setExpanded] = (0, $583VT$react.useState)(false);
|
|
289
587
|
const [openAuth, setOpenAuth] = (0, $583VT$react.useState)(false);
|
|
290
588
|
const onSubmit = (0, $583VT$react.useCallback)(async (values)=>{
|
|
@@ -544,186 +842,9 @@ var $d68cd57b2d06b6d5$export$2e2bcd8739ae039 = $d68cd57b2d06b6d5$var$CommentsLis
|
|
|
544
842
|
|
|
545
843
|
|
|
546
844
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const $03510abb28fd3d8a$export$e57ff0f701c44363 = (value)=>{
|
|
551
|
-
// If the field is null-ish, we suppose there are no values.
|
|
552
|
-
if (value === null || value === undefined) return [];
|
|
553
|
-
// Return as is.
|
|
554
|
-
if (Array.isArray(value)) return value;
|
|
555
|
-
// Single value is made an array.
|
|
556
|
-
return [
|
|
557
|
-
value
|
|
558
|
-
];
|
|
559
|
-
};
|
|
560
|
-
var $03510abb28fd3d8a$export$2e2bcd8739ae039 = {
|
|
561
|
-
arrayOf: $03510abb28fd3d8a$export$e57ff0f701c44363
|
|
562
|
-
};
|
|
563
|
-
const $03510abb28fd3d8a$export$34aed805e991a647 = (iterable, predicate)=>{
|
|
564
|
-
const seen = new Set();
|
|
565
|
-
return iterable.filter((item)=>{
|
|
566
|
-
const key = predicate(item);
|
|
567
|
-
if (seen.has(key)) return false;
|
|
568
|
-
seen.add(key);
|
|
569
|
-
return true;
|
|
570
|
-
});
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
const $2b75a2f49c9ef165$var$useItemsFromPagesAndNotifications = (pages, notifications, dereferenceItems)=>{
|
|
575
|
-
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
576
|
-
// Add all items from pages and process notifications (possibly new and deleted items).
|
|
577
|
-
const items = (0, $583VT$react.useMemo)(()=>{
|
|
578
|
-
const addItems = notifications.map((n)=>n.type === "Add").map((n)=>n.object);
|
|
579
|
-
const removeItems = notifications.map((n)=>n.type === "Remove").map((n)=>n.object.id || n.object);
|
|
580
|
-
const currentItems = !pages ? [] : pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items));
|
|
581
|
-
const currentAndNew = currentItems.concat(addItems);
|
|
582
|
-
return currentAndNew// Filter out removed items.
|
|
583
|
-
.filter((item)=>!removeItems.some((r)=>(r.id ?? r) === (item.id ?? item)))// Filter duplicates.
|
|
584
|
-
.filter((item)=>currentAndNew.some((i2)=>(i2.id ?? i2) === (item.id ?? item)));
|
|
585
|
-
}, pages, notifications);
|
|
586
|
-
if (!dereferenceItems) return {
|
|
587
|
-
loadedItems: items,
|
|
588
|
-
isLoading: false,
|
|
589
|
-
isFetching: false
|
|
590
|
-
};
|
|
591
|
-
// Dereference all items, if they are not yet.
|
|
592
|
-
const itemQueries = (0, $583VT$reactquery.useQueries)(items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
593
|
-
queryKey: [
|
|
594
|
-
"resource",
|
|
595
|
-
itemUri
|
|
596
|
-
],
|
|
597
|
-
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
598
|
-
staleTime: Infinity
|
|
599
|
-
})));
|
|
600
|
-
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
601
|
-
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
602
|
-
return itemQuery.isSuccess && itemQuery.data || [];
|
|
603
|
-
}));
|
|
604
|
-
console.log("loadedItems", loadedItems.length, "total", items.length);
|
|
605
|
-
const errors = itemQueries.filter((q)=>q.error);
|
|
606
|
-
return {
|
|
607
|
-
loadedItems: loadedItems,
|
|
608
|
-
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
609
|
-
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
610
|
-
errors: errors.length > 0 && errors
|
|
611
|
-
};
|
|
612
|
-
};
|
|
613
|
-
const $2b75a2f49c9ef165$var$useCollection = (predicateOrUrl, options = {})=>{
|
|
614
|
-
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
615
|
-
const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
|
|
616
|
-
const [totalItems, setTotalItems] = (0, $583VT$react.useState)();
|
|
617
|
-
const [notifications, setNotifications] = (0, $583VT$react.useState)([]);
|
|
618
|
-
const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
|
|
619
|
-
status: "disconnected",
|
|
620
|
-
error: undefined
|
|
621
|
-
});
|
|
622
|
-
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
623
|
-
// Get collectionUrl from webId predicate or URL.
|
|
624
|
-
const collectionUrl = (0, $583VT$react.useMemo)(()=>{
|
|
625
|
-
if (predicateOrUrl) {
|
|
626
|
-
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
627
|
-
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
628
|
-
}
|
|
629
|
-
return undefined;
|
|
630
|
-
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
631
|
-
}, [
|
|
632
|
-
identity,
|
|
633
|
-
predicateOrUrl
|
|
634
|
-
]);
|
|
635
|
-
// Fetch page of collection item references (if pageParam provided)
|
|
636
|
-
// or default to `collectionUrl` (which should give you the first page).
|
|
637
|
-
const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
638
|
-
// Fetch page or first page (collectionUrl)
|
|
639
|
-
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
640
|
-
if (json.totalItems) setTotalItems(json.totalItems);
|
|
641
|
-
// If first page, handle this here.
|
|
642
|
-
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
643
|
-
if (json.first?.items) {
|
|
644
|
-
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
645
|
-
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
646
|
-
else json = json.first;
|
|
647
|
-
} else // Fetch the first page
|
|
648
|
-
({ json: json } = await dataProvider.fetch(json.first));
|
|
649
|
-
}
|
|
650
|
-
return json;
|
|
651
|
-
}, [
|
|
652
|
-
dataProvider,
|
|
653
|
-
collectionUrl,
|
|
654
|
-
identity,
|
|
655
|
-
setTotalItems
|
|
656
|
-
]);
|
|
657
|
-
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
658
|
-
const { data: data, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
|
|
659
|
-
"collection",
|
|
660
|
-
{
|
|
661
|
-
collectionUrl: collectionUrl
|
|
662
|
-
}
|
|
663
|
-
], fetchCollection, {
|
|
664
|
-
enabled: !!(collectionUrl && identity?.id),
|
|
665
|
-
getNextPageParam: (lastPage)=>lastPage.next,
|
|
666
|
-
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
667
|
-
});
|
|
668
|
-
// Put all items together in a list.
|
|
669
|
-
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $2b75a2f49c9ef165$var$useItemsFromPagesAndNotifications(data?.pages, notifications, dereferenceItems);
|
|
670
|
-
// Notifications have been processed after hook call, so reset.
|
|
671
|
-
// useEffect(() => {
|
|
672
|
-
// setNotifications([]);
|
|
673
|
-
// }, [notifications])
|
|
674
|
-
// Live Updates
|
|
675
|
-
(0, $583VT$react.useEffect)(()=>{
|
|
676
|
-
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
677
|
-
(0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
|
|
678
|
-
webSocket.addEventListener("message", (e)=>{
|
|
679
|
-
if (e.data && e.data.type === "Add" || e.data.type === "Remove") setNotifications([
|
|
680
|
-
...notifications,
|
|
681
|
-
e.data
|
|
682
|
-
]);
|
|
683
|
-
});
|
|
684
|
-
webSocket.addEventListener("error", (e)=>{
|
|
685
|
-
setHasLiveUpdates({
|
|
686
|
-
status: "error",
|
|
687
|
-
error: e
|
|
688
|
-
});
|
|
689
|
-
// TODO: Retry after a while
|
|
690
|
-
});
|
|
691
|
-
webSocket.addEventListener("close", (e)=>{
|
|
692
|
-
setHasLiveUpdates({
|
|
693
|
-
...hasLiveUpdates,
|
|
694
|
-
status: "disconnected"
|
|
695
|
-
});
|
|
696
|
-
});
|
|
697
|
-
setHasLiveUpdates({
|
|
698
|
-
status: "connected"
|
|
699
|
-
});
|
|
700
|
-
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
701
|
-
}, [
|
|
702
|
-
collectionUrl,
|
|
703
|
-
liveUpdates,
|
|
704
|
-
dataProvider.fetch
|
|
705
|
-
]);
|
|
706
|
-
const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
|
|
707
|
-
return {
|
|
708
|
-
items: items,
|
|
709
|
-
totalItems: totalItems,
|
|
710
|
-
error: allErrors.length > 0 && allErrors,
|
|
711
|
-
refetch: refetch,
|
|
712
|
-
fetchNextPage: fetchNextPage,
|
|
713
|
-
hasNextPage: hasNextPage,
|
|
714
|
-
isLoading: isLoadingPage || isLoadingItems,
|
|
715
|
-
isFetching: isFetchingPage || isFetchingItems,
|
|
716
|
-
isFetchingNextPage: isFetchingNextPage,
|
|
717
|
-
url: collectionUrl,
|
|
718
|
-
hasLiveUpdates: hasLiveUpdates
|
|
719
|
-
};
|
|
720
|
-
};
|
|
721
|
-
var $2b75a2f49c9ef165$export$2e2bcd8739ae039 = $2b75a2f49c9ef165$var$useCollection;
|
|
722
|
-
|
|
723
|
-
|
|
724
845
|
const $2e5504cc4159ca8d$var$CommentsField = ({ source: source, context: context, helperText: helperText, placeholder: placeholder, userResource: userResource, mentions: mentions })=>{
|
|
725
846
|
const record = (0, $583VT$reactadmin.useRecordContext)();
|
|
726
|
-
const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $
|
|
847
|
+
const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)(record.replies);
|
|
727
848
|
if (!userResource) throw new Error("No userResource defined for CommentsField");
|
|
728
849
|
return /*#__PURE__*/ (0, $583VT$reactjsxruntime.jsxs)((0, $583VT$reactjsxruntime.Fragment), {
|
|
729
850
|
children: [
|
|
@@ -759,7 +880,7 @@ var $2e5504cc4159ca8d$export$2e2bcd8739ae039 = $2e5504cc4159ca8d$var$CommentsFie
|
|
|
759
880
|
|
|
760
881
|
const $505d598a33288aad$var$CollectionList = ({ collectionUrl: collectionUrl, resource: resource, children: children })=>{
|
|
761
882
|
if ((0, ($parcel$interopDefault($583VT$react))).Children.count(children) !== 1) throw new Error("<CollectionList> only accepts a single child");
|
|
762
|
-
const { items: actorsUris } = (0, $
|
|
883
|
+
const { items: actorsUris } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)(collectionUrl);
|
|
763
884
|
const { data: data, isLoading: isLoading, isFetching: isFetching } = (0, $583VT$reactadmin.useGetMany)(resource, {
|
|
764
885
|
ids: Array.isArray(actorsUris) ? actorsUris : [
|
|
765
886
|
actorsUris
|
|
@@ -802,302 +923,49 @@ var $b0c94a9bdea99da5$export$2e2bcd8739ae039 = $b0c94a9bdea99da5$var$ReferenceCo
|
|
|
802
923
|
|
|
803
924
|
|
|
804
925
|
|
|
805
|
-
|
|
806
|
-
const $5ca5f7e9fc1c3544$var$useItemsFromPages = (pages, dereferenceItems)=>{
|
|
807
|
-
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
808
|
-
const items = (0, $583VT$react.useMemo)(()=>pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
|
|
809
|
-
pages
|
|
810
|
-
]);
|
|
811
|
-
// We will force dereference, if some items are not URI string references.
|
|
812
|
-
const shouldDereference = (0, $583VT$react.useMemo)(()=>{
|
|
813
|
-
return dereferenceItems || items.some((item)=>typeof item !== "string");
|
|
814
|
-
}, [
|
|
815
|
-
dereferenceItems,
|
|
816
|
-
items
|
|
817
|
-
]);
|
|
818
|
-
// Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
|
|
819
|
-
const itemQueries = (0, $583VT$reactquery.useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
820
|
-
queryKey: [
|
|
821
|
-
"resource",
|
|
822
|
-
itemUri
|
|
823
|
-
],
|
|
824
|
-
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
825
|
-
staleTime: Infinity
|
|
826
|
-
})));
|
|
827
|
-
if (!shouldDereference) return {
|
|
828
|
-
loadedItems: items,
|
|
829
|
-
isLoading: false,
|
|
830
|
-
isFetching: false
|
|
831
|
-
};
|
|
832
|
-
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
833
|
-
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
834
|
-
return itemQuery.isSuccess && itemQuery.data || [];
|
|
835
|
-
}));
|
|
836
|
-
const errors = itemQueries.filter((q)=>q.error);
|
|
837
|
-
return {
|
|
838
|
-
loadedItems: loadedItems,
|
|
839
|
-
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
840
|
-
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
841
|
-
errors: errors.length > 0 ? errors : undefined
|
|
842
|
-
};
|
|
843
|
-
};
|
|
844
926
|
/**
|
|
845
|
-
*
|
|
846
|
-
*
|
|
927
|
+
* Hook to fetch the inbox of the logged user.
|
|
928
|
+
* Returns the same data as the useCollection hooks, plus:
|
|
929
|
+
* - `awaitActivity`: a function to wait for a certain activity to be received
|
|
930
|
+
* - `owner`: the WebID of the inbox's owner
|
|
931
|
+
* See https://semapps.org/docs/frontend/activitypub-components#useinbox for usage
|
|
847
932
|
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
848
|
-
*/ const $
|
|
849
|
-
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
933
|
+
*/ const $486f741c94cd8f74$var$useInbox = (options = {})=>{
|
|
850
934
|
const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
|
|
851
|
-
const
|
|
852
|
-
const
|
|
853
|
-
const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
|
|
854
|
-
status: "connecting"
|
|
855
|
-
});
|
|
856
|
-
const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
|
|
857
|
-
// Get collectionUrl from webId predicate or URL.
|
|
858
|
-
const collectionUrl = (0, $583VT$react.useMemo)(()=>{
|
|
859
|
-
if (predicateOrUrl) {
|
|
860
|
-
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
861
|
-
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
862
|
-
}
|
|
863
|
-
return undefined;
|
|
864
|
-
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
865
|
-
}, [
|
|
866
|
-
identity,
|
|
867
|
-
predicateOrUrl
|
|
868
|
-
]);
|
|
869
|
-
// Fetch page of collection item references (if pageParam provided)
|
|
870
|
-
// or default to `collectionUrl` (which should give you the first page).
|
|
871
|
-
const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
872
|
-
// Fetch page or first page (collectionUrl)
|
|
873
|
-
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
874
|
-
if (json.totalItems) setTotalItems(json.totalItems);
|
|
875
|
-
// If first page, handle this here.
|
|
876
|
-
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
877
|
-
if (json.first?.items) {
|
|
878
|
-
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
879
|
-
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
880
|
-
else json = json.first;
|
|
881
|
-
} else // Fetch the first page
|
|
882
|
-
({ json: json } = await dataProvider.fetch(json.first));
|
|
883
|
-
}
|
|
884
|
-
return json;
|
|
885
|
-
}, [
|
|
886
|
-
dataProvider,
|
|
887
|
-
collectionUrl,
|
|
888
|
-
identity,
|
|
889
|
-
setTotalItems
|
|
890
|
-
]);
|
|
891
|
-
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
892
|
-
const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
|
|
893
|
-
"collection",
|
|
894
|
-
{
|
|
895
|
-
collectionUrl: collectionUrl
|
|
896
|
-
}
|
|
897
|
-
], fetchCollection, {
|
|
898
|
-
enabled: !!(collectionUrl && identity?.id),
|
|
899
|
-
getNextPageParam: (lastPage)=>lastPage.next,
|
|
900
|
-
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
901
|
-
});
|
|
902
|
-
// Put all items together in a list (and dereference, if required).
|
|
903
|
-
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $5ca5f7e9fc1c3544$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
|
|
904
|
-
const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
|
|
905
|
-
const addItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
|
|
906
|
-
queryClient.setQueryData([
|
|
907
|
-
"collection",
|
|
908
|
-
{
|
|
909
|
-
collectionUrl: collectionUrl
|
|
910
|
-
}
|
|
911
|
-
], (oldData)=>{
|
|
912
|
-
if (!oldData) return oldData;
|
|
913
|
-
setTotalItems(totalItems && totalItems + 1);
|
|
914
|
-
// Destructure, so react knows, it needs to re-render the pages.
|
|
915
|
-
const pages = [
|
|
916
|
-
...oldData.pages
|
|
917
|
-
];
|
|
918
|
-
const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
|
|
919
|
-
firstPageItems.unshift(item);
|
|
920
|
-
oldData.pages = pages;
|
|
921
|
-
return oldData;
|
|
922
|
-
});
|
|
923
|
-
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
924
|
-
"collection",
|
|
925
|
-
{
|
|
926
|
-
collectionUrl: collectionUrl
|
|
927
|
-
}
|
|
928
|
-
], {
|
|
929
|
-
active: true,
|
|
930
|
-
exact: true
|
|
931
|
-
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
932
|
-
}, [
|
|
933
|
-
queryClient,
|
|
934
|
-
collectionUrl
|
|
935
|
-
]);
|
|
936
|
-
const removeItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
|
|
937
|
-
queryClient.setQueryData([
|
|
938
|
-
"collection",
|
|
939
|
-
{
|
|
940
|
-
collectionUrl: collectionUrl
|
|
941
|
-
}
|
|
942
|
-
], (oldData)=>{
|
|
943
|
-
if (!oldData) return oldData;
|
|
944
|
-
setTotalItems(totalItems && totalItems - 1);
|
|
945
|
-
// Destructure, so react knows, it needs to re-render the pages array.
|
|
946
|
-
const pages = [
|
|
947
|
-
...oldData.pages
|
|
948
|
-
];
|
|
949
|
-
// Find the item in all pages and remove the item to be removed (either item.id or just item)
|
|
950
|
-
pages.forEach((page)=>{
|
|
951
|
-
if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
|
|
952
|
-
else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
|
|
953
|
-
});
|
|
954
|
-
oldData.pages = pages;
|
|
955
|
-
return oldData;
|
|
956
|
-
});
|
|
957
|
-
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
958
|
-
"collection",
|
|
959
|
-
{
|
|
960
|
-
collectionUrl: collectionUrl
|
|
961
|
-
}
|
|
962
|
-
], {
|
|
963
|
-
active: true,
|
|
964
|
-
exact: true
|
|
965
|
-
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
966
|
-
}, [
|
|
967
|
-
queryClient,
|
|
968
|
-
collectionUrl
|
|
969
|
-
]);
|
|
970
|
-
// Live Updates
|
|
971
|
-
(0, $583VT$react.useEffect)(()=>{
|
|
972
|
-
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
973
|
-
(0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
|
|
974
|
-
webSocket.addEventListener("message", (e)=>{
|
|
975
|
-
const data = JSON.parse(e.data);
|
|
976
|
-
if (data && data.type === "Add") addItem(data.object, true);
|
|
977
|
-
else if (data && data.type === "Remove") removeItem(data.object, true);
|
|
978
|
-
});
|
|
979
|
-
webSocket.addEventListener("error", (e)=>{
|
|
980
|
-
setHasLiveUpdates({
|
|
981
|
-
status: "error",
|
|
982
|
-
error: e
|
|
983
|
-
});
|
|
984
|
-
// TODO: Retry after a while
|
|
985
|
-
});
|
|
986
|
-
webSocket.addEventListener("close", (e)=>{
|
|
987
|
-
if (!hasLiveUpdates.error) setHasLiveUpdates({
|
|
988
|
-
...hasLiveUpdates,
|
|
989
|
-
status: "closed"
|
|
990
|
-
});
|
|
991
|
-
});
|
|
992
|
-
setHasLiveUpdates({
|
|
993
|
-
status: "connected"
|
|
994
|
-
});
|
|
995
|
-
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
996
|
-
}, [
|
|
997
|
-
collectionUrl,
|
|
998
|
-
liveUpdates,
|
|
999
|
-
dataProvider
|
|
1000
|
-
]);
|
|
935
|
+
const { url: url, items: items, awaitWebSocketConnection: awaitWebSocketConnection, ...rest } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)("inbox", options);
|
|
936
|
+
const awaitActivity = (0, $5e70f9d0635e25dd$export$2e2bcd8739ae039)(awaitWebSocketConnection, items);
|
|
1001
937
|
return {
|
|
938
|
+
url: url,
|
|
1002
939
|
items: items,
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
addItem: addItem,
|
|
1008
|
-
removeItem: removeItem,
|
|
1009
|
-
hasNextPage: hasNextPage,
|
|
1010
|
-
isLoading: isLoadingPage || isLoadingItems,
|
|
1011
|
-
isFetching: isFetchingPage || isFetchingItems,
|
|
1012
|
-
isFetchingNextPage: isFetchingNextPage,
|
|
1013
|
-
url: collectionUrl,
|
|
1014
|
-
hasLiveUpdates: hasLiveUpdates
|
|
940
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
941
|
+
awaitActivity: awaitActivity,
|
|
942
|
+
owner: identity?.id,
|
|
943
|
+
...rest
|
|
1015
944
|
};
|
|
1016
945
|
};
|
|
1017
|
-
var $
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
const $97664763db3c0a46$var$useInbox = ()=>{
|
|
1024
|
-
const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
|
|
1025
|
-
const inboxUrl = (0, $583VT$react.useMemo)(()=>{
|
|
1026
|
-
if (identity?.webIdData) return identity?.webIdData?.inbox;
|
|
1027
|
-
}, [
|
|
1028
|
-
identity
|
|
1029
|
-
]);
|
|
1030
|
-
const sparqlEndpoint = (0, $583VT$react.useMemo)(()=>{
|
|
1031
|
-
if (identity?.webIdData) return identity?.webIdData?.endpoints?.["void:sparqlEndpoint"] || `${identity?.id}/sparql`;
|
|
1032
|
-
}, [
|
|
1033
|
-
identity
|
|
1034
|
-
]);
|
|
1035
|
-
const fetch = (0, $583VT$react.useCallback)(async ({ filters: filters })=>{
|
|
1036
|
-
if (!sparqlEndpoint || !inboxUrl) return;
|
|
1037
|
-
const token = localStorage.getItem("token");
|
|
1038
|
-
const blankNodesQuery = (0, $583VT$semappssemanticdataprovider.buildBlankNodesQuery)([
|
|
1039
|
-
"as:object"
|
|
1040
|
-
]);
|
|
1041
|
-
let filtersWhereQuery = "";
|
|
1042
|
-
if (filters) Object.keys(filters).forEach((predicate)=>{
|
|
1043
|
-
if (filters[predicate]) {
|
|
1044
|
-
const object = filters[predicate].startsWith("http") ? `<${filters[predicate]}>` : filters[predicate];
|
|
1045
|
-
filtersWhereQuery += `?s1 ${predicate} ${object} .`;
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
1048
|
-
const query = `
|
|
1049
|
-
PREFIX as: <https://www.w3.org/ns/activitystreams#>
|
|
1050
|
-
CONSTRUCT {
|
|
1051
|
-
?s1 ?p1 ?o1 .
|
|
1052
|
-
${blankNodesQuery.construct}
|
|
1053
|
-
}
|
|
1054
|
-
WHERE {
|
|
1055
|
-
<${inboxUrl}> as:items ?s1 .
|
|
1056
|
-
?s1 ?p1 ?o1 .
|
|
1057
|
-
FILTER( (isIRI(?s1)) ) .
|
|
1058
|
-
${filtersWhereQuery}
|
|
1059
|
-
${blankNodesQuery.where}
|
|
1060
|
-
}
|
|
1061
|
-
`;
|
|
1062
|
-
const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(sparqlEndpoint, {
|
|
1063
|
-
method: "POST",
|
|
1064
|
-
body: query,
|
|
1065
|
-
headers: new Headers({
|
|
1066
|
-
Accept: "application/ld+json",
|
|
1067
|
-
Authorization: token ? `Bearer ${token}` : undefined
|
|
1068
|
-
})
|
|
1069
|
-
});
|
|
1070
|
-
if (json["@graph"]) return json["@graph"];
|
|
1071
|
-
return null;
|
|
1072
|
-
}, [
|
|
1073
|
-
sparqlEndpoint,
|
|
1074
|
-
inboxUrl
|
|
1075
|
-
]);
|
|
1076
|
-
return {
|
|
1077
|
-
fetch: fetch,
|
|
1078
|
-
url: inboxUrl,
|
|
1079
|
-
owner: identity?.id
|
|
1080
|
-
};
|
|
1081
|
-
};
|
|
1082
|
-
var $97664763db3c0a46$export$2e2bcd8739ae039 = $97664763db3c0a46$var$useInbox;
|
|
946
|
+
var $486f741c94cd8f74$export$2e2bcd8739ae039 = $486f741c94cd8f74$var$useInbox;
|
|
1083
947
|
|
|
1084
948
|
|
|
1085
949
|
|
|
1086
950
|
|
|
1087
|
-
const $
|
|
951
|
+
const $59fc2d2cba62bd8e$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora.software/ns/schema/2.1")=>{
|
|
1088
952
|
const [schema, setSchema] = (0, $583VT$react.useState)();
|
|
1089
953
|
(0, $583VT$react.useEffect)(()=>{
|
|
1090
954
|
(async ()=>{
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
955
|
+
if (host && rel) {
|
|
956
|
+
const protocol = host.includes(":") ? "http" : "https"; // If the host has a port, we are likely on HTTP
|
|
957
|
+
const nodeinfoUrl = `${protocol}://${host}/.well-known/nodeinfo`;
|
|
958
|
+
try {
|
|
959
|
+
const { json: links } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(nodeinfoUrl);
|
|
960
|
+
// Accept any version of the nodeinfo protocol
|
|
961
|
+
const link = links?.links?.find((l)=>l.rel === rel);
|
|
962
|
+
if (link) {
|
|
963
|
+
const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(link.href);
|
|
964
|
+
setSchema(json);
|
|
965
|
+
}
|
|
966
|
+
} catch (e) {
|
|
967
|
+
// Do nothing if nodeinfo can't be fetched
|
|
968
|
+
}
|
|
1101
969
|
}
|
|
1102
970
|
})();
|
|
1103
971
|
}, [
|
|
@@ -1107,7 +975,7 @@ const $30fd77858150739b$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora
|
|
|
1107
975
|
]);
|
|
1108
976
|
return schema;
|
|
1109
977
|
};
|
|
1110
|
-
var $
|
|
978
|
+
var $59fc2d2cba62bd8e$export$2e2bcd8739ae039 = $59fc2d2cba62bd8e$var$useNodeinfo;
|
|
1111
979
|
|
|
1112
980
|
|
|
1113
981
|
|