diff --git a/config/solid-server/readme.md b/config/solid-server/readme.md new file mode 100644 index 000000000..39fdf5867 --- /dev/null +++ b/config/solid-server/readme.md @@ -0,0 +1,3 @@ +solid-remote-server-compose.yaml && solid-remote-server-config.json are templates for deploying the server remotely. The server URL can be updated as needed, the current setup is for our deployment on opencommons. + +The config should be stored as /config/solid-server/solid-config.json and solid-remote-server-compose.yaml stored at the community solid server root. diff --git a/config/solid-server/solid-remote-server-compose.yaml b/config/solid-server/solid-remote-server-compose.yaml new file mode 100644 index 000000000..dca990d5d --- /dev/null +++ b/config/solid-server/solid-remote-server-compose.yaml @@ -0,0 +1,13 @@ +services: + solid-server: + image: solidproject/community-server:7.0 + restart: always + user: root + ports: + - '3000:3000' + environment: + - BASE_URL=https://opencommons.net + command: ['--baseUrl', 'https://opencommons.net'] + volumes: + - ./data/solid-data:/data + - ./config/solid-server/solid-config.json:/community-server/config/my-config.json diff --git a/config/solid-server/solid-remote-server-config.json b/config/solid-server/solid-remote-server-config.json new file mode 100644 index 000000000..2689a2c5f --- /dev/null +++ b/config/solid-server/solid-remote-server-config.json @@ -0,0 +1,51 @@ +{ + "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld", + "import": [ + "css:config/app/init/static-root.json", + "css:config/app/main/default.json", + "css:config/app/variables/default.json", + "css:config/http/handler/default.json", + "css:config/http/middleware/default.json", + "css:config/http/notifications/all.json", + "css:config/http/server-factory/http.json", + "css:config/http/static/default.json", + "css:config/identity/access/public.json", + "css:config/identity/email/default.json", + "css:config/identity/handler/default.json", + "css:config/identity/oidc/default.json", + "css:config/identity/ownership/token.json", + "css:config/identity/pod/static.json", + "css:config/ldp/authentication/dpop-bearer.json", + "css:config/ldp/authorization/webacl.json", + "css:config/ldp/handler/default.json", + "css:config/ldp/metadata-parser/default.json", + "css:config/ldp/metadata-writer/default.json", + "css:config/ldp/modes/default.json", + "css:config/storage/backend/file.json", + "css:config/storage/key-value/resource-store.json", + "css:config/storage/location/pod.json", + "css:config/storage/middleware/default.json", + "css:config/util/auxiliary/acl.json", + "css:config/util/identifiers/suffix.json", + "css:config/util/index/default.json", + "css:config/util/logging/winston.json", + "css:config/util/representation-conversion/default.json", + "css:config/util/resource-locker/file.json", + "css:config/util/variables/default.json" + ], + "@graph": [], + "servers": [ + { + "serverUri": "https://opencommons.net/", + "locations": [ + { + "url": "https://opencommons.net/", + "availableMediaTypes": ["text/turtle"], + "basePath": "/", + "description": "This config was generated by generator and very basic" + } + ] + } + ], + "baseUrl": "https://opencommons.net/" +} diff --git a/env.template b/env.template index bbf2be67b..73ac46a5d 100644 --- a/env.template +++ b/env.template @@ -1,5 +1,5 @@ VITE_SOLID_IDENTITY_PROVIDER="http://localhost:3000/" VITE_SOLID_POD_SERVER="http://localhost:3000/" VITE_SUGGESTED_OIDC_OPTIONS="http://localhost:3000/, https://opencommons.net/, https://solidcommunity.net/, https://login.inrupt.com/, https://inrupt.net/" -VITE_OIDC_WEBIDS = '{"http://localhost:3000/": "http://localhost:3000/user/profile/card#me", "https://opencommons.net/": "http://opencommons.net/user/profile/card#me", "https://solidcommunity.net/": "https://user.solidcommunity.net/profile/card#me", "https://login.inrupt.com/": "https://id.inrupt.com/user", "https://inrupt.net/": "https://id.inrupt.com/user"}' +VITE_OIDC_WEBIDS = '{"http://localhost:3000/": "http://localhost:3000/user/profile/card#me", "https://opencommons.net/": "https://opencommons.net/user/profile/card#me", "https://solidcommunity.net/": "https://user.solidcommunity.net/profile/card#me", "https://login.inrupt.com/": "https://id.inrupt.com/user", "https://inrupt.net/": "https://id.inrupt.com/user"}' VITE_CLIENT_ID_DOC="http://localhost:3000/clientAppId.json" diff --git a/package-lock.json b/package-lock.json index f831c763b..3b919ebdf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pass", - "version": "1.1.0-alpha", + "version": "1.2.0-alpha", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pass", - "version": "1.1.0-alpha", + "version": "1.2.0-alpha", "license": "MIT", "dependencies": { "@emotion/react": "^11.10.8", @@ -3825,21 +3825,32 @@ "license": "MIT" }, "node_modules/@solid/access-token-verifier": { - "version": "2.0.5", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solid/access-token-verifier/-/access-token-verifier-2.1.0.tgz", + "integrity": "sha512-79u92GD1SBTxjYghg2ta6cfoBNZ5ljz/9zE6RmXUypTXW7oI18DTWiSrEjWwI4njW+OMh+4ih+sAR6AkI1IFxg==", "dev": true, - "license": "MIT", "dependencies": { - "jose": "^4.10.3", + "jose": "^5.1.3", "lru-cache": "^6.0.0", - "n3": "^1.16.2", - "node-fetch": "^2.6.7", + "n3": "^1.17.1", + "node-fetch": "^2.7.0", "ts-guards": "^0.5.1" } }, + "node_modules/@solid/access-token-verifier/node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@solid/access-token-verifier/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -3849,20 +3860,21 @@ }, "node_modules/@solid/access-token-verifier/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/@solid/community-server": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@solid/community-server/-/community-server-7.0.3.tgz", - "integrity": "sha512-YLmuE7yLjOjiGmpyuPJ+Q058dMGrmMTsduo1aXW6JlMS7pwDjNawBQ3Y029K2QCRUHJSZaNqVXqPdIiJqcKoFA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@solid/community-server/-/community-server-7.1.3.tgz", + "integrity": "sha512-d5SZQ5cP/k887QnLly+AN6DnLnLumcQrddWqiw7tytFk1A8WxP+DSATLlBw0SSt1uABhi2xKXzuLDOuWP5zdaQ==", "dev": true, "dependencies": { "@comunica/context-entries": "^2.8.2", "@comunica/query-sparql": "^2.9.0", "@rdfjs/types": "^1.1.0", "@solid/access-control-policy": "^0.1.3", - "@solid/access-token-verifier": "^2.0.5", + "@solid/access-token-verifier": "^2.1.0", "@types/async-lock": "^1.4.0", "@types/bcryptjs": "^2.4.4", "@types/cookie": "^0.5.2", @@ -3889,7 +3901,7 @@ "async-lock": "^1.4.0", "bcryptjs": "^2.4.3", "componentsjs": "^5.4.2", - "cookie": "^0.5.0", + "cookie": "^0.7.0", "cors": "^2.8.5", "cross-fetch": "^4.0.0", "ejs": "^3.1.9", @@ -3906,7 +3918,7 @@ "marked": "^9.1.0", "mime-types": "^2.1.35", "n3": "^1.17.1", - "nodemailer": "^6.9.6", + "nodemailer": "^6.9.9", "oidc-provider": "^8.4.0", "proper-lockfile": "^4.1.2", "pump": "^3.0.0", @@ -5953,9 +5965,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "engines": { "node": ">= 0.6" @@ -6018,9 +6030,10 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6829,9 +6842,10 @@ "license": "MIT" }, "node_modules/eslint-config-esnext/node_modules/cross-spawn": { - "version": "6.0.5", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, - "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -7256,9 +7270,10 @@ "license": "MIT" }, "node_modules/eslint-config-node/node_modules/cross-spawn": { - "version": "6.0.5", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, - "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -10853,7 +10868,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -10861,7 +10878,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -11164,9 +11180,9 @@ } }, "node_modules/oidc-provider/node_modules/nanoid": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.4.tgz", - "integrity": "sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "dev": true, "funding": [ { @@ -12390,9 +12406,10 @@ } }, "node_modules/rollup": { - "version": "3.29.4", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, - "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -13485,8 +13502,9 @@ }, "node_modules/ts-guards": { "version": "0.5.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ts-guards/-/ts-guards-0.5.1.tgz", + "integrity": "sha512-Y6P/VJnwARiPMfxO7rvaYaz5tGQ5TQ0Wnb2cWIxMpFOioYkhsT8XaCrJX6wYPNFACa4UOrN5SPqhwpM8NolAhQ==", + "dev": true }, "node_modules/tsconfig-paths": { "version": "3.14.2", @@ -17373,18 +17391,28 @@ "dev": true }, "@solid/access-token-verifier": { - "version": "2.0.5", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solid/access-token-verifier/-/access-token-verifier-2.1.0.tgz", + "integrity": "sha512-79u92GD1SBTxjYghg2ta6cfoBNZ5ljz/9zE6RmXUypTXW7oI18DTWiSrEjWwI4njW+OMh+4ih+sAR6AkI1IFxg==", "dev": true, "requires": { - "jose": "^4.10.3", + "jose": "^5.1.3", "lru-cache": "^6.0.0", - "n3": "^1.16.2", - "node-fetch": "^2.6.7", + "n3": "^1.17.1", + "node-fetch": "^2.7.0", "ts-guards": "^0.5.1" }, "dependencies": { + "jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "dev": true + }, "lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -17392,21 +17420,23 @@ }, "yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@solid/community-server": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@solid/community-server/-/community-server-7.0.3.tgz", - "integrity": "sha512-YLmuE7yLjOjiGmpyuPJ+Q058dMGrmMTsduo1aXW6JlMS7pwDjNawBQ3Y029K2QCRUHJSZaNqVXqPdIiJqcKoFA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@solid/community-server/-/community-server-7.1.3.tgz", + "integrity": "sha512-d5SZQ5cP/k887QnLly+AN6DnLnLumcQrddWqiw7tytFk1A8WxP+DSATLlBw0SSt1uABhi2xKXzuLDOuWP5zdaQ==", "dev": true, "requires": { "@comunica/context-entries": "^2.8.2", "@comunica/query-sparql": "^2.9.0", "@rdfjs/types": "^1.1.0", "@solid/access-control-policy": "^0.1.3", - "@solid/access-token-verifier": "^2.0.5", + "@solid/access-token-verifier": "^2.1.0", "@types/async-lock": "^1.4.0", "@types/bcryptjs": "^2.4.4", "@types/cookie": "^0.5.2", @@ -17433,7 +17463,7 @@ "async-lock": "^1.4.0", "bcryptjs": "^2.4.3", "componentsjs": "^5.4.2", - "cookie": "^0.5.0", + "cookie": "^0.7.0", "cors": "^2.8.5", "cross-fetch": "^4.0.0", "ejs": "^3.1.9", @@ -17450,7 +17480,7 @@ "marked": "^9.1.0", "mime-types": "^2.1.35", "n3": "^1.17.1", - "nodemailer": "^6.9.6", + "nodemailer": "^6.9.9", "oidc-provider": "^8.4.0", "proper-lockfile": "^4.1.2", "pump": "^3.0.0", @@ -18886,9 +18916,9 @@ "version": "1.9.0" }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true }, "cookies": { @@ -18931,7 +18961,9 @@ } }, "cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -19507,7 +19539,9 @@ "dev": true }, "cross-spawn": { - "version": "6.0.5", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -19790,7 +19824,9 @@ "dev": true }, "cross-spawn": { - "version": "6.0.5", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -22081,7 +22117,9 @@ } }, "nanoid": { - "version": "3.3.6", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true }, "natural-compare": { @@ -22273,9 +22311,9 @@ "dev": true }, "nanoid": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.4.tgz", - "integrity": "sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "dev": true } } @@ -23087,7 +23125,9 @@ } }, "rollup": { - "version": "3.29.4", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -23790,6 +23830,8 @@ }, "ts-guards": { "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ts-guards/-/ts-guards-0.5.1.tgz", + "integrity": "sha512-Y6P/VJnwARiPMfxO7rvaYaz5tGQ5TQ0Wnb2cWIxMpFOioYkhsT8XaCrJX6wYPNFACa4UOrN5SPqhwpM8NolAhQ==", "dev": true }, "tsconfig-paths": { diff --git a/package.json b/package.json index 33e43f373..38fc8a926 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pass", "homepage": ".", - "version": "1.1.0-alpha", + "version": "1.2.0-alpha", "description": "", "scripts": { "start": "concurrently --kill-others \"npm run podserver\" \"npm run dev\"", diff --git a/src/components/Contacts/ContactListTableDesktop.jsx b/src/components/Contacts/ContactListTableDesktop.jsx index f4dfdef84..7f63053da 100644 --- a/src/components/Contacts/ContactListTableDesktop.jsx +++ b/src/components/Contacts/ContactListTableDesktop.jsx @@ -4,6 +4,7 @@ import React from 'react'; import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; import EditOutlined from '@mui/icons-material/EditOutlined'; import SendIcon from '@mui/icons-material/Send'; +import Typography from '@mui/material/Typography'; import { useTheme } from '@mui/material/styles'; import { DataGrid, @@ -12,6 +13,10 @@ import { GridToolbarFilterButton, GridToolbarDensitySelector } from '@mui/x-data-grid'; +// Custom Hooks Imports +import useNotification from '@hooks/useNotification'; +// Util Imports +import { saveToClipboard } from '@utils'; // Component Imports import ContactProfileIcon from './ContactProfileIcon'; @@ -49,6 +54,7 @@ const ContactListTableDesktop = ({ handleSendMessage, 'data-testid': dataTestId }) => { + const { addNotification } = useNotification(); const theme = useTheme(); const columnTitlesArray = [ @@ -68,6 +74,15 @@ const ContactListTableDesktop = ({ }, { field: 'webId', + renderCell: (contact) => ( + saveToClipboard(contact.id, 'webId copied to clipboard', addNotification)} + > + {contact.id} + + ), headerName: 'Web ID', minWidth: 150, flex: 1, @@ -101,7 +116,7 @@ const ContactListTableDesktop = ({ field: 'Edit', renderCell: (contact) => ( editContact(contact.row.Profile)} /> ), diff --git a/src/components/Contacts/ContactListTableMobile.jsx b/src/components/Contacts/ContactListTableMobile.jsx index 48ece5b3d..1f5478a6b 100644 --- a/src/components/Contacts/ContactListTableMobile.jsx +++ b/src/components/Contacts/ContactListTableMobile.jsx @@ -185,6 +185,18 @@ const ContactListTableMobile = ({ 'aria-labelledby': 'actions-icon-button' }} > + + saveToClipboard(contact.webId, 'webId copied to clipboard', addNotification), + contact + )} + startIcon={} + sx={iconStyling} + > + Copy WebId + Message - {/* TODO: Keep copy function? */} - {/* If so, also add to Desktop table? */} - {/* Maybe without any icon. Simply click on the web ID and it will copy? */} - - saveToClipboard(contact.webId, 'webId copied to clipboard', addNotification), - contact - )} - startIcon={} - sx={iconStyling} - > - Copy WebId - { const { session } = useSession(); const { documentListObject, loadingDocuments } = useContext(DocumentListContext); + const { addNotification } = useNotification(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const isSmallScreenHeight = useMediaQuery('(max-height: 600px)'); @@ -59,10 +60,21 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) => * @returns {Promise} A promise that resolves with the Blob of the document. * @throws {Error} Throws an error if there is an issue fetching the document blob. */ - const urlFileBlob = await getBlobFromSolid(session, urlToOpen); + try { + const urlFileBlob = await getBlobFromSolid(session, urlToOpen); - // Open a new window to display the document using the blob URL - window.open(urlFileBlob); + // Open a new window to display the document using the blob URL + window.open(urlFileBlob); + } catch (e) { + if (e?.statusCode === 403) { + addNotification('error', 'You do not have permission to view this document'); + } else { + addNotification( + 'error', + `Document preview failed. Reason: ${e?.message || 'Unknown error'}` + ); + } + } }; // Maps raw document types to user-friendly display names using `DOC_TYPES` diff --git a/src/components/Documents/DocumentsDesktop.jsx b/src/components/Documents/DocumentsDesktop.jsx index a93f58f05..2a2768668 100644 --- a/src/components/Documents/DocumentsDesktop.jsx +++ b/src/components/Documents/DocumentsDesktop.jsx @@ -14,8 +14,6 @@ import { } from '@mui/x-data-grid'; // Util Imports import { getTypeText } from '@utils'; -// Hooks Imports -import { useSession } from '@hooks'; // Theme Imports import theme from '../../theme'; @@ -68,16 +66,14 @@ const CustomToolbar = () => ( * @returns {React.JSX.Element} The DocumentsDesktop component */ const DocumentsDesktop = ({ documents, handlers }) => { - const { session } = useSession(); const location = useLocation(); - const profileWebId = decodeURIComponent(location.pathname.split('/')[2]); const columnTitlesArray = [ - { field: 'Name', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, - { field: 'Type', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, - { field: 'Description', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, - { field: 'Upload Date', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, - { field: 'Expiration Date', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, + { field: 'Name', minWidth: 120, flex: 3, headerAlign: 'center', align: 'center' }, + { field: 'Type', minWidth: 120, flex: 2, headerAlign: 'center', align: 'center' }, + { field: 'Description', minWidth: 120, flex: 3, headerAlign: 'center', align: 'center' }, + { field: 'Upload Date', minWidth: 120, flex: 2, headerAlign: 'center', align: 'center' }, + { field: 'Expiration Date', minWidth: 120, flex: 2, headerAlign: 'center', align: 'center' }, { field: 'Preview', minWidth: 100, @@ -116,7 +112,7 @@ const DocumentsDesktop = ({ documents, handlers }) => { onClick={() => handlers.onShare('document', name, type)} label="Share" data-testid={`share-button-${id}`} - disabled={session.info.webId !== profileWebId} + disabled={location.pathname !== '/documents'} /> ); } @@ -138,7 +134,7 @@ const DocumentsDesktop = ({ documents, handlers }) => { onClick={() => handlers.onDelete(document)} label="Delete" data-testid={`delete-button-${document.id}`} - disabled={session.info.webId !== profileWebId} + disabled={location.pathname !== '/documents'} /> ); } diff --git a/src/components/Messages/MessagePreview.jsx b/src/components/Messages/MessagePreview.jsx index ef4b5455a..6187ebf33 100644 --- a/src/components/Messages/MessagePreview.jsx +++ b/src/components/Messages/MessagePreview.jsx @@ -74,10 +74,12 @@ const MessagePreview = ({ message, folderType }) => { return 2; }; + const isInbox = folderType === 'Inbox'; + const messageInfo = [ { - title: 'Sender: ', - text: message?.sender, + title: isInbox ? 'Sender: ' : 'Recipient: ', + text: isInbox ? message?.sender : message?.recipient, xs_value: isSmallScreen ? 12 : renderMediumGridLeft() }, { diff --git a/src/components/Modals/NewMessageModal.jsx b/src/components/Modals/NewMessageModal.jsx index efd1df100..694c7084d 100644 --- a/src/components/Modals/NewMessageModal.jsx +++ b/src/components/Modals/NewMessageModal.jsx @@ -1,5 +1,6 @@ // React Imports import React, { useContext, useEffect, useState } from 'react'; +import { useLocation } from 'react-router-dom'; // Inrupt Library Imports import { useMessageList, useNotification, useSession, useContactsList } from '@hooks'; // Material UI Imports @@ -46,6 +47,7 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' const { podUrl } = useContext(SignedInUserContext); const { addNotification } = useNotification(); const [originalMessage, setOriginalMessage] = useState(oldMessage.message); + const location = useLocation(); const [message, setMessage] = useState({ recipientPodUrl: @@ -111,7 +113,7 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' await sendMessageTTL(session, messageWithTrimmedInputs, podUrl); setMessage({ - recipientPodUrl: '', + recipientPodUrl: location.pathname === '/contacts' ? toField : '', title: '', message: '' }); diff --git a/src/pages/Contacts.jsx b/src/pages/Contacts.jsx index 42869a195..c934bfed8 100644 --- a/src/pages/Contacts.jsx +++ b/src/pages/Contacts.jsx @@ -158,7 +158,6 @@ const Contacts = () => { }} IconComponent={KeyboardArrowDownIcon} > - {' '} Sort by: diff --git a/test/components/Messages/MessagePreview.test.jsx b/test/components/Messages/MessagePreview.test.jsx index 69bfd7deb..68b1943e6 100644 --- a/test/components/Messages/MessagePreview.test.jsx +++ b/test/components/Messages/MessagePreview.test.jsx @@ -1,19 +1,34 @@ import React from 'react'; import { render, cleanup } from '@testing-library/react'; -import { describe, expect, it, afterEach } from 'vitest'; +import { describe, expect, it, afterEach, vi } from 'vitest'; import { MessagePreview } from '@components/Messages'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import createMatchMedia from '../../helpers/createMatchMedia'; const queryClient = new QueryClient(); -const mockMessageInfo = { sender: 'test', title: 'test title', uploadDate: new Date('1-1-2000') }; -const MockMessagePreview = () => ( +const mockMessageInfo = { + sender: 'test', + recipient: 'testrecipient', + title: 'test title', + uploadDate: new Date('1-1-2000') +}; +const MockMessagePreview = ({ folderType = 'Inbox' }) => ( - + ); +vi.mock('react-router-dom', async () => { + const actual = vi.importActual('react-router-dom'); + return { + ...actual, + useLocation: vi.fn().mockReturnValue({ + pathname: '/contacts' + }) + }; +}); + describe('Grid sizes', () => { afterEach(() => { cleanup(); @@ -54,3 +69,16 @@ describe('Grid sizes', () => { expect(dateCell.classList.contains('MuiGrid-grid-xs-12')).toBe(true); }); }); + +describe('Outbox shows Recipient instead of Sender', () => { + afterEach(() => { + cleanup(); + }); + + it('renders Recipient text', () => { + const { getByText } = render(); + const recipientCell = getByText('Recipient:').parentElement; + + expect(recipientCell.classList.contains('MuiGrid-grid-xs-5')).toBe(true); + }); +}); diff --git a/test/components/Modals/NewMessageModal.test.jsx b/test/components/Modals/NewMessageModal.test.jsx index 7210aaffd..91d027ecb 100644 --- a/test/components/Modals/NewMessageModal.test.jsx +++ b/test/components/Modals/NewMessageModal.test.jsx @@ -16,6 +16,16 @@ const MockNewMessageModal = () => ( ); +vi.mock('react-router-dom', async () => { + const actual = vi.importActual('react-router-dom'); + return { + ...actual, + useLocation: vi.fn().mockReturnValue({ + pathname: '/contacts' + }) + }; +}); + it('renders button group flex-direction as row default', () => { const { getByRole } = render(); const cancelButton = getByRole('button', { name: 'Cancel' });