1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

frontend: add tests & stories for many components

Also more compound adoption
Also prettier upgrade
This commit is contained in:
Quentin Gliech
2023-08-04 16:46:51 +02:00
parent c8ba2a1fa3
commit f001463585
52 changed files with 1246 additions and 193 deletions

View File

@@ -16,7 +16,8 @@
"@urql/exchange-refocus": "^1.0.2",
"@urql/exchange-request-policy": "^1.0.2",
"@vector-im/compound-design-tokens": "^0.0.3",
"@vector-im/compound-web": "^0.2.3",
"@vector-im/compound-web": "^0.2.4",
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
"graphql": "^16.7.1",
"jotai": "^2.2.3",
@@ -36,13 +37,14 @@
"@storybook/addon-controls": "^7.2.1",
"@storybook/addon-docs": "^7.2.1",
"@storybook/addon-essentials": "^7.2.1",
"@storybook/addon-measure": "^7.2.0",
"@storybook/addon-outline": "^7.2.0",
"@storybook/addon-toolbars": "^7.2.0",
"@storybook/addon-viewport": "^7.2.0",
"@storybook/addon-measure": "^7.2.1",
"@storybook/addon-outline": "^7.2.1",
"@storybook/addon-toolbars": "^7.2.1",
"@storybook/addon-viewport": "^7.2.1",
"@storybook/react": "^7.2.1",
"@storybook/react-vite": "^7.2.1",
"@types/node": "^20.4.6",
"@testing-library/react": "^14.0.0",
"@types/node": "^20.4.7",
"@types/react": "^18.2.18",
"@types/react-dom": "^18.2.7",
"@types/react-test-renderer": "^18.0.0",
@@ -50,14 +52,15 @@
"@vitest/coverage-v8": "^0.34.1",
"autoprefixer": "^10.4.14",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.9.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-matrix-org": "^1.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-matrix-org": "^1.2.1",
"eslint-plugin-prettier": "^5.0.0",
"happy-dom": "^10.7.0",
"postcss": "^8.4.27",
"prettier": "2.8.0",
"prettier": "3.0.1",
"react-test-renderer": "^18.2.0",
"rimraf": "^5.0.1",
"storybook": "^7.2.1",
@@ -6977,6 +6980,21 @@
"node": ">=10"
}
},
"node_modules/@storybook/cli/node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/@storybook/cli/node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -7049,6 +7067,21 @@
"url": "https://opencollective.com/storybook"
}
},
"node_modules/@storybook/codemod/node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/@storybook/components": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.2.1.tgz",
@@ -7455,6 +7488,21 @@
"url": "https://opencollective.com/storybook"
}
},
"node_modules/@storybook/csf-tools/node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/@storybook/docs-mdx": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-0.1.0.tgz",
@@ -8418,6 +8466,21 @@
"url": "https://github.com/sponsors/gregberge"
}
},
"node_modules/@svgr/plugin-prettier/node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/@svgr/plugin-svgo": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz",
@@ -8614,6 +8677,136 @@
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@testing-library/dom": {
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz",
"integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "5.1.3",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@testing-library/dom/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/aria-query": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
"integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
"dev": true,
"dependencies": {
"deep-equal": "^2.0.5"
}
},
"node_modules/@testing-library/dom/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@testing-library/dom/node_modules/pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"node_modules/@testing-library/dom/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@testing-library/react": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz",
"integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@testing-library/dom": "^9.0.0",
"@types/react-dom": "^18.0.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -8622,6 +8815,12 @@
"node": ">=10.13.0"
}
},
"node_modules/@types/aria-query": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz",
"integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==",
"dev": true
},
"node_modules/@types/babel__core": {
"version": "7.20.1",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
@@ -8880,9 +9079,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "20.4.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.6.tgz",
"integrity": "sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA==",
"version": "20.4.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz",
"integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==",
"dev": true
},
"node_modules/@types/node-fetch": {
@@ -9409,13 +9608,14 @@
}
},
"node_modules/@vector-im/compound-web": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-0.2.3.tgz",
"integrity": "sha512-7FI6Q1LN8dXur2sarP7UeMtAKcejuFw6AppM9Lu9fFjwLlbuIX2ZEprw1qa+EzgzUTysTU1TTdo7fxNqQwAQcA==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-0.2.4.tgz",
"integrity": "sha512-CRBZAYVQWbF/C+921KQ+DiimEHdd+UcOygHCU78qkeglOmZ0hZdKddGtOuIeZztYps2xSZAhG1RDVWvwmUHAnA==",
"dependencies": {
"@radix-ui/react-form": "^0.0.3",
"classnames": "^2.3.2",
"lodash": "^4.17.21"
"graphemer": "^1.4.0",
"rimraf": "^3.0.1"
},
"peerDependencies": {
"@fontsource/inter": "^5",
@@ -9434,6 +9634,20 @@
}
}
},
"node_modules/@vector-im/compound-web/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@vitejs/plugin-react": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz",
@@ -10403,8 +10617,7 @@
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/base16": {
"version": "1.0.0",
@@ -10547,7 +10760,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -11344,8 +11556,7 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/concat-stream": {
"version": "1.6.2",
@@ -11571,6 +11782,12 @@
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css.escape": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
"dev": true
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -11675,6 +11892,41 @@
"node": ">=6"
}
},
"node_modules/deep-equal": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz",
"integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==",
"dev": true,
"dependencies": {
"array-buffer-byte-length": "^1.0.0",
"call-bind": "^1.0.2",
"es-get-iterator": "^1.1.3",
"get-intrinsic": "^1.2.1",
"is-arguments": "^1.1.1",
"is-array-buffer": "^3.0.2",
"is-date-object": "^1.0.5",
"is-regex": "^1.1.4",
"is-shared-array-buffer": "^1.0.2",
"isarray": "^2.0.5",
"object-is": "^1.1.5",
"object-keys": "^1.1.1",
"object.assign": "^4.1.4",
"regexp.prototype.flags": "^1.5.0",
"side-channel": "^1.0.4",
"which-boxed-primitive": "^1.0.2",
"which-collection": "^1.0.1",
"which-typed-array": "^1.1.9"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/deep-equal/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"dev": true
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -12045,6 +12297,12 @@
"node": ">=6.0.0"
}
},
"node_modules/dom-accessibility-api": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true
},
"node_modules/dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
@@ -12330,6 +12588,32 @@
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
"dev": true
},
"node_modules/es-get-iterator": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
"integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.3",
"has-symbols": "^1.0.3",
"is-arguments": "^1.1.1",
"is-map": "^2.0.2",
"is-set": "^2.0.2",
"is-string": "^1.0.7",
"isarray": "^2.0.5",
"stop-iteration-iterator": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-get-iterator/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"dev": true
},
"node_modules/es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
@@ -12563,9 +12847,9 @@
}
},
"node_modules/eslint-config-prettier": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.9.0.tgz",
"integrity": "sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
"integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
"dev": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
@@ -12867,9 +13151,9 @@
}
},
"node_modules/eslint-plugin-matrix-org": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-1.2.0.tgz",
"integrity": "sha512-Wp5CeLnyEwGBn8ZfVbSuO2y0Fs51IWonPJ1QRQTntaRxOkEQnnky3gOPwpfGJ8JB0CxYr1zXfeHh8LcYHW4wcg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-1.2.1.tgz",
"integrity": "sha512-A3cDjhG7RHwfCS8o3bOip8hSCsxtmgk2ahvqE5v/Ic2kPEZxixY6w8zLj7hFGsrRmPSEpLWqkVLt8uvQBapiQA==",
"dev": true,
"peerDependencies": {
"@babel/core": "*",
@@ -12887,26 +13171,34 @@
"eslint-plugin-react": "*",
"eslint-plugin-react-hooks": "*",
"eslint-plugin-unicorn": "*",
"prettier": "2.8.0",
"prettier": "*",
"typescript": "*"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
"integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz",
"integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==",
"dev": true,
"dependencies": {
"prettier-linter-helpers": "^1.0.0"
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.8.5"
},
"engines": {
"node": ">=12.0.0"
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/prettier"
},
"peerDependencies": {
"eslint": ">=7.28.0",
"prettier": ">=2.0.0"
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
@@ -14169,8 +14461,7 @@
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.2",
@@ -14408,7 +14699,6 @@
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -14532,8 +14822,7 @@
"node_modules/graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
},
"node_modules/graphql": {
"version": "16.7.1",
@@ -14688,6 +14977,53 @@
"node": ">=0.10.0"
}
},
"node_modules/happy-dom": {
"version": "10.7.0",
"resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-10.7.0.tgz",
"integrity": "sha512-dJFPbA7KW4kkH3MFJBPTX73ywOfcrJcu6CAUw0CnCH0aEDcnPNG8QVmOAxsJSvTZFzLCnmSx/jMzAp00hdm0gw==",
"dev": true,
"dependencies": {
"css.escape": "^1.5.1",
"entities": "^4.5.0",
"iconv-lite": "^0.6.3",
"webidl-conversions": "^7.0.0",
"whatwg-encoding": "^2.0.0",
"whatwg-mimetype": "^3.0.0"
}
},
"node_modules/happy-dom/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/happy-dom/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/happy-dom/node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -14967,7 +15303,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -14976,8 +15311,7 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/inquirer": {
"version": "8.2.5",
@@ -15371,6 +15705,15 @@
"tslib": "^2.0.3"
}
},
"node_modules/is-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
"integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-nan": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
@@ -15478,6 +15821,15 @@
"node": ">=0.10.0"
}
},
"node_modules/is-set": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
"integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-shared-array-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
@@ -15589,6 +15941,15 @@
"tslib": "^2.0.3"
}
},
"node_modules/is-weakmap": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
"integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakref": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -15601,6 +15962,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakset": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
"integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -16508,7 +16882,8 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash.curry": {
"version": "4.1.1",
@@ -16718,6 +17093,15 @@
"yallist": "^3.0.2"
}
},
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"bin": {
"lz-string": "bin/bin.js"
}
},
"node_modules/magic-string": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
@@ -16942,7 +17326,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -17461,7 +17844,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
@@ -17792,7 +18174,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -18133,15 +18514,15 @@
}
},
"node_modules/prettier": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz",
"integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
@@ -19919,6 +20300,18 @@
"integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==",
"dev": true
},
"node_modules/stop-iteration-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
"integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
"dev": true,
"dependencies": {
"internal-slot": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/store2": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz",
@@ -21779,6 +22172,39 @@
"integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
"dev": true
},
"node_modules/whatwg-encoding": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
"dev": true,
"dependencies": {
"iconv-lite": "0.6.3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/whatwg-mimetype": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -21820,6 +22246,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-collection": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
"integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
"dev": true,
"dependencies": {
"is-map": "^2.0.1",
"is-set": "^2.0.1",
"is-weakmap": "^2.0.1",
"is-weakset": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
@@ -21950,8 +22391,7 @@
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/write-file-atomic": {
"version": "4.0.2",

View File

@@ -23,7 +23,8 @@
"@urql/exchange-refocus": "^1.0.2",
"@urql/exchange-request-policy": "^1.0.2",
"@vector-im/compound-design-tokens": "^0.0.3",
"@vector-im/compound-web": "^0.2.3",
"@vector-im/compound-web": "^0.2.4",
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
"graphql": "^16.7.1",
"jotai": "^2.2.3",
@@ -43,13 +44,14 @@
"@storybook/addon-controls": "^7.2.1",
"@storybook/addon-docs": "^7.2.1",
"@storybook/addon-essentials": "^7.2.1",
"@storybook/addon-measure": "^7.2.0",
"@storybook/addon-outline": "^7.2.0",
"@storybook/addon-toolbars": "^7.2.0",
"@storybook/addon-viewport": "^7.2.0",
"@storybook/addon-measure": "^7.2.1",
"@storybook/addon-outline": "^7.2.1",
"@storybook/addon-toolbars": "^7.2.1",
"@storybook/addon-viewport": "^7.2.1",
"@storybook/react": "^7.2.1",
"@storybook/react-vite": "^7.2.1",
"@types/node": "^20.4.6",
"@testing-library/react": "^14.0.0",
"@types/node": "^20.4.7",
"@types/react": "^18.2.18",
"@types/react-dom": "^18.2.7",
"@types/react-test-renderer": "^18.0.0",
@@ -57,14 +59,15 @@
"@vitest/coverage-v8": "^0.34.1",
"autoprefixer": "^10.4.14",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.9.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-matrix-org": "^1.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-matrix-org": "^1.2.1",
"eslint-plugin-prettier": "^5.0.0",
"happy-dom": "^10.7.0",
"postcss": "^8.4.27",
"prettier": "2.8.0",
"prettier": "3.0.1",
"react-test-renderer": "^18.2.0",
"rimraf": "^5.0.1",
"storybook": "^7.2.1",

View File

@@ -77,31 +77,35 @@ const routeToPath = (route: Route): string =>
.map((part) => encodeURIComponent(part))
.join("/");
export const appConfigAtom = atom(window.APP_CONFIG);
const pathToRoute = (path: string): Route => {
const segments = path.split("/").map(decodeURIComponent);
return segmentsToRoute(segments);
};
const locationToRoute = (location: Location): Route => {
if (
!location.pathname ||
!location.pathname.startsWith(window.APP_CONFIG.root)
) {
throw new Error("Invalid location");
const locationToRoute = (root: string, location: Location): Route => {
if (!location.pathname || !location.pathname.startsWith(root)) {
throw new Error(`Invalid location ${location.pathname}`);
}
const path = location.pathname.slice(window.APP_CONFIG.root.length);
const path = location.pathname.slice(root.length);
return pathToRoute(path);
};
const locationAtom = atomWithLocation();
export const locationAtom = atomWithLocation();
export const routeAtom = atom(
(get) => locationToRoute(get(locationAtom)),
(_get, set, value: Route) => {
(get) => {
const location = get(locationAtom);
const config = get(appConfigAtom);
return locationToRoute(config.root, location);
},
(get, set, value: Route) => {
const appConfig = get(appConfigAtom);
set(locationAtom, {
pathname: window.APP_CONFIG.root + routeToPath(value),
pathname: appConfig.root + routeToPath(value),
});
}
},
);
const Home = lazy(() => import("./pages/Home"));

View File

@@ -37,7 +37,7 @@ export type GqlAtom<T> = WritableAtom<
*/
export const mapQueryAtom = <Data, Variables extends AnyVariables, NewData>(
queryAtom: AtomWithQuery<Data, Variables>,
mapper: (data: Data) => NewData
mapper: (data: Data) => NewData,
): GqlAtom<NewData> => {
return atom(
async (get): Promise<GqlResult<NewData>> => {
@@ -55,7 +55,7 @@ export const mapQueryAtom = <Data, Variables extends AnyVariables, NewData>(
(_get, set, context) => {
set(queryAtom, context);
}
},
);
};
@@ -90,7 +90,7 @@ export const currentUserIdAtom: GqlAtom<string | null> = mapQueryAtom(
return data.viewer.id;
}
return null;
}
},
);
const CURRENT_VIEWER_SESSION_QUERY = graphql(/* GraphQL */ `
@@ -119,5 +119,5 @@ export const currentBrowserSessionIdAtom: GqlAtom<string | null> = mapQueryAtom(
return data.viewerSession.id;
}
return null;
}
},
);

View File

@@ -1,4 +1,4 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,18 +13,13 @@
// limitations under the License.
import type { Meta, StoryObj } from "@storybook/react";
import { H1, H5, Body } from "@vector-im/compound-web";
import Block from "./Block";
import { Title, Subtitle, Body } from "./Typography";
const meta = {
title: "UI/Block",
component: Block,
subcomponents: {
Title,
Subtitle,
Body,
} as Record<string, React.ComponentType<unknown>>,
tags: ["autodocs"],
} satisfies Meta<typeof Block>;
@@ -34,8 +29,8 @@ type Story = StoryObj<typeof Block>;
export const Basic: Story = {
render: (args) => (
<Block {...args}>
<Title>Title</Title>
<Subtitle>Subtitle</Subtitle>
<H1>Title</H1>
<H5>Subtitle</H5>
<Body justified>
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit
enim labore culpa sint ad nisi Lorem pariatur mollit ex esse

View File

@@ -0,0 +1,45 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { create } from "react-test-renderer";
import { describe, expect, it } from "vitest";
import Block from "./Block";
describe("Block", () => {
it("render <Block />", () => {
const component = create(<Block />);
expect(component.toJSON()).toMatchSnapshot();
});
it("render <Block /> with children", () => {
const component = create(
<Block>
<h1>Title</h1>
<p>Body</p>
</Block>,
);
expect(component.toJSON()).toMatchSnapshot();
});
it("passes down the className prop", () => {
const component = create(<Block className="foo" />);
expect(component.toJSON()).toMatchSnapshot();
});
it("renders with highlight", () => {
const component = create(<Block highlight />);
expect(component.toJSON()).toMatchSnapshot();
});
});

View File

@@ -12,18 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import cx from "classnames";
import styles from "./Block.module.css";
type Props = {
type Props = React.PropsWithChildren<{
className?: string;
highlight?: boolean;
};
}>;
const Block: React.FC<React.PropsWithChildren<Props>> = ({
children,
highlight,
}) => {
const Block: React.FC<Props> = ({ children, className, highlight }) => {
return (
<div className={styles.block} data-active={highlight}>
<div className={cx(styles.block, className)} data-active={highlight}>
{children}
</div>
);

View File

@@ -0,0 +1,33 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Block > passes down the className prop 1`] = `
<div
className="_block_17898c foo"
/>
`;
exports[`Block > render <Block /> 1`] = `
<div
className="_block_17898c"
/>
`;
exports[`Block > render <Block /> with children 1`] = `
<div
className="_block_17898c"
>
<h1>
Title
</h1>
<p>
Body
</p>
</div>
`;
exports[`Block > renders with highlight 1`] = `
<div
className="_block_17898c"
data-active={true}
/>
`;

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default } from "./Block";

View File

@@ -14,8 +14,8 @@
*/
.block-list {
display: grid;
grid-template-columns: 1fr;
display: flex;
flex-direction: column;
gap: var(--cpd-space-4x);
align-content: flex-start;
}

View File

@@ -0,0 +1,44 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Meta, StoryObj } from "@storybook/react";
import { H2, Body } from "@vector-im/compound-web";
import Block from "../Block";
import BlockList from "./BlockList";
const meta = {
title: "UI/Block List",
component: BlockList,
} satisfies Meta<typeof BlockList>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Basic: Story = {
render: (args) => (
<BlockList {...args}>
<Block>
<H2>Block 1</H2>
<Body>Body 1</Body>
</Block>
<Block>
<H2>Block 2</H2>
<Body>Body 2</Body>
</Block>
</BlockList>
),
};

