linked-data-browser 0.0.2 → 0.0.4

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.
Files changed (47) hide show
  1. package/.ldo/profile.context.ts +14 -0
  2. package/.ldo/profile.typings.ts +6 -4
  3. package/app/index.tsx +2 -1
  4. package/components/ResourceView.tsx +7 -2
  5. package/components/common/LoadingBar.tsx +27 -0
  6. package/components/common/ProfileAvatar.tsx +28 -0
  7. package/components/nav/DialogProvider.tsx +5 -8
  8. package/components/nav/Layout.tsx +20 -81
  9. package/components/nav/header/AddressBox.tsx +8 -7
  10. package/components/nav/header/AvatarMenu.tsx +54 -57
  11. package/components/nav/header/Header.tsx +18 -2
  12. package/components/nav/header/SignInMenu.tsx +11 -14
  13. package/components/nav/header/ViewMenu.tsx +4 -4
  14. package/components/sharing/AccessDropdown.tsx +95 -0
  15. package/components/sharing/CopyLink.tsx +21 -0
  16. package/components/sharing/PermissionRow.tsx +38 -0
  17. package/components/sharing/SharingModal.tsx +149 -0
  18. package/components/sharing/WacRuleForm.tsx +44 -0
  19. package/components/sharing/agentPermissions/AgentInformation.tsx +37 -0
  20. package/components/sharing/agentPermissions/AgentInput.tsx +126 -0
  21. package/components/sharing/agentPermissions/AgentPermissionRow.tsx +36 -0
  22. package/components/sharing/agentPermissions/AgentPermissions.tsx +56 -0
  23. package/components/sharing/agentPermissions/useContactFilter.ts +35 -0
  24. package/components/ui/button.tsx +52 -5
  25. package/components/ui/dialog.tsx +1 -1
  26. package/components/ui/input-dropdown.tsx +105 -0
  27. package/components/ui/input.tsx +34 -2
  28. package/components/ui/text.tsx +47 -0
  29. package/components/useViewContext.tsx +141 -0
  30. package/components/{nav/utilityResourceViews → utilityResourceViews}/ErrorMessageResourceView.tsx +2 -2
  31. package/lib/icons/Fingerprint.tsx +4 -0
  32. package/lib/icons/Link.tsx +4 -0
  33. package/lib/icons/Loader.tsx +4 -0
  34. package/lib/icons/LogOut.tsx +4 -0
  35. package/lib/icons/Plus.tsx +4 -0
  36. package/lib/icons/Save.tsx +4 -0
  37. package/lib/icons/User.tsx +4 -0
  38. package/lib/icons/UserPlus.tsx +4 -0
  39. package/lib/icons/Users.tsx +4 -0
  40. package/package.json +12 -7
  41. package/resourceViews/Container/ContainerView.tsx +5 -6
  42. package/resourceViews/Profile/ProfileConfig.tsx +20 -0
  43. package/resourceViews/Profile/ProfileKnows.tsx +65 -0
  44. package/resourceViews/Profile/ProfileView.tsx +59 -0
  45. package/resourceViews/RawCode/RawCodeView.tsx +35 -9
  46. package/test-server/server-config.json +1 -1
  47. package/components/nav/useValidView.tsx +0 -51