View File

@@ -0,0 +1,42 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { create } from "react-test-renderer";
import { describe, expect, it } from "vitest";
import Block from "../Block";
import BlockList from "./BlockList";
describe("BlockList", () => {
it("render an empty <BlockList />", () => {
const component = create(<BlockList />);
expect(component.toJSON()).toMatchSnapshot();
});
it("render <BlockList /> with children", () => {
const component = create(
<BlockList>
<Block>Block 1</Block>
<Block>Block 2</Block>
</BlockList>,
);
expect(component.toJSON()).toMatchSnapshot();
});
it("passes down the className prop", () => {
const component = create(<BlockList className="foo" />);
expect(component.toJSON()).toMatchSnapshot();
});
});

View File

@@ -12,10 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import cx from "classnames";
import styles from "./BlockList.module.css";
const BlockList: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
return <div className={styles.blockList}>{children}</div>;
type Props = React.PropsWithChildren<{
className?: string;
}>;
const BlockList: React.FC<Props> = ({ className, children }) => {
return <div className={cx(styles.blockList, className)}>{children}</div>;
};
export default BlockList;

View File

@@ -0,0 +1,30 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`BlockList > passes down the className prop 1`] = `
<div
className="_blockList_f8cc7f foo"
/>
`;
exports[`BlockList > render <BlockList /> with children 1`] = `
<div
className="_blockList_f8cc7f"
>
<div
className="_block_17898c"
>
Block 1
</div>
<div
className="_block_17898c"
>
Block 2
</div>
</div>
`;
exports[`BlockList > render an empty <BlockList /> 1`] = `
<div
className="_blockList_f8cc7f"
/>
`;

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default } from "./BlockList";