@@ -0,0 +1,65 @@
1
+ import { Input } from '../../components/ui/input';
2
+ import React, { FunctionComponent, useCallback, useState } from 'react';
3
+ import { Plus } from '../../lib/icons/Plus';
4
+ import { SolidProfileShape } from '.ldo/profile.typings';
5
+ import { AgentInformation } from '../../components/sharing/agentPermissions/AgentInformation';
6
+ import { View } from 'react-native';
7
+ import { useChangeSetData } from '@ldo/react';
8
+ import { SolidLeaf } from '@ldo/connected-solid';
9
+ import { Button } from '../../components/ui/button';
10
+ import { Trash } from '../../lib/icons/Trash';
11
+
12
+ export interface ProfileKnowsProps {
13
+ resource: SolidLeaf;
14
+ profile: SolidProfileShape;
15
+ setProfile: useChangeSetData<SolidProfileShape, any>;
16
+ }
17
+
18
+ export const ProfileKnows: FunctionComponent<ProfileKnowsProps> = ({
19
+ resource,
20
+ profile,
21
+ setProfile,
22
+ }) => {
23
+ console.log(profile.knows?.size);
24
+
25
+ const [newContact, setNewContact] = useState('');
26
+ const addNewContact = useCallback(() => {
27
+ setProfile(resource, (cProfile) => {
28
+ cProfile.knows?.add({ '@id': newContact });
29
+ });
30
+ setNewContact('');
31
+ }, [newContact, resource, setProfile]);
32
+
33
+ return (
34
+ <View className="gap-4">
35
+ <Input
36
+ placeholder="https://example.pod/john/profile/card#me"
37
+ label="New Contact WebId"
38
+ buttonRight={{
39
+ iconRight: <Plus />,
40
+ onPress: addNewContact,
41
+ variant: 'secondary',
42
+ }}
43
+ value={newContact}
44
+ onChangeText={setNewContact}
45
+ onSubmitEditing={addNewContact}
46
+ />
47
+ {profile.knows?.map((friend) => (
48
+ <AgentInformation
49
+ webId={friend['@id']}
50
+ accessoryRight={
51
+ <Button
52
+ variant="ghost"
53
+ iconRight={<Trash />}
54
+ onPress={() => {
55
+ setProfile(resource, (cProfile) => {
56
+ cProfile.knows?.delete(friend);
57
+ });
58
+ }}
59
+ />
60
+ }
61
+ />
62
+ ))}
63
+ </View>
64
+ );
65
+ };
@@ -0,0 +1,59 @@
1
+ import { ScrollView, View } from 'react-native';
2
+ import { Text } from '../../components/ui/text';
3
+ import React, { FunctionComponent } from 'react';
4
+ import { Input } from '../../components/ui/input';
5
+ import { Separator } from '../../components/ui/separator';
6
+ import { ProfileKnows } from './ProfileKnows';
7
+ import { useViewContext } from 'components/useViewContext';
8
+ import { SolidProfileShapeShapeType } from '.ldo/profile.shapeTypes';
9
+ import { useChangeSubject, useResource } from '@ldo/solid-react';
10
+ import { Button } from '../../components/ui/button';
11
+ import { SolidLeaf } from '@ldo/connected-solid';
12
+
13
+ export const ProfileView: FunctionComponent = () => {
14
+ const { targetUri } = useViewContext();
15
+
16
+ const profileResource = useResource(targetUri);
17
+ const [profile, setProfile, commitProfile, transactionDataset] =
18
+ useChangeSubject(SolidProfileShapeShapeType, targetUri);
19
+
20
+ if (
21
+ !targetUri ||
22
+ !profileResource ||
23
+ !profile ||
24
+ profileResource.type === 'InvalidIdentifierResource'
25
+ )
26
+ return <></>;
27
+
28
+ return (
29
+ <ScrollView contentContainerClassName="flex-row justify-center p-4">
30
+ <View className="max-w-[600px] flex-1 padding gap-4">
31
+ <Text variant="h1">Profile</Text>
32
+ <Input
33
+ placeholder="John Doe"
34
+ label="Name"
35
+ value={profile?.fn}
36
+ onChangeText={(text) => {
37
+ setProfile(profileResource, (cProfile) => {
38
+ cProfile!.fn = text;
39
+ });
40
+ }}
41
+ />
42
+ <Separator />
43
+ <Text variant="h2">Contacts</Text>
44
+ <ProfileKnows
45
+ profile={profile}
46
+ setProfile={setProfile}
47
+ resource={profileResource as SolidLeaf}
48
+ />
49
+ <Button
50
+ disabled={!transactionDataset.hasChanges()}
51
+ text="Update Profile"
52
+ className="self-end"
53
+ onPress={commitProfile}
54
+ isLoading={profileResource.isLoading()}
55
+ />
56
+ </View>
57
+ </ScrollView>
58
+ );
59
+ };
@@ -5,21 +5,30 @@ import React, {
5
5
  useEffect,
6
6
  useState,
7
7
  } from 'react';
8
- import { useTargetResource } from '../../components/TargetResourceProvider';
9
8
  import { RawCodeEditor } from './RawCodeEditor';
10
9
  import { View } from 'react-native';
11
10
  import { Button } from '../../components/ui/button';
12
11
  import { Text } from '../../components/ui/text';
13
12
  import { Notifier } from 'react-native-notifier';
13
+ import { useViewContext } from '../../components/useViewContext';
14
+ import { LoadingBar } from '../../components/common/LoadingBar';
15
+ import { Save } from "../../lib/icons/Save";
14
16
 