View File

@@ -54,7 +54,7 @@ const endSessionFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const endSessionAtom = atom(
(get) => get(endSession),
(get, set) => set(endSession, { id })
(get, set) => set(endSession, { id }),
);
return endSessionAtom;

View File

@@ -81,7 +81,7 @@ const browserSessionListFamily = atomFamily((userId: string) => {
const browserSessionList = mapQueryAtom(
browserSessionListQuery,
(data) => data.user?.browserSessions || null
(data) => data.user?.browserSessions || null,
);
return browserSessionList;
@@ -98,7 +98,7 @@ const pageInfoFamily = atomFamily((userId: string) => {
const paginationFamily = atomFamily((userId: string) => {
const paginationAtom = atomWithPagination(
currentPaginationAtom,
pageInfoFamily(userId)
pageInfoFamily(userId),
);
return paginationAtom;

View File

@@ -62,7 +62,7 @@ const endCompatSessionFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const endCompatSessionAtom = atom(
(get) => get(endCompatSession),
(get, set) => set(endCompatSession, { id })
(get, set) => set(endCompatSession, { id }),
);
return endCompatSessionAtom;

View File

@@ -78,7 +78,7 @@ const compatSessionListFamily = atomFamily((userId: string) => {
const compatSessionList = mapQueryAtom(
compatSessionListQuery,
(data) => data.user?.compatSessions || null
(data) => data.user?.compatSessions || null,
);
return compatSessionList;
@@ -96,7 +96,7 @@ const pageInfoFamily = atomFamily((userId: string) => {
const paginationFamily = atomFamily((userId: string) => {
const paginationAtom = atomWithPagination(
currentPaginationAtom,
pageInfoFamily(userId)
pageInfoFamily(userId),
);
return paginationAtom;
});

View File

@@ -0,0 +1,21 @@
/* Copyright 2023 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.loading-screen {
display: flex;
min-height: 100vh;
justify-content: center;
align-items: center;
}

View File

@@ -19,6 +19,9 @@ import LoadingScreen from "./LoadingScreen";
const meta = {
title: "UI/Loading Screen",
component: LoadingScreen,
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
} satisfies Meta<typeof LoadingScreen>;

View File

@@ -13,12 +13,14 @@
// limitations under the License.
import { create } from "react-test-renderer";
import { expect, it } from "vitest";
import { describe, expect, it } from "vitest";
import LoadingScreen from "./LoadingScreen";
it("render <LoadingScreen />", () => {
describe("LoadingScreen", () => {
it("render <LoadingScreen />", () => {
const component = create(<LoadingScreen />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -12,10 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import LoadingSpinner from "./LoadingSpinner";
import LoadingSpinner from "../LoadingSpinner";
import styles from "./LoadingScreen.module.css";
const LoadingScreen: React.FC = () => (
<main className="min-h-screen flex justify-center items-center">
<main className={styles.loadingScreen}>
<LoadingSpinner />
</main>
);

View File

@@ -0,0 +1,28 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`LoadingScreen > render <LoadingScreen /> 1`] = `
<main
className="_loadingScreen_0642c6"
>
<div
role="status"
>
<svg
className="_loadingSpinnerInner_0c7436"
fill="none"
viewBox="0 0 100 101"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span
className="sr-only"
>
Loading...
</span>
</div>
</main>
`;

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default } from "./LoadingScreen";

View File

@@ -0,0 +1,28 @@
/* Copyright 2023 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.loading-spinner-inner {
height: var(--cpd-space-16x);
width: var(--cpd-space-16x);
display: inline;
animation: spin 1s linear infinite;
fill: var(--cpd-color-icon-primary);
}

View File

@@ -12,10 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import styles from "./LoadingSpinner.module.css";
const LoadingSpinner: React.FC = () => (
<div role="status">
<svg
className="inline mr-2 w-16 h-16 animate-spin fill-accent"
className={styles.loadingSpinnerInner}
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default } from "./LoadingSpinner";

View File

@@ -0,0 +1,52 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import type { Meta, StoryObj } from "@storybook/react";
import { Provider } from "jotai";
import { useHydrateAtoms } from "jotai/utils";
import { appConfigAtom, locationAtom } from "../../Router";
import NavItem, { ExternalLink } from "../NavItem";
import NavBar from "./NavBar";
const meta = {
title: "UI/Nav Bar",
component: NavBar,
tags: ["autodocs"],
render: (props): React.ReactElement => (
<Provider>
<WithHomePage>
<NavBar {...props}>
<NavItem route={{ type: "home" }}>Home</NavItem>
<NavItem route={{ type: "account" }}>Account</NavItem>
<ExternalLink href="https://example.com">External</ExternalLink>
</NavBar>
</WithHomePage>
</Provider>
),
} satisfies Meta<typeof NavBar>;
const WithHomePage: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
useHydrateAtoms([
[appConfigAtom, { root: "/" }],
[locationAtom, { pathname: "/" }],
]);
return <>{children}</>;
};
export default meta;
type Story = StoryObj<typeof NavBar>;
export const Basic: Story = {};

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default } from "./NavBar";

View File

@@ -0,0 +1,59 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import type { Meta, StoryObj } from "@storybook/react";
import { Provider } from "jotai";
import { useHydrateAtoms } from "jotai/utils";
import { appConfigAtom, locationAtom } from "../../Router";
import NavItem from "./NavItem";
const meta = {
title: "UI/Nav Item",
component: NavItem,
tags: ["autodocs"],
render: (props): React.ReactElement => (
<Provider>
<WithHomePage>
<NavItem {...props} />
</WithHomePage>
</Provider>
),
} satisfies Meta<typeof NavItem>;
const WithHomePage: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
useHydrateAtoms([
[appConfigAtom, { root: "/" }],
[locationAtom, { pathname: "/" }],
]);
return <>{children}</>;
};
export default meta;
type Story = StoryObj<typeof NavItem>;
export const Active: Story = {
args: {
route: { type: "home" },
children: "Home",
},
};
export const Inactive: Story = {
args: {
route: { type: "account" },
children: "Account",
},
};

View File

@@ -0,0 +1,86 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// @vitest-environment happy-dom
import { Provider } from "jotai";
import { useHydrateAtoms } from "jotai/utils";
import { create } from "react-test-renderer";
import { beforeEach, describe, expect, it } from "vitest";
import { appConfigAtom, locationAtom } from "../../Router";
import NavItem from "./NavItem";
beforeEach(async () => {
// For some reason, the locationAtom gets updated with `about:black` on render,
// so we need to set a "real" location and wait for the next tick
window.location.assign("https://example.com/");
// Wait the next tick for the location to update
await new Promise((resolve) => setTimeout(resolve, 0));
});
const HydrateLocation: React.FC<React.PropsWithChildren<{ path: string }>> = ({
children,
path,
}) => {
useHydrateAtoms([
[appConfigAtom, { root: "/" }],
[locationAtom, { pathname: path }],
]);
return <>{children}</>;
};
const WithLocation: React.FC<React.PropsWithChildren<{ path: string }>> = ({
children,
path,
}) => {
return (
<Provider>
<HydrateLocation path={path}>{children}</HydrateLocation>
</Provider>
);
};
describe("NavItem", () => {
it("render an active <NavItem />", () => {
const component = create(
<WithLocation path="/">
<NavItem route={{ type: "home" }}>Active</NavItem>
</WithLocation>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
it("render an inactive <NavItem />", () => {
const component = create(
<WithLocation path="/account">
<NavItem route={{ type: "home" }}>Inactive</NavItem>
</WithLocation>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
it("renders a different route", () => {
const component = create(
<WithLocation path="/">
<NavItem route={{ type: "account" }}>Account</NavItem>
</WithLocation>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -15,7 +15,7 @@
import { Link as CpdLink } from "@vector-im/compound-web";
import { useAtomValue } from "jotai";
import { Link, Route, routeAtom } from "../Router";
import { Link, Route, routeAtom } from "../../Router";
import styles from "./NavItem.module.css";

View File

@@ -0,0 +1,38 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`NavItem > render an active <NavItem /> 1`] = `
<li>
<a
aria-current="page"
className="_navItem_8603fc"
href=""
onClick={[Function]}
>
Active
</a>
</li>
`;
exports[`NavItem > render an inactive <NavItem /> 1`] = `
<li>
<a
className="_navItem_8603fc"
href=""
onClick={[Function]}
>
Inactive
</a>
</li>
`;
exports[`NavItem > renders a different route 1`] = `
<li>
<a
className="_navItem_8603fc"
href="account"
onClick={[Function]}
>
Account
</a>
</li>
`;

View File

@@ -0,0 +1,15 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export { default, ExternalLink } from "./NavItem";

View File

@@ -58,7 +58,7 @@ const endSessionFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const endSessionAtom = atom(
(get) => get(endSession),
(get, set) => set(endSession, { id })
(get, set) => set(endSession, { id }),
);
return endSessionAtom;

View File

@@ -79,7 +79,7 @@ const oauth2SessionListFamily = atomFamily((userId: string) => {
const oauth2SessionList = mapQueryAtom(
oauth2SessionListQuery,
(data) => data.user?.oauth2Sessions || null
(data) => data.user?.oauth2Sessions || null,
);
return oauth2SessionList;
@@ -97,7 +97,7 @@ const pageInfoFamily = atomFamily((userId: string) => {
const paginationFamily = atomFamily((userId: string) => {
const paginationAtom = atomWithPagination(
currentPaginationAtom,
pageInfoFamily(userId)
pageInfoFamily(userId),
);
return paginationAtom;
});

View File

@@ -116,7 +116,7 @@ const verifyEmailFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const verifyEmailAtom = atom(
(get) => get(verifyEmail),
(get, set, code: string) => set(verifyEmail, { id, code })
(get, set, code: string) => set(verifyEmail, { id, code }),
);
return verifyEmailAtom;
@@ -124,13 +124,13 @@ const verifyEmailFamily = atomFamily((id: string) => {
const resendVerificationEmailFamily = atomFamily((id: string) => {
const resendVerificationEmail = atomWithMutation(
RESEND_VERIFICATION_EMAIL_MUTATION
RESEND_VERIFICATION_EMAIL_MUTATION,
);
// A proxy atom which pre-sets the id variable in the mutation
const resendVerificationEmailAtom = atom(
(get) => get(resendVerificationEmail),
(get, set) => set(resendVerificationEmail, { id })
(get, set) => set(resendVerificationEmail, { id }),
);
return resendVerificationEmailAtom;
@@ -142,7 +142,7 @@ const removeEmailFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const removeEmailAtom = atom(
(get) => get(removeEmail),
(get, set) => set(removeEmail, { id })
(get, set) => set(removeEmail, { id }),
);
return removeEmailAtom;
@@ -154,7 +154,7 @@ const setPrimaryEmailFamily = atomFamily((id: string) => {
// A proxy atom which pre-sets the id variable in the mutation
const setPrimaryEmailAtom = atom(
(get) => get(setPrimaryEmail),
(get, set) => set(setPrimaryEmail, { id })
(get, set) => set(setPrimaryEmail, { id }),
);
return setPrimaryEmailAtom;
@@ -171,7 +171,7 @@ const UserEmail: React.FC<{
const data = useFragment(FRAGMENT, email);
const [verifyEmailResult, verifyEmail] = useAtom(verifyEmailFamily(data.id));
const [resendVerificationEmailResult, resendVerificationEmail] = useAtom(
resendVerificationEmailFamily(data.id)
resendVerificationEmailFamily(data.id),
);
const setPrimaryEmail = useSetAtom(setPrimaryEmailFamily(data.id));
const removeEmail = useSetAtom(removeEmailFamily(data.id));

View File

@@ -90,7 +90,7 @@ const primaryEmailIdFamily = atomFamily((userId: string) => {
},
(get, set) => {
set(primaryEmailResultFamily(userId));
}
},
);
return primaryEmailIdAtom;
@@ -118,7 +118,7 @@ const pageInfoFamily = atomFamily((userId: string) => {
const paginationFamily = atomFamily((userId: string) => {
const paginationAtom = atomWithPagination(
currentPaginationAtom,
pageInfoFamily(userId)
pageInfoFamily(userId),
);
return paginationAtom;
});
@@ -131,7 +131,7 @@ const UserEmailList: React.FC<{
const setPagination = useSetAtom(currentPaginationAtom);
const [prevPage, nextPage] = useAtomValue(paginationFamily(userId));
const [primaryEmailId, refreshPrimaryEmailId] = useAtom(
primaryEmailIdFamily(userId)
primaryEmailIdFamily(userId),
);
// XXX: we may not want to directly use that atom here, but rather have a local state
const latestAddedEmail = useAtomValue(latestAddedEmailAtom);

View File

@@ -7,7 +7,7 @@ import { FragmentDefinitionNode } from "graphql";
import { Incremental } from "./graphql";
export type FragmentType<
TDocumentType extends DocumentTypeDecoration<any, any>
TDocumentType extends DocumentTypeDecoration<any, any>,
> = TDocumentType extends DocumentTypeDecoration<infer TType, any>
? [TType] extends [{ " $fragmentName"?: infer TKey }]
? TKey extends string
@@ -19,7 +19,7 @@ export type FragmentType<
// return non-nullable if `fragmentType` is non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>,
): TType;
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
@@ -27,12 +27,12 @@ export function useFragment<TType>(
fragmentType:
| FragmentType<DocumentTypeDecoration<TType, any>>
| null
| undefined
| undefined,
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>,
): ReadonlyArray<TType>;
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
@@ -40,7 +40,7 @@ export function useFragment<TType>(
fragmentType:
| ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
| null
| undefined
| undefined,
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
@@ -48,14 +48,14 @@ export function useFragment<TType>(
| FragmentType<DocumentTypeDecoration<TType, any>>
| ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
| null
| undefined
| undefined,
): TType | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}
export function makeFragmentData<
F extends DocumentTypeDecoration<any, any>,
FT extends ResultOf<F>
FT extends ResultOf<F>,
>(data: FT, _fragment: F): FragmentType<F> {
return data as FragmentType<F>;
}
@@ -65,7 +65,7 @@ export function isFragmentReady<TQuery, TFrag>(
data:
| FragmentType<TypedDocumentNode<Incremental<TFrag>, any>>
| null
| undefined
| undefined,
): data is FragmentType<typeof fragmentNode> {
const deferredFields = (
queryNode as {

View File

@@ -79,140 +79,140 @@ export function graphql(source: string): unknown;
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): typeof documents["\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
source: "\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n",
): (typeof documents)["\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): typeof documents["\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
source: "\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n",
): (typeof documents)["\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): typeof documents["\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
source: "\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n",
): (typeof documents)["\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"
): typeof documents["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"];
source: "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n",
): (typeof documents)["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n"
): typeof documents["\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n"];
source: "\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n",
): (typeof documents)["\n mutation EndBrowserSession($id: ID!) {\n endBrowserSession(input: { browserSessionId: $id }) {\n status\n browserSession {\n id\n ...BrowserSession_session\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): typeof documents["\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
source: "\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment CompatSession_sso_login on CompatSsoLogin {\n id\n redirectUri\n }\n"
): typeof documents["\n fragment CompatSession_sso_login on CompatSsoLogin {\n id\n redirectUri\n }\n"];
source: "\n fragment CompatSession_sso_login on CompatSsoLogin {\n id\n redirectUri\n }\n",
): (typeof documents)["\n fragment CompatSession_sso_login on CompatSsoLogin {\n id\n redirectUri\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n ...CompatSession_sso_login\n }\n }\n"
): typeof documents["\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n ...CompatSession_sso_login\n }\n }\n"];
source: "\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n ...CompatSession_sso_login\n }\n }\n",
): (typeof documents)["\n fragment CompatSession_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n ssoLogin {\n id\n ...CompatSession_sso_login\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n"
): typeof documents["\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n"];
source: "\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n",
): (typeof documents)["\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n finishedAt\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query CompatSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): typeof documents["\n query CompatSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
source: "\n query CompatSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query CompatSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n"
): typeof documents["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n"];
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n",
): (typeof documents)["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n"
): typeof documents["\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n"];
source: "\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n",
): (typeof documents)["\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): typeof documents["\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
source: "\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n"
): typeof documents["\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n"];
source: "\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n",
): (typeof documents)["\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): typeof documents["\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
source: "\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n",
): (typeof documents)["\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): typeof documents["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
source: "\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n",
): (typeof documents)["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n"
): typeof documents["\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n"];
source: "\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n",
): (typeof documents)["\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n"
): typeof documents["\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n"];
source: "\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n",
): (typeof documents)["\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): typeof documents["\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
source: "\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n",
): (typeof documents)["\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n"
): typeof documents["\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n"];
source: "\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n",
): (typeof documents)["\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n matrix {\n mxid\n displayName\n }\n }\n }\n"
): typeof documents["\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n matrix {\n mxid\n displayName\n }\n }\n }\n"];
source: "\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n matrix {\n mxid\n displayName\n }\n }\n }\n",
): (typeof documents)["\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n matrix {\n mxid\n displayName\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n }\n"
): typeof documents["\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n }\n"];
source: "\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n }\n",
): (typeof documents)["\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n"
): typeof documents["\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n"];
source: "\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n",
): (typeof documents)["\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};

View File

@@ -13,7 +13,7 @@ export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
};
export type MakeEmpty<
T extends { [key: string]: unknown },
K extends keyof T
K extends keyof T,
> = { [_ in K]?: never };
export type Incremental<T> =
| T

View File

@@ -52,7 +52,7 @@ const cache = cacheExchange({
result: { removeEmail?: RemoveEmailPayload },
args: MutationRemoveEmailArgs,
cache,
_info
_info,
) => {
// Invalidate the email entity
cache.invalidate({

View File

@@ -32,5 +32,5 @@ createRoot(document.getElementById("root") as HTMLElement).render(
</Suspense>
</HydrateAtoms>
</Provider>
</StrictMode>
</StrictMode>,
);

View File

@@ -47,7 +47,7 @@ const browserSessionFamily = atomFamily((id: string) => {
const browserSessionAtom = mapQueryAtom(
browserSessionQueryAtom,
(data) => data?.browserSession
(data) => data?.browserSession,
);
return browserSessionAtom;

View File

@@ -44,7 +44,7 @@ const oauth2ClientFamily = atomFamily((id: string) => {
const oauth2ClientAtom = mapQueryAtom(
oauth2ClientQueryAtom,
(data) => data?.oauth2Client
(data) => data?.oauth2Client,
);
return oauth2ClientAtom;

View File

@@ -34,14 +34,14 @@ export type Pagination = ForwardPagination | BackwardPagination;
// Check if the pagination is forward pagination.
export const isForwardPagination = (
pagination: Pagination
pagination: Pagination,
): pagination is ForwardPagination => {
return pagination.hasOwnProperty("first");
};
// Check if the pagination is backward pagination.
export const isBackwardPagination = (
pagination: Pagination
pagination: Pagination,
): pagination is BackwardPagination => {
return pagination.hasOwnProperty("last");
};
@@ -81,7 +81,7 @@ export const atomForCurrentPagination = (): WritableAtom<
} else {
set(dataAtom, action);
}
}
},
);
currentPaginationAtom.onMount = (setAtom): void => {
@@ -95,11 +95,11 @@ export const atomForCurrentPagination = (): WritableAtom<
// next pagination objects, given the current pagination and the page info.
export const atomWithPagination = (
currentPaginationAtom: Atom<Pagination>,
pageInfoAtom: Atom<Promise<PageInfo | null>>
pageInfoAtom: Atom<Promise<PageInfo | null>>,
): Atom<Promise<[BackwardPagination | null, ForwardPagination | null]>> => {
const paginationAtom = atom(
async (
get
get,
): Promise<[BackwardPagination | null, ForwardPagination | null]> => {
const currentPagination = get(currentPaginationAtom);
const pageInfo = await get(pageInfoAtom);
@@ -127,7 +127,7 @@ export const atomWithPagination = (
}
return [previousPagination, nextPagination];
}
},
);
return paginationAtom;