15
17
  export const RawCodeView: FunctionComponent = () => {
16
- const { targetUri } = useTargetResource();
17
18
  const { fetch } = useSolidAuth();
18
19
  const [content, setContent] = useState<string>('');
20
+ const [contentType, setContentType] = useState<string>('');
21
+ const [didEdit, setDidEdit] = useState(false);
22
+ const { curViewConfig, targetResource } = useViewContext();
23
+ const [isFetching, setIsFetching] = useState(false);
24
+ const [isSaving, setIsSaving] = useState(false);
25
+
26
+ const targetUri = targetResource?.uri;
19
27
 
20
28
  // Independently fetch the target resource, so we have the raw turtle
21
29
  const fetchContent = useCallback(async () => {
22
- if (!targetUri) return;
30
+ if (!targetUri || curViewConfig.name !== 'rawCode') return;
31
+ setIsFetching(true);
23
32
  const response = await fetch(targetUri);
24
33
  if (response.status !== 200) {
25
34
  Notifier.showNotification({
@@ -27,24 +36,35 @@ export const RawCodeView: FunctionComponent = () => {
27
36
  });
28
37
  }
29
38
  setContent(await response.text());
30
- }, [fetch, targetUri]);
39
+ setIsFetching(false);
40
+ setDidEdit(false);
41
+ setContentType(response.headers.get('content-type') ?? '');
42
+ }, [curViewConfig.name, fetch, targetUri]);
31
43
 
32
44
  const submitChanges = useCallback(async () => {
33
45
  if (!targetUri) return;
46
+ setIsSaving(true);
34
47
  const response = await fetch(targetUri, {
35
48
  method: 'put',
49
+ headers: {
50
+ 'content-type': contentType,
51
+ },
36
52
  body: content,
37
53
  });
38
54
  if (response.status !== 205) {
39
55
  Notifier.showNotification({
40
56
  title: `Could save document. Recieved ${response.status}`,
41
57
  });
58
+ setIsSaving(false);
59
+ return;
42
60
  }
43
61
  Notifier.showNotification({
44
62
  title: `Document Saved`,
45
63
  });
46
64
  await fetchContent();
47
- }, [content, fetch, fetchContent, targetUri]);
65
+ setIsSaving(false);
66
+ setDidEdit(false);
67
+ }, [content, contentType, fetch, fetchContent, targetUri]);
48
68
 
49
69
  useEffect(() => {
50
70
  fetchContent();
@@ -52,16 +72,22 @@ export const RawCodeView: FunctionComponent = () => {
52
72
 
53
73
  return (
54
74
  <View className="flex-1 relative">
75
+ <LoadingBar isLoading={isFetching || isSaving} />
55
76
  <RawCodeEditor
56
77
  value={content}
57
- onChange={(value) => setContent(value ?? '')}
78
+ onChange={(value) => {
79
+ setDidEdit(true);
80
+ setContent(value ?? '');
81
+ }}
58
82
  />
59
83
  <Button
60
84
  className="absolute bottom-2 right-2 z-10"
61
85
  onPress={submitChanges}
62
- >
63
- <Text>Save Changes</Text>
64
- </Button>
86
+ text="Save Changes"
87
+ iconLeft={<Save />}
88
+ isLoading={isSaving}
89
+ disabled={!didEdit || isSaving}
90
+ />
65
91
  </View>
66
92
  );
67
93
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "@context": [
3
- "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld"
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld"
4
4
  ],
5
5
  "import": [
6
6
  "css:config/app/init/default.json",
@@ -1,51 +0,0 @@
1
- import createContainer from 'constate';
2
- import React, { useEffect, useMemo, useState } from 'react';
3
- import { useDataBrowserConfig } from '../DataBrowser';
4
- import { useTargetResource } from '../TargetResourceProvider';
5
- import { ResourceViewConfig } from '../ResourceView';
6
- import { EyeOff } from '../../lib/icons/EyeOff';
7
- import { ErrorMessageResourceView } from './utilityResourceViews/ErrorMessageResourceView';
8
-
9
- export const [ValidViewProvider, useValidView] = createContainer(() => {
10
- const { targetUri, targetResource } = useTargetResource();
11
- const { views } = useDataBrowserConfig();
12
-
13
- const validViews = useMemo(() => {
14
- const noValidView: ResourceViewConfig = {
15
- name: 'noValid',
16
- displayName: 'No Valid View',
17
- displayIcon: EyeOff,
18
- view: () => (
19
- <ErrorMessageResourceView
20
- icon={EyeOff}
21
- message="No Views are available to display this resource."
22
- />
23
- ),
24
- canDisplay: () => false,
25
- };
26
- if (
27
- !targetResource ||
28
- !targetUri ||
29
- targetResource.type === 'InvalidIdentifierResouce'
30
- ) {
31
- return [noValidView];
32
- }
33
- const potentialViews = views.filter((view) =>
34
- view.canDisplay(targetUri, targetResource),
35
- );
36
- return potentialViews.length > 0 ? potentialViews : [noValidView];
37
- }, [targetResource, targetUri, views]);
38
-
39
- const [curViewConfig, setCurViewConfig] = useState<ResourceViewConfig>(
40
- validViews[0],
41
- );
42
- useEffect(() => {
43
- setCurViewConfig(validViews[0]);
44
- }, [targetUri, validViews]);
45
-
46
- return {
47
- validViews,
48
- curViewConfig,
49
- setCurViewConfig,
50
- };
51
- });