mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' of https://github.com/appwrite/appwrite-console-poc into feat-hover-list
This commit is contained in:
@@ -147,7 +147,7 @@ Adding a new dependency should have vital value on the product with minimum poss
|
||||
│ │ │ │ ├── _create.svelte // Component to Create collections
|
||||
│ │ │ │ └── index.svelte // Entrypoint for "/console/[PROJECT_ID]/database"
|
||||
│ │ │ ├── storage // Storage Service "/console/[PROJECT]/storage"
|
||||
│ │ │ └── authentication // Users Service "/console/[PROJECT]/authentication"
|
||||
│ │ │ └── auth // Users Service "/console/[PROJECT]/auth"
|
||||
│ │ └──...
|
||||
│ ├── login.svelte // Component for Login "/console/login"
|
||||
│ └── register.svelte // Component for Register "/console/register"
|
||||
|
||||
Generated
+38
-504
@@ -8,11 +8,12 @@
|
||||
"name": "@appwrite/console",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@aw-labs/appwrite-console": "^6.0.0",
|
||||
"@aw-labs/icons": "0.0.0-66",
|
||||
"@aw-labs/ui": "0.0.0-66",
|
||||
"@aw-labs/appwrite-console": "^10.0.0",
|
||||
"@aw-labs/icons": "0.0.0-72",
|
||||
"@aw-labs/ui": "0.0.0-72",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"echarts": "^5.4.0",
|
||||
"pretty-bytes": "^6.0.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"web-vitals": "^3.0.3"
|
||||
@@ -71,23 +72,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@aw-labs/appwrite-console": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/appwrite-console/-/appwrite-console-6.0.0.tgz",
|
||||
"integrity": "sha512-g4sCMGiIptDUyKhJSfiKsG/gzqMIt3MQCdqod6bNWMunbXUqN7DeA0BT4MuTeVGdQuoOKuSmgHeExatlu0Dh9Q==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/appwrite-console/-/appwrite-console-10.0.0.tgz",
|
||||
"integrity": "sha512-YyEQ5SIhkvI/Axt/EOkAqKcMTkfEpQt7W1q91lWKQ+Hm9woMzYUcf8KThBnMvEFbphWQRaJKLtfpr8EJjCjm4w==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "3.1.5",
|
||||
"isomorphic-form-data": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aw-labs/icons": {
|
||||
"version": "0.0.0-66",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-66.tgz",
|
||||
"integrity": "sha512-3r6pxixYZ6Bn9QTUbFk8XYwds+CHz1baRkOVsQ5HoFz6XgvzTWn3/+pvZZ56Ht2Ek//wr4wwI30pdCXaX4QIsA=="
|
||||
"version": "0.0.0-72",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-72.tgz",
|
||||
"integrity": "sha512-z3k9ex4oKdE/VUPeqc6lpo2HuhC39Dov2NEXv/1v6YBw2l20LavNA6m7NU/DFkq+m286un/dp6w7ORbgpZlIvw=="
|
||||
},
|
||||
"node_modules/@aw-labs/ui": {
|
||||
"version": "0.0.0-66",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-66.tgz",
|
||||
"integrity": "sha512-5qFISwKzOyZq7Ix5FG/BhVKEcIMXd2/Y8Ioba+ejTQ8B9hzj6FlwxUw7hLT49ZDhU+kxpjJQV51hRpbHGvmEag==",
|
||||
"version": "0.0.0-72",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-72.tgz",
|
||||
"integrity": "sha512-+NR8p3fRMVj/RMPmyVJPcdaRwYkWNw7jJ/wxT4zjYxa7QeeMJwILYfYIFYnnu0GG9SN9nOc2z+yISqL0p0HgfA==",
|
||||
"dependencies": {
|
||||
"@aw-labs/icons": "*",
|
||||
"normalize.css": "^8.0.1",
|
||||
@@ -721,38 +722,6 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz",
|
||||
"integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz",
|
||||
"integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
|
||||
@@ -2899,54 +2868,6 @@
|
||||
"esbuild-windows-arm64": "0.15.10"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz",
|
||||
"integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz",
|
||||
"integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz",
|
||||
@@ -2963,262 +2884,6 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz",
|
||||
"integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz",
|
||||
"integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz",
|
||||
"integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz",
|
||||
"integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz",
|
||||
"integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz",
|
||||
"integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz",
|
||||
"integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz",
|
||||
"integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz",
|
||||
"integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz",
|
||||
"integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
@@ -6278,6 +5943,17 @@
|
||||
"svelte": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-bytes": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.0.0.tgz",
|
||||
"integrity": "sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==",
|
||||
"engines": {
|
||||
"node": "^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
@@ -7782,23 +7458,23 @@
|
||||
}
|
||||
},
|
||||
"@aw-labs/appwrite-console": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/appwrite-console/-/appwrite-console-6.0.0.tgz",
|
||||
"integrity": "sha512-g4sCMGiIptDUyKhJSfiKsG/gzqMIt3MQCdqod6bNWMunbXUqN7DeA0BT4MuTeVGdQuoOKuSmgHeExatlu0Dh9Q==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/appwrite-console/-/appwrite-console-10.0.0.tgz",
|
||||
"integrity": "sha512-YyEQ5SIhkvI/Axt/EOkAqKcMTkfEpQt7W1q91lWKQ+Hm9woMzYUcf8KThBnMvEFbphWQRaJKLtfpr8EJjCjm4w==",
|
||||
"requires": {
|
||||
"cross-fetch": "3.1.5",
|
||||
"isomorphic-form-data": "2.0.0"
|
||||
}
|
||||
},
|
||||
"@aw-labs/icons": {
|
||||
"version": "0.0.0-66",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-66.tgz",
|
||||
"integrity": "sha512-3r6pxixYZ6Bn9QTUbFk8XYwds+CHz1baRkOVsQ5HoFz6XgvzTWn3/+pvZZ56Ht2Ek//wr4wwI30pdCXaX4QIsA=="
|
||||
"version": "0.0.0-72",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-72.tgz",
|
||||
"integrity": "sha512-z3k9ex4oKdE/VUPeqc6lpo2HuhC39Dov2NEXv/1v6YBw2l20LavNA6m7NU/DFkq+m286un/dp6w7ORbgpZlIvw=="
|
||||
},
|
||||
"@aw-labs/ui": {
|
||||
"version": "0.0.0-66",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-66.tgz",
|
||||
"integrity": "sha512-5qFISwKzOyZq7Ix5FG/BhVKEcIMXd2/Y8Ioba+ejTQ8B9hzj6FlwxUw7hLT49ZDhU+kxpjJQV51hRpbHGvmEag==",
|
||||
"version": "0.0.0-72",
|
||||
"resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-72.tgz",
|
||||
"integrity": "sha512-+NR8p3fRMVj/RMPmyVJPcdaRwYkWNw7jJ/wxT4zjYxa7QeeMJwILYfYIFYnnu0GG9SN9nOc2z+yISqL0p0HgfA==",
|
||||
"requires": {
|
||||
"@aw-labs/icons": "*",
|
||||
"normalize.css": "^8.0.1",
|
||||
@@ -8291,20 +7967,6 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"@esbuild/android-arm": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz",
|
||||
"integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-loong64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz",
|
||||
"integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
|
||||
@@ -9991,27 +9653,6 @@
|
||||
"esbuild-windows-arm64": "0.15.10"
|
||||
}
|
||||
},
|
||||
"esbuild-android-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz",
|
||||
"integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-android-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz",
|
||||
"integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz",
|
||||
@@ -10019,118 +9660,6 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-32": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz",
|
||||
"integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz",
|
||||
"integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz",
|
||||
"integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-mips64le": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz",
|
||||
"integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-ppc64le": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz",
|
||||
"integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-riscv64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz",
|
||||
"integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-s390x": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz",
|
||||
"integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-netbsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-openbsd-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz",
|
||||
"integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-sunos-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz",
|
||||
"integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-32": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz",
|
||||
"integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz",
|
||||
"integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-arm64": {
|
||||
"version": "0.15.10",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz",
|
||||
"integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
@@ -12460,6 +11989,11 @@
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"pretty-bytes": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.0.0.tgz",
|
||||
"integrity": "sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg=="
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
|
||||
+4
-3
@@ -19,11 +19,12 @@
|
||||
"e2e": "playwright test tests/e2e"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aw-labs/appwrite-console": "^6.0.0",
|
||||
"@aw-labs/icons": "0.0.0-66",
|
||||
"@aw-labs/ui": "0.0.0-66",
|
||||
"@aw-labs/appwrite-console": "^10.0.0",
|
||||
"@aw-labs/icons": "0.0.0-72",
|
||||
"@aw-labs/ui": "0.0.0-72",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"echarts": "^5.4.0",
|
||||
"pretty-bytes": "^6.0.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"web-vitals": "^3.0.3"
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { EChartsOption } from 'echarts';
|
||||
import type { BarSeriesOption } from 'echarts/charts';
|
||||
import Base from './base.svelte';
|
||||
|
||||
export let series: BarSeriesOption[];
|
||||
export let options: EChartsOption = null;
|
||||
</script>
|
||||
|
||||
<Base
|
||||
{options}
|
||||
series={series.map((s) => {
|
||||
s.type = 'bar';
|
||||
s.stack = 'total';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"borderWidth": 1
|
||||
},
|
||||
"lineStyle": {
|
||||
"width": 2
|
||||
"width": 1
|
||||
},
|
||||
"symbolSize": 4,
|
||||
"symbol": "emptyCircle",
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
import dark from './dark.json';
|
||||
import type { ECharts } from 'echarts/core';
|
||||
import type { BarSeriesOption, LineSeriesOption } from 'echarts/charts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
registerTheme('light', { ...base, ...light });
|
||||
registerTheme('dark', { ...base, ...dark });
|
||||
|
||||
export let options: EChartsOption;
|
||||
export let series: (BarSeriesOption | LineSeriesOption)[];
|
||||
|
||||
let chart: ECharts;
|
||||
@@ -19,6 +21,7 @@
|
||||
|
||||
$: option = {
|
||||
...defaultConfig,
|
||||
...options,
|
||||
series
|
||||
};
|
||||
|
||||
@@ -39,7 +42,7 @@
|
||||
(await import('echarts/components')).TransformComponent,
|
||||
(await import('echarts/components')).LegendComponent,
|
||||
(await import('echarts/features')).LabelLayout,
|
||||
(await import('echarts/renderers')).CanvasRenderer
|
||||
(await import('echarts/renderers')).SVGRenderer
|
||||
]);
|
||||
makeChart();
|
||||
});
|
||||
@@ -85,6 +88,7 @@
|
||||
<style>
|
||||
.echart {
|
||||
width: 100%;
|
||||
min-height: 12rem;
|
||||
min-height: 10rem;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,8 +17,8 @@ export const defaultConfig: EChartsOption = {
|
||||
containLabel: true,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 15,
|
||||
top: 15
|
||||
bottom: 0,
|
||||
top: 45
|
||||
},
|
||||
xAxis: {
|
||||
type: 'time',
|
||||
@@ -27,6 +27,11 @@ export const defaultConfig: EChartsOption = {
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
splitNumber: 3,
|
||||
minInterval: 1
|
||||
minInterval: 1,
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
}
|
||||
},
|
||||
"axisLabel": {
|
||||
"color": "#666666"
|
||||
"color": "#868EA3"
|
||||
},
|
||||
"splitLine": {
|
||||
"lineStyle": {
|
||||
"color": ["#333333"]
|
||||
"color": ["#4F5769"]
|
||||
}
|
||||
},
|
||||
"splitArea": {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
},
|
||||
"splitLine": {
|
||||
"lineStyle": {
|
||||
"color": ["#E0E6F1"]
|
||||
"color": ["#E8E9F0"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
<script lang="ts">
|
||||
import type { LineSeriesOption } from 'echarts/charts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
import { Colors } from './config';
|
||||
import Base from './base.svelte';
|
||||
|
||||
export let series: LineSeriesOption[];
|
||||
export let options: EChartsOption = null;
|
||||
</script>
|
||||
|
||||
<Base
|
||||
{options}
|
||||
series={series.map((s) => {
|
||||
s.type = 'line';
|
||||
s.stack = 'total';
|
||||
s.lineStyle = {
|
||||
shadowBlur: 38,
|
||||
shadowColor: Colors.Primary,
|
||||
shadowOffsetY: 15,
|
||||
shadowOffsetX: 0
|
||||
};
|
||||
s.showSymbol = false;
|
||||
|
||||
return s;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
export let isTile = false;
|
||||
export let isDashed = false;
|
||||
</script>
|
||||
|
||||
<article class="card" class:common-section={!isTile}>
|
||||
<article class="card" class:is-border-dashed={isDashed} class:common-section={!isTile}>
|
||||
<slot />
|
||||
</article>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
style={`--grid-gap:1.5rem; --grid-item-size:${total > 3 ? '22rem' : '25rem'};`}>
|
||||
<slot />
|
||||
|
||||
{#if limit + offset > total && (total % 2 !== 0 || total % 4 === 0)}
|
||||
<Empty isButton on:click>
|
||||
{#if total > 3 ? total < limit + offset : total % 2 !== 0}
|
||||
<Empty on:click>
|
||||
<slot name="empty" />
|
||||
</Empty>
|
||||
{/if}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
import 'prismjs/plugins/autoloader/prism-autoloader';
|
||||
import 'prismjs/plugins/custom-class/prism-custom-class';
|
||||
import 'prismjs/plugins/line-numbers/prism-line-numbers';
|
||||
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
|
||||
import { afterUpdate } from 'svelte';
|
||||
import { Copy } from '.';
|
||||
|
||||
@@ -49,16 +48,16 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<pre class={`language-${language}`} class:line-numbers={withLineNumbers}>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
<pre class={`language-${language}`} class:line-numbers={withLineNumbers}><code
|
||||
>{code}</code></pre>
|
||||
</section>
|
||||
|
||||
<style lang="scss" global>
|
||||
@import 'prismjs/themes/prism.css';
|
||||
@import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
|
||||
|
||||
.box {
|
||||
--p-box-background-color: var(--color-neutral-300) !important;
|
||||
--p-box-background-color: var(--color-neutral-400) !important;
|
||||
|
||||
body.theme-light & {
|
||||
--p-box-background-color: var(--color-neutral-5) !important;
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
<script lang="ts">
|
||||
export let withIndentation = false;
|
||||
</script>
|
||||
|
||||
<li class="collapsible-item">
|
||||
<details class="collapsible-wrapper">
|
||||
<summary class="collapsible-button">
|
||||
<span class="text"><slot name="title" /></span>
|
||||
<span class="collapsible-button-optional"><slot name="subtitle" /></span>
|
||||
<slot name="beforetitle" />
|
||||
<div>
|
||||
<span class="text"><slot name="title" /></span>
|
||||
<span class="collapsible-button-optional"><slot name="subtitle" /></span>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<span class="icon-cheveron-down" aria-hidden="true" />
|
||||
</div>
|
||||
</summary>
|
||||
<div class="collapsible-content">
|
||||
<div
|
||||
class="collapsible-content"
|
||||
class:u-margin-block-start-8={withIndentation}
|
||||
class:u-padding-inline-32={withIndentation}>
|
||||
<slot />
|
||||
</div>
|
||||
</details>
|
||||
|
||||
@@ -22,21 +22,23 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="input-text-wrapper is-with-end-button">
|
||||
<div>
|
||||
<label class:u-hide={!showLabel} class="label" for={label}>{label}</label>
|
||||
<div class="input-text-wrapper">
|
||||
<div class="input-text-wrapper" style="--amount-of-buttons:1">
|
||||
<input {value} id={label} type="text" class="input-text" readonly />
|
||||
<button
|
||||
type="button"
|
||||
class="input-button"
|
||||
aria-label="Click to copy."
|
||||
on:click={copy}
|
||||
on:mouseenter={() => setTimeout(() => (content = 'Click to copy'))}
|
||||
use:tooltip={{
|
||||
content,
|
||||
hideOnClick: false
|
||||
}}>
|
||||
<span class="icon-duplicate" aria-hidden="true" />
|
||||
</button>
|
||||
<div class="options-list">
|
||||
<button
|
||||
type="button"
|
||||
class="input-button"
|
||||
aria-label="Click to copy."
|
||||
on:click={copy}
|
||||
on:mouseenter={() => setTimeout(() => (content = 'Click to copy'))}
|
||||
use:tooltip={{
|
||||
content,
|
||||
hideOnClick: false
|
||||
}}>
|
||||
<span class="icon-duplicate" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
<li class="drop-tabs-item">
|
||||
{#if disabled}
|
||||
<span class="drop-tabs-button is-disabled">
|
||||
<button class="drop-tabs-button" disabled>
|
||||
<span class="text"><slot /></span>
|
||||
</span>
|
||||
</button>
|
||||
{:else}
|
||||
<a class="drop-tabs-button" {href}>
|
||||
<span class="text"><slot /></span>
|
||||
|
||||
@@ -3,52 +3,44 @@
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import EmptyLight from '$lib/images/empty-light.svg';
|
||||
import EmptyDark from '$lib/images/empty-dark.svg';
|
||||
import { Heading } from '.';
|
||||
|
||||
export let isButton = false;
|
||||
export let single = false;
|
||||
export let target: string = null;
|
||||
export let href: string = null;
|
||||
</script>
|
||||
|
||||
{#if isButton}
|
||||
{#if single}
|
||||
<article class="card u-grid u-cross-center u-width-full-line common-section">
|
||||
<div class="u-flex u-flex-vertical u-cross-center u-gap-24">
|
||||
<button type="button" on:click|preventDefault>
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img src={EmptyDark} alt="create" aria-hidden="true" />
|
||||
{:else}
|
||||
<img src={EmptyLight} alt="create" aria-hidden="true" />
|
||||
{/if}
|
||||
</button>
|
||||
<slot>
|
||||
<div class="u-text-center">
|
||||
<Heading size="7" tag="h4">Create your first {target} to get started.</Heading>
|
||||
<p class="body-text-2 u-margin-block-start-4">
|
||||
Need a hand? Check out our documentation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 u-main-center">
|
||||
<Button external {href} text>Documentation</Button>
|
||||
<Button secondary on:click>Create {target}</Button>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</article>
|
||||
{:else}
|
||||
<button
|
||||
on:click|preventDefault
|
||||
type="button"
|
||||
class="card u-grid u-cross-center u-width-full-line dashed"
|
||||
class:common-section={single}>
|
||||
{#if single}
|
||||
<div class="u-flex u-flex-vertical u-cross-center u-gap-24">
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img src={EmptyDark} alt="create" aria-hidden="true" />
|
||||
{:else}
|
||||
<img src={EmptyLight} alt="create" aria-hidden="true" />
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<div class="common-section">
|
||||
<Button secondary round>
|
||||
<i class="icon-plus" />
|
||||
</Button>
|
||||
</div>
|
||||
<div class="common-section">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
{:else}
|
||||
<article class="card u-grid u-cross-center u-width-full-line" class:common-section={single}>
|
||||
{#if single}
|
||||
<div class="u-flex u-flex-vertical u-cross-center u-gap-24">
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img src={EmptyDark} alt="create" aria-hidden="true" />
|
||||
{:else}
|
||||
<img src={EmptyLight} alt="create" aria-hidden="true" />
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="common-section u-main-center u-flex">
|
||||
class="card u-grid u-cross-center u-width-full-line dashed">
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<div class="common-section">
|
||||
<Button secondary round>
|
||||
<i class="icon-plus" />
|
||||
</Button>
|
||||
@@ -56,6 +48,6 @@
|
||||
<div class="common-section">
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
</article>
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -3,20 +3,24 @@
|
||||
import Light from '$lib/images/search-light.svg';
|
||||
import Dark from '$lib/images/search-dark.svg';
|
||||
import PaginationInline from './paginationInline.svelte';
|
||||
|
||||
export let hidePages = false;
|
||||
</script>
|
||||
|
||||
<article class="card u-grid u-cross-center u-width-full-line common-section">
|
||||
<div class="u-flex u-flex-vertical u-cross-center u-gap-24">
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img src={Dark} alt="create" aria-hidden="true" />
|
||||
{:else}
|
||||
<img src={Light} alt="create" aria-hidden="true" />
|
||||
{/if}
|
||||
<button type="button" on:click|preventDefault>
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img src={Dark} alt="create" aria-hidden="true" />
|
||||
{:else}
|
||||
<img src={Light} alt="create" aria-hidden="true" />
|
||||
{/if}
|
||||
</button>
|
||||
<slot />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: 0</p>
|
||||
<PaginationInline limit={1} offset={0} sum={0} />
|
||||
<PaginationInline limit={1} offset={0} sum={0} {hidePages} />
|
||||
</div>
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
<script>
|
||||
import { FormItem } from '$lib/elements/forms';
|
||||
|
||||
export let show = false;
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<section class="modal is-inner-modal">
|
||||
<header class="modal-header u-flex-wrap">
|
||||
<h4 class="modal-title body-text-1">
|
||||
<slot name="title" />
|
||||
</h4>
|
||||
<button
|
||||
type="button"
|
||||
class="x-button"
|
||||
aria-label="Close"
|
||||
title="Close"
|
||||
on:click={() => (show = false)}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
<p class="u-flex-basis-100-percent">
|
||||
<slot name="subtitle" />
|
||||
</p>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</section>
|
||||
<FormItem>
|
||||
<section class="modal is-inner-modal">
|
||||
<div class="modal-form">
|
||||
<header class="modal-header u-flex-wrap">
|
||||
<h4 class="modal-title body-text-1">
|
||||
<slot name="title" />
|
||||
</h4>
|
||||
<button
|
||||
type="button"
|
||||
class="x-button"
|
||||
aria-label="Close"
|
||||
title="Close"
|
||||
on:click={() => (show = false)}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
<p class="u-flex-basis-100-percent">
|
||||
<slot name="subtitle" />
|
||||
</p>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</FormItem>
|
||||
{/if}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||
import { Alert } from '$lib/components';
|
||||
|
||||
export let show = false;
|
||||
@@ -13,6 +13,14 @@
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(() => {
|
||||
if (show) openModal();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (show) closeModal();
|
||||
});
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === dialog) {
|
||||
closeModal();
|
||||
@@ -21,7 +29,7 @@
|
||||
function openModal() {
|
||||
if (dialog && !dialog.open) {
|
||||
dialog.showModal();
|
||||
document.body.classList.add('u-overflow-hidden');
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +39,7 @@
|
||||
dispatch('close');
|
||||
dialog.close();
|
||||
show = false;
|
||||
document.body.classList.remove('u-overflow-hidden');
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,50 +69,52 @@
|
||||
class:is-small={size === 'small'}
|
||||
class:is-big={size === 'big'}
|
||||
bind:this={dialog}>
|
||||
<!-- svelte-ignore a11y-no-redundant-roles -->
|
||||
<form class="modal-form" role="form" on:submit|preventDefault>
|
||||
<header class="modal-header">
|
||||
{#if warning}
|
||||
<div class="avatar is-color-orange is-medium">
|
||||
<span class="icon-exclamation" aria-hidden="true" />
|
||||
</div>
|
||||
{/if}
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="header" />
|
||||
</h4>
|
||||
{#if closable}
|
||||
<button
|
||||
type="button"
|
||||
class="x-button"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={closeModal}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<div bind:this={alert}>
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{#if $$slots.footer}
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
{#if show}
|
||||
<!-- svelte-ignore a11y-no-redundant-roles -->
|
||||
<form class="modal-form" role="form" on:submit|preventDefault>
|
||||
<header class="modal-header">
|
||||
{#if warning}
|
||||
<div class="avatar is-color-orange is-medium">
|
||||
<span class="icon-exclamation" aria-hidden="true" />
|
||||
</div>
|
||||
{/if}
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="header" />
|
||||
</h4>
|
||||
{#if closable}
|
||||
<button
|
||||
type="button"
|
||||
class="x-button"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={closeModal}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<div bind:this={alert}>
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
</form>
|
||||
|
||||
{#if $$slots.footer}
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</form>
|
||||
{/if}
|
||||
</dialog>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { DropList, DropListItem } from '..';
|
||||
import Custom from './custom.svelte';
|
||||
import Team from './team.svelte';
|
||||
@@ -22,10 +21,7 @@
|
||||
</script>
|
||||
|
||||
<DropList bind:show={showDropdown} placement="bottom-end">
|
||||
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Add role</span>
|
||||
</Button>
|
||||
<slot />
|
||||
<svelte:fragment slot="list">
|
||||
<DropListItem disabled={$groups.has('any')} on:click={() => dispatch('create', ['any'])}>
|
||||
Any
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export { default as Permissions } from './permissions.svelte';
|
||||
export { default as Roles } from './roles.svelte';
|
||||
export { default as Team } from './team.svelte';
|
||||
export { default as User } from './user.svelte';
|
||||
|
||||
@@ -10,26 +10,23 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellHead,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from '$lib/elements/table';
|
||||
import { difference } from '$lib/helpers/array';
|
||||
import { symmetricDifference } from '$lib/helpers/array';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { writable, type Unsubscriber } from 'svelte/store';
|
||||
import { Empty } from '../';
|
||||
import Actions from './actions.svelte';
|
||||
import Row from './row.svelte';
|
||||
|
||||
export let withCreate = false;
|
||||
export let withCrud = true;
|
||||
export let permissions: string[] = [];
|
||||
export let executeAccess: string[] = [];
|
||||
|
||||
let showUser = false;
|
||||
let showTeam = false;
|
||||
@@ -43,10 +40,7 @@
|
||||
permissions.forEach(fromPermissionString);
|
||||
unsubscribe = groups.subscribe(() => {
|
||||
const current = exportRoles();
|
||||
if (
|
||||
difference(current, permissions).length ||
|
||||
difference(permissions, current).length
|
||||
) {
|
||||
if (symmetricDifference(current, permissions).length) {
|
||||
permissions = current;
|
||||
}
|
||||
});
|
||||
@@ -145,76 +139,61 @@
|
||||
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
$: if (executeAccess.length && !permissions.length) {
|
||||
executeAccess.forEach((permission) => {
|
||||
addRole(permission);
|
||||
});
|
||||
}
|
||||
$: if ([...$groups]?.length && !permissions.length) {
|
||||
executeAccess = [...$groups].sort(sortRoles).map(([role]) => role);
|
||||
}
|
||||
|
||||
//TODO: click on Empty components opens the dropdown
|
||||
</script>
|
||||
|
||||
{#if [...$groups]?.length}
|
||||
<Table noMargin noStyles noMobile>
|
||||
<TableHeader>
|
||||
<TableCellHead>Role</TableCellHead>
|
||||
{#if withCrud}
|
||||
{#if withCreate}
|
||||
<TableCellHead width={70}>Create</TableCellHead>
|
||||
{/if}
|
||||
<TableCellHead width={70}>Read</TableCellHead>
|
||||
<TableCellHead width={70}>Update</TableCellHead>
|
||||
<TableCellHead width={70}>Delete</TableCellHead>
|
||||
{#if withCreate}
|
||||
<TableCellHead width={70}>Create</TableCellHead>
|
||||
{/if}
|
||||
<TableCellHead width={70}>Read</TableCellHead>
|
||||
<TableCellHead width={70}>Update</TableCellHead>
|
||||
<TableCellHead width={70}>Delete</TableCellHead>
|
||||
<TableCellHead width={40} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each [...$groups].sort(sortRoles) as [role, permission]}
|
||||
<TableRow>
|
||||
<TableCellText title="Role">
|
||||
<TableCell title="Role">
|
||||
<Row {role} />
|
||||
</TableCellText>
|
||||
</TableCell>
|
||||
|
||||
{#if withCrud}
|
||||
{#if withCreate}
|
||||
<TableCell title="Create">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Create"
|
||||
checked={permission.create}
|
||||
on:change={() => togglePermission(role, 'create')} />
|
||||
</TableCell>
|
||||
{/if}
|
||||
<TableCell title="Read">
|
||||
{#if withCreate}
|
||||
<TableCell title="Create">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Read"
|
||||
checked={permission.read}
|
||||
on:change={() => togglePermission(role, 'read')} />
|
||||
</TableCell>
|
||||
<TableCell title="Update">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Update"
|
||||
checked={permission.update}
|
||||
on:change={() => togglePermission(role, 'update')} />
|
||||
</TableCell>
|
||||
<TableCell title="Delete">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Delete"
|
||||
checked={permission.delete}
|
||||
on:change={() => togglePermission(role, 'delete')} />
|
||||
aria-label="Create"
|
||||
checked={permission.create}
|
||||
on:change={() => togglePermission(role, 'create')} />
|
||||
</TableCell>
|
||||
{/if}
|
||||
<TableCell title="Read">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Read"
|
||||
checked={permission.read}
|
||||
on:change={() => togglePermission(role, 'read')} />
|
||||
</TableCell>
|
||||
<TableCell title="Update">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Update"
|
||||
checked={permission.update}
|
||||
on:change={() => togglePermission(role, 'update')} />
|
||||
</TableCell>
|
||||
<TableCell title="Delete">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="icon-check"
|
||||
aria-label="Delete"
|
||||
checked={permission.delete}
|
||||
on:change={() => togglePermission(role, 'delete')} />
|
||||
</TableCell>
|
||||
|
||||
<TableCell title="Remove" width={40}>
|
||||
<div class="u-flex">
|
||||
@@ -231,18 +210,38 @@
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create}>
|
||||
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Add role</span>
|
||||
</Button>
|
||||
</Actions>
|
||||
{:else}
|
||||
<span class="eyebrow-heading-3 u-sep-block-end">ROLE</span>
|
||||
|
||||
<Empty isButton on:click={() => (showDropdown = !showDropdown)}>
|
||||
Add a role to get started
|
||||
</Empty>
|
||||
<article class="card u-grid u-cross-center u-width-full-line dashed">
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<div class="common-section">
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create}>
|
||||
<Button secondary round on:click={() => (showDropdown = !showDropdown)}>
|
||||
<i class="icon-plus" />
|
||||
</Button>
|
||||
</Actions>
|
||||
</div>
|
||||
<div class="common-section">
|
||||
<span class="text"> Add a role to get started </span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/if}
|
||||
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create} />
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellHead,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from '$lib/elements/table';
|
||||
import { difference } from '$lib/helpers/array';
|
||||
import { symmetricDifference } from '$lib/helpers/array';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { writable, type Unsubscriber } from 'svelte/store';
|
||||
import Actions from './actions.svelte';
|
||||
@@ -28,7 +30,7 @@
|
||||
roles.forEach(addRole);
|
||||
unsubscribe = groups.subscribe((n) => {
|
||||
const current = Array.from(n.keys());
|
||||
if (difference(current, roles).length || difference(roles, current).length) {
|
||||
if (symmetricDifference(current, roles).length) {
|
||||
roles = current;
|
||||
}
|
||||
});
|
||||
@@ -69,39 +71,84 @@
|
||||
return n;
|
||||
});
|
||||
}
|
||||
|
||||
function sortRoles(a: string, b: string) {
|
||||
if ((a === 'any') !== (b === 'any')) {
|
||||
return a === 'any' ? -1 : 1;
|
||||
}
|
||||
if ((a === 'users') !== (b === 'users')) {
|
||||
return a === 'users' ? -1 : 1;
|
||||
}
|
||||
if ((a === 'guests') !== (b === 'guests')) {
|
||||
return a === 'guests' ? -1 : 1;
|
||||
}
|
||||
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
$: if (roles) {
|
||||
roles.forEach(addRole);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Table noMargin noStyles noMobile>
|
||||
<TableHeader>
|
||||
<TableCellHead>Role</TableCellHead>
|
||||
<TableCellHead width={40} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each [...$groups.keys()] as role}
|
||||
<TableRow>
|
||||
<TableCellText title="Role">
|
||||
<Row {role} />
|
||||
</TableCellText>
|
||||
<TableCellText title="Remove">
|
||||
<div class="u-flex">
|
||||
<button
|
||||
class="button is-text is-only-icon"
|
||||
type="button"
|
||||
aria-label="delete"
|
||||
on:click={() => deleteRole(role)}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</TableCellText>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create} />
|
||||
{#if [...$groups.keys()]?.length}
|
||||
<Table noMargin noStyles noMobile>
|
||||
<TableHeader>
|
||||
<TableCellHead>Role</TableCellHead>
|
||||
<TableCellHead width={40} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each [...$groups.keys()].sort(sortRoles) as role}
|
||||
<TableRow>
|
||||
<TableCell title="Role">
|
||||
<Row {role} />
|
||||
</TableCell>
|
||||
<TableCellText title="Remove">
|
||||
<div class="u-flex">
|
||||
<button
|
||||
class="button is-text is-only-icon"
|
||||
type="button"
|
||||
aria-label="delete"
|
||||
on:click={() => deleteRole(role)}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</TableCellText>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create}>
|
||||
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Add role</span>
|
||||
</Button>
|
||||
</Actions>
|
||||
{:else}
|
||||
<article class="card u-grid u-cross-center u-width-full-line dashed">
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<div class="common-section">
|
||||
<Actions
|
||||
bind:showCustom
|
||||
bind:showDropdown
|
||||
bind:showTeam
|
||||
bind:showUser
|
||||
{groups}
|
||||
on:create={create}>
|
||||
<Button secondary round on:click={() => (showDropdown = !showDropdown)}>
|
||||
<i class="icon-plus" />
|
||||
</Button>
|
||||
</Actions>
|
||||
</div>
|
||||
<div class="common-section">
|
||||
<span class="text"> Add a role to get started </span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/if}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import { Query, type Models } from '@aw-labs/appwrite-console';
|
||||
import { AvatarInitials, Modal, PaginationInline } from '..';
|
||||
import { AvatarInitials, EmptySearch, Modal, PaginationInline } from '..';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import type { Permission } from './permissions.svelte';
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
|
||||
<Modal bind:show on:submit={create} on:close={reset} size="big">
|
||||
<svelte:fragment slot="header">Select teams</svelte:fragment>
|
||||
<InputSearch bind:value={search} />
|
||||
{#if results?.teams}
|
||||
<InputSearch autofocus disabled={!results?.teams?.length && !search} bind:value={search} />
|
||||
{#if results?.teams?.length}
|
||||
<div class="table-wrapper">
|
||||
<table class="table is-table-layout-auto is-remove-outer-styles">
|
||||
<tbody class="table-tbody">
|
||||
@@ -93,11 +93,44 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset sum={results?.total} hidePages />
|
||||
</div>
|
||||
{:else if search}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<b class="body-text-2">Sorry we couldn't find "{search}"</b>
|
||||
<p>There are no teams that match your search.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 common-section u-main-center">
|
||||
<Button external href="https://appwrite.io/docs/client/teams" text
|
||||
>Documentation</Button>
|
||||
<Button secondary on:click={() => (search = '')}>Clear search</Button>
|
||||
</div>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<p class="text u-line-height-1-5">
|
||||
You have no teams. Create a team to see them here.
|
||||
</p>
|
||||
<p class="text u-line-height-1-5">
|
||||
Need a hand? Check out our <a
|
||||
href="https://appwrite.io/docs/client/teams"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
documentation</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{/if}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset sum={results?.total} hidePages />
|
||||
</div>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button submit disabled={!hasSelection}>Create</Button>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button, InputSearch } from '$lib/elements/forms';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { AvatarInitials, Modal, PaginationInline } from '..';
|
||||
import { AvatarInitials, EmptySearch, Modal, PaginationInline } from '..';
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import { Query, type Models } from '@aw-labs/appwrite-console';
|
||||
import type { Writable } from 'svelte/store';
|
||||
@@ -60,8 +60,8 @@
|
||||
|
||||
<Modal bind:show on:submit={create} on:close={reset} size="big">
|
||||
<svelte:fragment slot="header">Select users</svelte:fragment>
|
||||
<InputSearch bind:value={search} />
|
||||
{#if results?.users}
|
||||
<InputSearch autofocus disabled={!results?.users?.length && !search} bind:value={search} />
|
||||
{#if results?.users?.length}
|
||||
<div class="table-wrapper">
|
||||
<table class="table is-table-layout-auto is-remove-outer-styles">
|
||||
<tbody class="table-tbody">
|
||||
@@ -81,11 +81,37 @@
|
||||
</td>
|
||||
<td class="table-col" data-title="User">
|
||||
<label class="u-flex u-cross-center u-gap-8" for={user.$id}>
|
||||
<AvatarInitials size={32} name={user.name} />
|
||||
<div class="u-line-height-1-5">
|
||||
<div class="body-text-2">{user.name}</div>
|
||||
<div class="u-x-small">{user.$id}</div>
|
||||
</div>
|
||||
{#if user.email || user.phone}
|
||||
{#if user.name}
|
||||
<AvatarInitials size={32} name={user.name} />
|
||||
<div class="u-line-height-1-5">
|
||||
<div class="body-text-2">
|
||||
{user.name}
|
||||
</div>
|
||||
<div class="u-x-small">{user.$id}</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="avatar is-size-small ">
|
||||
<span class="icon-minus-sm" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="u-line-height-1-5">
|
||||
<div class="body-text-2">
|
||||
{user.email ? user.email : user.phone}
|
||||
</div>
|
||||
<div class="u-x-small">{user.$id}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="avatar is-size-small ">
|
||||
<span class="icon-anonymous" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="u-line-height-1-5">
|
||||
<div class="body-text-2">
|
||||
{user.name ? user.name : '-'}
|
||||
</div>
|
||||
<div class="u-x-small">{user.$id}</div>
|
||||
</div>
|
||||
{/if}
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -93,11 +119,44 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset sum={results?.total} hidePages />
|
||||
</div>
|
||||
{:else if search}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<b class="body-text-2">Sorry we couldn't find "{search}"</b>
|
||||
<p>There are no Users that match your search.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 common-section u-main-center">
|
||||
<Button external href="https://appwrite.io/docs/server/users" text
|
||||
>Documentation</Button>
|
||||
<Button secondary on:click={() => (search = '')}>Clear search</Button>
|
||||
</div>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<p class="text u-line-height-1-5">
|
||||
You have no users. Create a user to see them here.
|
||||
</p>
|
||||
<p class="text u-line-height-1-5">
|
||||
Need a hand? Check out our <a
|
||||
href="https://appwrite.io/docs/server/users"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
documentation</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{/if}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset sum={results?.total} hidePages />
|
||||
</div>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button submit disabled={!hasSelection}>Create</Button>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -34,14 +34,18 @@
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(async () => {
|
||||
const url = new URL($page.url);
|
||||
url.search = value;
|
||||
|
||||
if (url.search === value) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Reset to first page if search changes.
|
||||
*/
|
||||
if ($page.data.page > 1) {
|
||||
url.pathname = url.pathname.replace(new RegExp(`/${$page.data.page}*$`), '/');
|
||||
}
|
||||
|
||||
url.search = value;
|
||||
|
||||
goto(url, { keepfocus: true });
|
||||
}, debounce);
|
||||
};
|
||||
|
||||
+39
-36
@@ -1,59 +1,62 @@
|
||||
export const PAGE_LIMIT = 12; // default page limit
|
||||
export const CARD_LIMIT = 6; // default card limit
|
||||
export enum Dependencies {
|
||||
ORGANIZATION = 'organization',
|
||||
PROJECT = 'project',
|
||||
PROJECTS = 'projects',
|
||||
ACCOUNT = 'account',
|
||||
ACCOUNT_SESSIONS = 'account_sessions',
|
||||
USER = 'user',
|
||||
USERS = 'users',
|
||||
SESSIONS = 'sessions',
|
||||
TEAM = 'team',
|
||||
TEAMS = 'teams',
|
||||
MEMBERSHIPS = 'memberships',
|
||||
DATABASE = 'database',
|
||||
COLLECTION = 'collection',
|
||||
DOCUMENT = 'document',
|
||||
DOCUMENTS = 'documents',
|
||||
ATTRIBUTES = 'attributes',
|
||||
INDEXES = 'indexes',
|
||||
BUCKET = 'bucket',
|
||||
FILE = 'file',
|
||||
FILES = 'files',
|
||||
FUNCTION = 'function',
|
||||
FUNCTIONS = 'functions',
|
||||
VARIABLES = 'variables',
|
||||
DEPLOYMENTS = 'deployments',
|
||||
PLATFORM = 'platform',
|
||||
PLATFORMS = 'platforms',
|
||||
KEY = 'key',
|
||||
KEYS = 'keys',
|
||||
DOMAINS = 'domains',
|
||||
WEBHOOK = 'webhook',
|
||||
WEBHOOKS = 'webhooks'
|
||||
ORGANIZATION = 'dependency:organization',
|
||||
PROJECT = 'dependency:project',
|
||||
PROJECTS = 'dependency:projects',
|
||||
ACCOUNT = 'dependency:account',
|
||||
ACCOUNT_SESSIONS = 'dependency:account_sessions',
|
||||
USER = 'dependency:user',
|
||||
USERS = 'dependency:users',
|
||||
SESSIONS = 'dependency:sessions',
|
||||
TEAM = 'dependency:team',
|
||||
TEAMS = 'dependency:teams',
|
||||
MEMBERSHIPS = 'dependency:memberships',
|
||||
DATABASE = 'dependency:database',
|
||||
COLLECTION = 'dependency:collection',
|
||||
DOCUMENT = 'dependency:document',
|
||||
DOCUMENTS = 'dependency:documents',
|
||||
BUCKET = 'dependency:bucket',
|
||||
FILE = 'dependency:file',
|
||||
FILES = 'dependency:files',
|
||||
FUNCTION = 'dependency:function',
|
||||
FUNCTIONS = 'dependency:functions',
|
||||
VARIABLES = 'dependency:variables',
|
||||
DEPLOYMENTS = 'dependency:deployments',
|
||||
EXECUTIONS = 'dependency:executions',
|
||||
PLATFORM = 'dependency:platform',
|
||||
PLATFORMS = 'dependency:platforms',
|
||||
KEY = 'dependency:key',
|
||||
KEYS = 'dependency:keys',
|
||||
DOMAINS = 'dependency:domains',
|
||||
WEBHOOK = 'dependency:webhook',
|
||||
WEBHOOKS = 'dependency:webhooks'
|
||||
}
|
||||
|
||||
export const scopes = [
|
||||
export const scopes: {
|
||||
scope: string;
|
||||
description: string;
|
||||
category: string;
|
||||
}[] = [
|
||||
{
|
||||
scope: 'users.read',
|
||||
description: "Access to read your project's users",
|
||||
category: 'Authentication'
|
||||
category: 'Auth'
|
||||
},
|
||||
{
|
||||
scope: 'users.write',
|
||||
description: "Access to create, update, and delete your project's users",
|
||||
category: 'Authentication'
|
||||
category: 'Auth'
|
||||
},
|
||||
{
|
||||
scope: 'teams.read',
|
||||
description: "Access to read your project's teams",
|
||||
category: 'Authentication'
|
||||
category: 'Auth'
|
||||
},
|
||||
{
|
||||
scope: 'teams.write',
|
||||
description: "Access to create, update, and delete your project's teams",
|
||||
category: 'Authentication'
|
||||
category: 'Auth'
|
||||
},
|
||||
{
|
||||
scope: 'databases.read',
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
let element: HTMLInputElement;
|
||||
let error: string;
|
||||
|
||||
const pattern = String.raw`^[^]+\s+[^]+\s+[^]+\s+[^]+\s+[^]`;
|
||||
|
||||
onMount(() => {
|
||||
if (element && autofocus) {
|
||||
element.focus();
|
||||
@@ -57,6 +59,7 @@
|
||||
{maxlength}
|
||||
{readonly}
|
||||
{step}
|
||||
{pattern}
|
||||
type="text"
|
||||
class="input-text"
|
||||
bind:value
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
const handleInvalid = (event: Event) => {
|
||||
function handleInvalid(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (element.validity.valueMissing) {
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
error = element.validationMessage;
|
||||
};
|
||||
}
|
||||
|
||||
$: if (value) {
|
||||
error = null;
|
||||
@@ -45,6 +45,7 @@
|
||||
{disabled}
|
||||
{readonly}
|
||||
{required}
|
||||
step=".001"
|
||||
autocomplete={autocomplete ? 'on' : 'off'}
|
||||
type="datetime-local"
|
||||
class="input-text"
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
import { clickOnEnter } from '$lib/helpers/a11y';
|
||||
</script>
|
||||
|
||||
<div class="table-row" role="row" on:keyup={clickOnEnter} on:click|preventDefault>
|
||||
<!-- svelte-ignore a11y-unknown-role -->
|
||||
<tr
|
||||
class="table-row"
|
||||
role="row button"
|
||||
tabindex="0"
|
||||
on:keyup={clickOnEnter}
|
||||
on:click|preventDefault>
|
||||
<slot />
|
||||
</div>
|
||||
</tr>
|
||||
|
||||
@@ -8,3 +8,7 @@ export function difference(arr1: unknown[], arr2: unknown[]) {
|
||||
const intersection = new Set(arr1.filter((elem) => !set.has(elem)));
|
||||
return Array.from(intersection);
|
||||
}
|
||||
|
||||
export function symmetricDifference(arr1: unknown[], arr2: unknown[]) {
|
||||
return difference(arr1, arr2).concat(difference(arr2, arr1));
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
export function calculateSize(bytes: number, decimals = 1) {
|
||||
@@ -20,55 +22,16 @@ export function bytesToSize(value: number, unit: string) {
|
||||
return value / Math.pow(1024, index);
|
||||
}
|
||||
|
||||
export function humanFileSize(value: number): {
|
||||
export function humanFileSize(bytes: number): {
|
||||
value: string;
|
||||
unit: string;
|
||||
} {
|
||||
if (!value) return { value: 'No', unit: 'Bytes' };
|
||||
const length = value.toString().length;
|
||||
const unit =
|
||||
length < 7
|
||||
? 'kilobyte'
|
||||
: length < 11
|
||||
? 'megabyte'
|
||||
: length < 15
|
||||
? 'gigabyte'
|
||||
: length < 19
|
||||
? 'terabyte'
|
||||
: 'petabyte';
|
||||
|
||||
const formatter = Intl.NumberFormat('en', {
|
||||
style: 'unit',
|
||||
maximumSignificantDigits: 3,
|
||||
maximumFractionDigits: 2,
|
||||
unit
|
||||
});
|
||||
|
||||
while (value > 1000) {
|
||||
value /= 1000;
|
||||
}
|
||||
|
||||
const parts: {
|
||||
integer: string;
|
||||
unit: string;
|
||||
fraction?: string;
|
||||
decimal?: string;
|
||||
} = formatter.formatToParts(value).reduce(
|
||||
(prev, curr) => {
|
||||
prev[curr.type] = curr.value;
|
||||
|
||||
return prev;
|
||||
},
|
||||
{
|
||||
integer: '',
|
||||
unit: '',
|
||||
decimal: '',
|
||||
fraction: ''
|
||||
}
|
||||
);
|
||||
const value = prettyBytes(bytes, {
|
||||
locale: 'en'
|
||||
}).split(' ');
|
||||
|
||||
return {
|
||||
value: `${parts.integer}${parts.decimal}${parts.fraction}`,
|
||||
unit: parts.unit
|
||||
value: value[0],
|
||||
unit: value[1]
|
||||
};
|
||||
}
|
||||
|
||||
+29
-32
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Empty, Pagination } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { EmptySearch, Pagination, Trim } from '$lib/components';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -12,18 +11,21 @@
|
||||
} from '$lib/elements/table';
|
||||
import { Container } from '$lib/layout';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import type { PageData } from './$types';
|
||||
import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import { PAGE_LIMIT } from '$lib/constants';
|
||||
import { page } from '$app/stores';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
export let data: PageData;
|
||||
export let logs: Models.LogList;
|
||||
export let path: string;
|
||||
export let offset = 0;
|
||||
|
||||
const getBrowser = (clientCode: string) => sdkForProject.avatars.getBrowser(clientCode, 80, 80);
|
||||
const getBrowser = (clientCode: string) => {
|
||||
return sdkForConsole.avatars.getBrowser(clientCode, 40, 40);
|
||||
};
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
{#if data.logs.total}
|
||||
{#if logs.total}
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableCellHead>Client</TableCellHead>
|
||||
@@ -33,7 +35,7 @@
|
||||
<TableCellHead>Date</TableCellHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.logs.logs as log}
|
||||
{#each logs.logs as log}
|
||||
<TableRow>
|
||||
<TableCell title="Client">
|
||||
{#if log.clientName}
|
||||
@@ -45,20 +47,17 @@
|
||||
src={getBrowser(log.clientCode).toString()}
|
||||
alt={log.clientName} />
|
||||
</div>
|
||||
<p class="text u-trim">
|
||||
<Trim>
|
||||
{log.clientName}
|
||||
{log.clientVersion}
|
||||
on {log.osName}
|
||||
{log.osVersion}
|
||||
</p>
|
||||
</Trim>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="u-flex u-cross-center u-gap-12">
|
||||
<p class="text u-trim">
|
||||
<span class="avatar is-color-empty" />
|
||||
|
||||
Unknown
|
||||
</p>
|
||||
<span class="avatar is-color-empty" />
|
||||
<p class="text u-trim">Unknown</p>
|
||||
</div>
|
||||
{/if}
|
||||
</TableCell>
|
||||
@@ -77,22 +76,20 @@
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {logs.total}</p>
|
||||
<Pagination limit={PAGE_LIMIT} {path} {offset} sum={logs.total} />
|
||||
</div>
|
||||
{:else}
|
||||
<Empty single>
|
||||
<p>No logs available</p>
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetLogs"
|
||||
>Documentation</Button>
|
||||
</Empty>
|
||||
<EmptySearch>
|
||||
<div class="u-flex u-flex-vertical u-cross-center">
|
||||
<div class="u-text-center">
|
||||
<p class="text u-line-height-1-5">
|
||||
You have no activity. Once your users start interacting with your app you'll
|
||||
see their activity here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{/if}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {data.logs.total}</p>
|
||||
<Pagination
|
||||
limit={PAGE_LIMIT}
|
||||
path={`/console/project-${$page.params.project}/authentication/user-${$page.params.user}/activity`}
|
||||
offset={data.offset}
|
||||
sum={data.logs.total} />
|
||||
</div>
|
||||
</Container>
|
||||
@@ -47,7 +47,7 @@
|
||||
<span class="text">Support</span>
|
||||
</a>
|
||||
</nav>
|
||||
<nav class="user-profile">
|
||||
<nav class="u-flex u-height-100-percents u-sep-inline-start">
|
||||
{#if $user}
|
||||
<div class="drop-wrapper" class:is-open={showDropdown} bind:this={droplistElement}>
|
||||
<button class="user-profile-button" on:click={() => (showDropdown = !showDropdown)}>
|
||||
|
||||
@@ -13,3 +13,5 @@ export { default as WizardStep } from './wizardStep.svelte';
|
||||
export { default as Breadcrumbs } from './breadcrumbs.svelte';
|
||||
export { default as Unauthenticated } from './unauthenticated.svelte';
|
||||
export { default as Usage, type UsagePeriods } from './usage.svelte';
|
||||
export { default as Activity } from './activity.svelte';
|
||||
export { default as Progress } from './progress.svelte';
|
||||
|
||||
@@ -35,8 +35,17 @@
|
||||
.getElementsByClassName('code-panel-content')[0]
|
||||
.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
$log.show = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
|
||||
{#if $log.data}
|
||||
<section class="cover-frame">
|
||||
<header class="cover-frame-header u-flex u-gap-16 u-main-space-between u-cross-center">
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
<span class="text">Overview</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
class:is-selected={$page.url.pathname.startsWith(`${path}/auth`)}
|
||||
href={`${path}/auth`}>
|
||||
<span class="icon-user-group" aria-hidden="true" />
|
||||
<span class="text">Auth</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
@@ -40,26 +49,6 @@
|
||||
<span class="text">Databases</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
class:is-selected={$page.url.pathname.startsWith(`${path}/storage`)}
|
||||
href={`${path}/storage`}>
|
||||
<span class="icon-folder" aria-hidden="true" />
|
||||
<span class="text">Storage</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
class:is-selected={$page.url.pathname.startsWith(
|
||||
`${path}/authentication`
|
||||
)}
|
||||
href={`${path}/authentication`}>
|
||||
<span class="icon-user-group" aria-hidden="true" />
|
||||
<span class="text">Authentication</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
@@ -69,6 +58,15 @@
|
||||
<span class="text">Functions</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="drop-list-item">
|
||||
<a
|
||||
class="drop-button"
|
||||
class:is-selected={$page.url.pathname.startsWith(`${path}/storage`)}
|
||||
href={`${path}/storage`}>
|
||||
<span class="icon-folder" aria-hidden="true" />
|
||||
<span class="text">Storage</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<script lang="ts">
|
||||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||
|
||||
let width: number;
|
||||
let updater: ReturnType<typeof setTimeout>;
|
||||
let completed = false;
|
||||
|
||||
const minimum = 0.08;
|
||||
const maximum = 0.994;
|
||||
const settleTime = 700;
|
||||
const intervalTime = 800;
|
||||
const stepSizes = [0, 0.005, 0.01, 0.02];
|
||||
|
||||
function animate(): void {
|
||||
if (updater) {
|
||||
clearInterval(updater);
|
||||
}
|
||||
updater = setInterval(() => {
|
||||
const randomStep = stepSizes[Math.floor(Math.random() * stepSizes.length)];
|
||||
const step = getIncrement(width) + randomStep;
|
||||
if (width < maximum) {
|
||||
width = width + step;
|
||||
}
|
||||
if (width > maximum) {
|
||||
width = maximum;
|
||||
stop();
|
||||
}
|
||||
}, intervalTime);
|
||||
}
|
||||
|
||||
function start(): void {
|
||||
width = minimum;
|
||||
animate();
|
||||
}
|
||||
|
||||
function complete(): void {
|
||||
clearInterval(updater);
|
||||
width = 1;
|
||||
setTimeout(() => {
|
||||
completed = true;
|
||||
setTimeout(() => {
|
||||
completed = false;
|
||||
width = 0;
|
||||
}, settleTime);
|
||||
}, settleTime);
|
||||
}
|
||||
|
||||
function getIncrement(number: number): number {
|
||||
if (number >= 0 && number < 0.2) return 0.1;
|
||||
else if (number >= 0.2 && number < 0.5) return 0.04;
|
||||
else if (number >= 0.5 && number < 0.8) return 0.02;
|
||||
else if (number >= 0.8 && number < 0.99) return 0.005;
|
||||
return 0;
|
||||
}
|
||||
|
||||
beforeNavigate(start);
|
||||
afterNavigate(complete);
|
||||
|
||||
$: barStyle = (width && width * 100 && `width: ${width * 100}%;`) || '';
|
||||
</script>
|
||||
|
||||
<svelte:head />
|
||||
|
||||
{#if width}
|
||||
<div class="progress-bar" class:progress-bar-hiding={completed} style={barStyle} />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.progress-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 2px;
|
||||
transition: width 0.2s ease-in-out;
|
||||
z-index: 5;
|
||||
background: hsl(var(--color-primary-200));
|
||||
}
|
||||
|
||||
.progress-bar-hiding {
|
||||
transition: top 0.8s ease;
|
||||
top: -8px;
|
||||
}
|
||||
</style>
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
<div class="u-margin-block-start-auto" />
|
||||
<p class="u-max-width-500 u-width-full-line u-margin-block-start-24">
|
||||
version 0.15.2.402
|
||||
<!-- version 0.15.2.402 -->
|
||||
</p>
|
||||
<div class="u-margin-block-start-20" />
|
||||
</div>
|
||||
|
||||
+51
-38
@@ -42,12 +42,17 @@
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<Heading tag="h2" size="5">{title}</Heading>
|
||||
<DropTabs>
|
||||
<DropTabsLink href={`${path}/24h`} disabled={$page.params.period === '24h'}
|
||||
>24h</DropTabsLink>
|
||||
<DropTabsLink href={`${path}/30d`} disabled={$page.params.period === '30d'}
|
||||
>30d</DropTabsLink>
|
||||
<DropTabsLink href={`${path}/90d`} disabled={$page.params.period === '90d'}
|
||||
>90d</DropTabsLink>
|
||||
<DropTabsLink href={`${path}/24h`} disabled={$page.params.period === '24h'}>
|
||||
24h
|
||||
</DropTabsLink>
|
||||
<DropTabsLink
|
||||
href={`${path}/30d`}
|
||||
disabled={!$page.params.period || $page.params.period === '30d'}>
|
||||
30d
|
||||
</DropTabsLink>
|
||||
<DropTabsLink href={`${path}/90d`} disabled={$page.params.period === '90d'}>
|
||||
90d
|
||||
</DropTabsLink>
|
||||
</DropTabs>
|
||||
</div>
|
||||
<Card>
|
||||
@@ -70,14 +75,16 @@
|
||||
<Heading tag="h6" size="6">{total(created)}</Heading>
|
||||
<p>{createdMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: createdMetadata.legend,
|
||||
data: [...created.map((e) => [e.date, e.value])],
|
||||
color: Colors.Secondary
|
||||
}
|
||||
]} />
|
||||
<div style="height: 12rem;">
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: createdMetadata.legend,
|
||||
data: [...created.map((e) => [e.date, e.value])],
|
||||
color: Colors.Secondary
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
@@ -85,14 +92,16 @@
|
||||
<Heading tag="h6" size="6">{total(read)}</Heading>
|
||||
<p>{readMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: readMetadata.legend,
|
||||
data: [...read.map((e) => [e.date, e.value])],
|
||||
color: Colors.Tertiary
|
||||
}
|
||||
]} />
|
||||
<div style="height: 12rem;">
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: readMetadata.legend,
|
||||
data: [...read.map((e) => [e.date, e.value])],
|
||||
color: Colors.Tertiary
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
@@ -100,14 +109,16 @@
|
||||
<Heading tag="h6" size="6">{total(updated)}</Heading>
|
||||
<p>{updatedMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: updatedMetadata.legend,
|
||||
data: [...updated.map((e) => [e.date, e.value])],
|
||||
color: Colors.Quaternary
|
||||
}
|
||||
]} />
|
||||
<div style="height: 12rem;">
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: updatedMetadata.legend,
|
||||
data: [...updated.map((e) => [e.date, e.value])],
|
||||
color: Colors.Quaternary
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
@@ -115,14 +126,16 @@
|
||||
<Heading tag="h6" size="6">{total(deleted)}</Heading>
|
||||
<p>{deletedMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: deletedMetadata.legend,
|
||||
data: [...deleted.map((e) => [e.date, e.value])],
|
||||
color: Colors.Quinary
|
||||
}
|
||||
]} />
|
||||
<div style="height: 12rem;">
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: deletedMetadata.legend,
|
||||
data: [...deleted.map((e) => [e.date, e.value])],
|
||||
color: Colors.Quinary
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
{/if}
|
||||
</Card>
|
||||
</Tiles>
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
let showExitModal = false;
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape' && !showExitModal) {
|
||||
const openDialog = document.querySelectorAll('dialog[open]');
|
||||
if (event.key === 'Escape' && !showExitModal && !openDialog?.length) {
|
||||
event.preventDefault();
|
||||
dispatch('exit');
|
||||
wizard.hide();
|
||||
|
||||
+121
-282
@@ -1,18 +1,14 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import type { SvelteComponent } from 'svelte';
|
||||
import Apple from '../../routes/console/project-[project]/authentication/_appleOAuth.svelte';
|
||||
import Microsoft from '../../routes/console/project-[project]/authentication/_microsoftOAuth.svelte';
|
||||
import Okta from '../../routes/console/project-[project]/authentication/_oktaOAuth.svelte';
|
||||
import Auth0 from '../../routes/console/project-[project]/authentication/_auth0OAuth.svelte';
|
||||
import Main from '../../routes/console/project-[project]/authentication/_mainOAuth.svelte';
|
||||
import Apple from '../../routes/console/project-[project]/auth/_appleOAuth.svelte';
|
||||
import Microsoft from '../../routes/console/project-[project]/auth/_microsoftOAuth.svelte';
|
||||
import Okta from '../../routes/console/project-[project]/auth/_oktaOAuth.svelte';
|
||||
import Auth0 from '../../routes/console/project-[project]/auth/_auth0OAuth.svelte';
|
||||
import Main from '../../routes/console/project-[project]/auth/_mainOAuth.svelte';
|
||||
|
||||
export type Provider = {
|
||||
name: string;
|
||||
export type Provider = Models.Provider & {
|
||||
icon: string;
|
||||
active: boolean;
|
||||
id: string | null;
|
||||
secret: string | null;
|
||||
docs?: string;
|
||||
component?: typeof SvelteComponent;
|
||||
};
|
||||
@@ -22,279 +18,122 @@ export type Providers = {
|
||||
};
|
||||
|
||||
const setProviders = (project: Models.Project): Provider[] => {
|
||||
return [
|
||||
{
|
||||
name: 'Amazon',
|
||||
icon: 'amazon',
|
||||
active: false,
|
||||
id: project?.providerAmazonAppid,
|
||||
secret: project?.providerAmazonSecret,
|
||||
docs: 'https://developer.amazon.com/apps-and-games/services-and-apis',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Apple',
|
||||
icon: 'apple',
|
||||
active: false,
|
||||
id: project?.providerAppleAppid,
|
||||
secret: project?.providerAppleSecret,
|
||||
docs: 'https://developer.apple.com/',
|
||||
component: Apple
|
||||
},
|
||||
{
|
||||
name: 'Auth0',
|
||||
icon: 'auth0',
|
||||
active: false,
|
||||
id: project?.providerAuth0Appid,
|
||||
secret: project?.providerAuth0Secret,
|
||||
docs: 'https://auth0.com/developers',
|
||||
component: Auth0
|
||||
},
|
||||
{
|
||||
name: 'Bitbucket',
|
||||
icon: 'bitBucket',
|
||||
active: false,
|
||||
id: project?.providerBitbucketAppid,
|
||||
secret: project?.providerBitbucketSecret,
|
||||
docs: 'https://developer.atlassian.com/bitbucket',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Bitly',
|
||||
icon: 'bitly',
|
||||
active: false,
|
||||
id: project?.providerBitlyAppid,
|
||||
secret: project?.providerBitlySecret,
|
||||
docs: 'https://dev.bitly.com/v4_documentation.html',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Box',
|
||||
icon: 'box',
|
||||
active: false,
|
||||
id: project?.providerBoxAppid,
|
||||
secret: project?.providerBoxSecret,
|
||||
docs: 'https://developer.box.com/reference/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Discord',
|
||||
icon: 'discord',
|
||||
active: false,
|
||||
id: project?.providerDiscordAppid,
|
||||
secret: project?.providerDiscordSecret,
|
||||
docs: 'https://discordapp.com/developers/docs/topics/oauth2',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Dropbox',
|
||||
icon: 'dropbox',
|
||||
active: false,
|
||||
id: project?.providerDropboxAppid,
|
||||
secret: project?.providerDropboxSecret,
|
||||
docs: 'https://www.dropbox.com/developers/documentation',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Facebook',
|
||||
icon: 'facebook',
|
||||
active: false,
|
||||
id: project?.providerFacebookAppid,
|
||||
secret: project?.providerFacebookSecret,
|
||||
docs: 'https://developers.facebook.com/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Github',
|
||||
icon: 'github',
|
||||
active: false,
|
||||
id: project?.providerGithubAppid,
|
||||
secret: project?.providerGithubSecret,
|
||||
docs: 'https://developer.github.com/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Gitlab',
|
||||
icon: 'gitlab',
|
||||
active: false,
|
||||
id: project?.providerGitlabAppid,
|
||||
secret: project?.providerGitlabSecret,
|
||||
docs: 'https://docs.gitlab.com/ee/api/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Google',
|
||||
icon: 'google',
|
||||
active: false,
|
||||
id: project?.providerGoogleAppid,
|
||||
secret: project?.providerGoogleSecret,
|
||||
docs: 'https://support.google.com/googleapi/answer/6158849',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Linkedin',
|
||||
icon: 'linkedin',
|
||||
active: false,
|
||||
id: project?.providerLinkedinAppid,
|
||||
secret: project?.providerLinkedinSecret,
|
||||
docs: 'https://developer.linkedin.com/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Microsoft',
|
||||
icon: 'microsoft',
|
||||
active: false,
|
||||
id: project?.providerMicrosoftAppid,
|
||||
secret: project?.providerMicrosoftSecret,
|
||||
docs: 'https://developer.microsoft.com/en-us/',
|
||||
component: Microsoft
|
||||
},
|
||||
{
|
||||
name: 'Notion',
|
||||
icon: 'notion',
|
||||
active: false,
|
||||
id: project?.providerNotionAppid,
|
||||
secret: project?.providerNotionSecret,
|
||||
docs: 'https://developers.notion.com/docs',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Okta',
|
||||
icon: 'okta',
|
||||
active: false,
|
||||
id: project?.providerOktaAppid,
|
||||
secret: project?.providerOktaSecret,
|
||||
docs: 'https://developer.okta.com/',
|
||||
component: Okta
|
||||
},
|
||||
{
|
||||
name: 'Paypal',
|
||||
icon: 'paypal',
|
||||
active: false,
|
||||
id: project?.providerPaypalAppid,
|
||||
secret: project?.providerPaypalSecret,
|
||||
docs: 'https://developer.paypal.com/docs/api/overview/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Paypal (sandbox)',
|
||||
icon: 'paypal',
|
||||
active: false,
|
||||
id: project?.providerPaypalSandboxAppid,
|
||||
secret: project?.providerPaypalSandboxSecret,
|
||||
docs: 'https://developer.paypal.com/docs/api/overview/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Salesforce',
|
||||
icon: 'salesforce',
|
||||
active: false,
|
||||
id: project?.providerSalesforceAppid,
|
||||
secret: project?.providerSalesforceSecret,
|
||||
docs: 'https://developer.salesforce.com/docs/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Slack',
|
||||
icon: 'slack',
|
||||
active: false,
|
||||
id: project?.providerSlackAppid,
|
||||
secret: project?.providerSlackSecret,
|
||||
docs: 'https://api.slack.com/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Spotify',
|
||||
icon: 'spotify',
|
||||
active: false,
|
||||
id: project?.providerSpotifyAppid,
|
||||
secret: project?.providerSpotifySecret,
|
||||
docs: 'https://developer.spotify.com/documentation/general/guides/authorization-guide/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Stripe',
|
||||
icon: 'stripe',
|
||||
active: false,
|
||||
id: project?.providerStripeAppid,
|
||||
secret: project?.providerStripeSecret,
|
||||
docs: 'https://stripe.com/docs/api',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Tradeshift',
|
||||
icon: 'tradeshift',
|
||||
active: false,
|
||||
id: project?.providerTradeshiftAppid,
|
||||
secret: project?.providerTradeshiftSecret,
|
||||
docs: 'https://developers.tradeshift.com/docs/api',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Tradeshift(sandbox)',
|
||||
icon: 'tradeshift',
|
||||
active: false,
|
||||
id: project?.providerTradeshiftBoxAppid,
|
||||
secret: project?.providerTradeshiftBoxSecret,
|
||||
docs: 'https://developers.tradeshift.com/docs/api',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Twitch',
|
||||
icon: 'twitch',
|
||||
active: false,
|
||||
id: project?.providerTwitchAppid,
|
||||
secret: project?.providerTwitchSecret,
|
||||
docs: 'https://dev.twitch.tv/docs/authentication',
|
||||
component: Main
|
||||
},
|
||||
return (
|
||||
project?.providers.map((n) => {
|
||||
let docs: Provider['docs'];
|
||||
let icon: Provider['icon'] = n.name.toLowerCase();
|
||||
let component: Provider['component'] = Main;
|
||||
|
||||
{
|
||||
name: 'Wordpress',
|
||||
icon: 'wordpress',
|
||||
active: false,
|
||||
id: project?.providerWordpressAppid,
|
||||
secret: project?.providerWordpressSecret,
|
||||
docs: 'https://developer.wordpress.com/docs/oauth2/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Yahoo',
|
||||
icon: 'yahoo',
|
||||
active: false,
|
||||
id: project?.providerYahooAppid,
|
||||
secret: project?.providerYahooSecret,
|
||||
docs: 'https://developer.yahoo.com/oauth2/guide/flows_authcode/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Yammer',
|
||||
icon: 'ms_yammer',
|
||||
active: false,
|
||||
id: project?.providerYammerAppid,
|
||||
secret: project?.providerYammerSecret,
|
||||
docs: 'https://developer.yammer.com/docs/oauth-2',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Yandex',
|
||||
icon: 'yandex',
|
||||
active: false,
|
||||
id: project?.providerYandexAppid,
|
||||
secret: project?.providerYandexSecret,
|
||||
docs: 'https://tech.yandex.com/oauth/',
|
||||
component: Main
|
||||
},
|
||||
{
|
||||
name: 'Zoom',
|
||||
icon: 'zoom',
|
||||
active: false,
|
||||
id: project?.providerZoomAppid,
|
||||
secret: project?.providerZoomSecret,
|
||||
docs: 'https://marketplace.zoom.us/docs/guides/auth/oauth/',
|
||||
component: Main
|
||||
}
|
||||
];
|
||||
switch (n.name.toLowerCase()) {
|
||||
case 'amazon':
|
||||
docs = 'https://developer.amazon.com/apps-and-games/services-and-apis';
|
||||
break;
|
||||
case 'apple':
|
||||
docs = 'https://developer.apple.com/';
|
||||
component = Apple;
|
||||
break;
|
||||
case 'auth0':
|
||||
docs = 'https://auth0.com/developers';
|
||||
component = Auth0;
|
||||
break;
|
||||
case 'bitbucket':
|
||||
docs = 'https://developer.atlassian.com/bitbucket';
|
||||
break;
|
||||
case 'bitly':
|
||||
docs = 'https://dev.bitly.com/v4_documentation.html';
|
||||
break;
|
||||
case 'box':
|
||||
docs = 'https://developer.box.com/reference/';
|
||||
break;
|
||||
case 'discord':
|
||||
docs = 'https://discordapp.com/developers/docs/topics/oauth2';
|
||||
break;
|
||||
case 'dropbox':
|
||||
docs = 'https://www.dropbox.com/developers/documentation';
|
||||
break;
|
||||
case 'facebook':
|
||||
docs = 'https://developers.facebook.com/';
|
||||
break;
|
||||
case 'github':
|
||||
docs = 'https://developer.github.com';
|
||||
break;
|
||||
case 'gitlab':
|
||||
docs = 'https://docs.gitlab.com/ee/api/';
|
||||
break;
|
||||
case 'google':
|
||||
docs = 'https://support.google.com/googleapi/answer/6158849';
|
||||
break;
|
||||
case 'linkedin':
|
||||
docs = 'https://developer.linkedin.com/';
|
||||
break;
|
||||
case 'microsoft':
|
||||
docs = 'https://developer.microsoft.com/en-us/';
|
||||
component = Microsoft;
|
||||
break;
|
||||
case 'notion':
|
||||
docs = 'https://developers.notion.com/docs';
|
||||
break;
|
||||
case 'okta':
|
||||
docs = 'https://developer.okta.com';
|
||||
component = Okta;
|
||||
break;
|
||||
case 'paypal':
|
||||
docs = 'https://developer.paypal.com/docs/api/overview/';
|
||||
break;
|
||||
case 'paypalsandbox':
|
||||
icon = 'paypal';
|
||||
docs = 'https://developer.paypal.com/docs/api/overview/';
|
||||
break;
|
||||
case 'salesforce':
|
||||
docs = 'https://developer.salesforce.com/docs/';
|
||||
break;
|
||||
case 'slack':
|
||||
docs = 'https://api.slack.com/';
|
||||
break;
|
||||
case 'spotify':
|
||||
docs =
|
||||
'https://developer.spotify.com/documentation/general/guides/authorization-guide/';
|
||||
break;
|
||||
case 'stripe':
|
||||
docs = 'https://stripe.com/docs/api';
|
||||
break;
|
||||
case 'tradeshift':
|
||||
docs = 'https://developers.tradeshift.com/docs/api';
|
||||
break;
|
||||
case 'tradeshiftbox':
|
||||
icon = 'tradeshift';
|
||||
docs = 'https://developers.tradeshift.com/docs/api';
|
||||
break;
|
||||
case 'twitch':
|
||||
docs = 'https://dev.twitch.tv/docs/auth';
|
||||
break;
|
||||
case 'wordpress':
|
||||
docs = 'https://developer.wordpress.com/docs/oauth2/';
|
||||
break;
|
||||
case 'yahoo':
|
||||
docs = 'https://developer.yahoo.com/oauth2/guide/flows_authcode/';
|
||||
break;
|
||||
case 'yammer':
|
||||
docs = 'https://developer.yammer.com/docs/oauth-2';
|
||||
break;
|
||||
case 'yandex':
|
||||
docs = 'https://tech.yandex.com/oauth/';
|
||||
break;
|
||||
case 'zoom':
|
||||
docs = 'https://marketplace.zoom.us/docs/guides/auth/oauth/';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
...n,
|
||||
icon,
|
||||
docs,
|
||||
component
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
};
|
||||
|
||||
function createOAuthProviders() {
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
import { base } from '$app/paths';
|
||||
import { browser, dev } from '$app/environment';
|
||||
import { app } from '$lib/stores/app';
|
||||
import Notifications from '$lib/layout/notifications.svelte';
|
||||
import Loading from './loading.svelte';
|
||||
import { Progress, Notifications } from '$lib/layout';
|
||||
import { loading } from './store';
|
||||
import Loading from './loading.svelte';
|
||||
|
||||
if (browser) {
|
||||
window.VERCEL_ANALYTICS_ID = import.meta.env.VERCEL_ANALYTICS_ID?.toString() ?? false;
|
||||
@@ -95,6 +95,8 @@
|
||||
<Loading />
|
||||
{/if}
|
||||
|
||||
<Progress />
|
||||
|
||||
<style lang="scss" global>
|
||||
.tippy-box {
|
||||
--p-tooltip-text-color: var(--color-neutral-10);
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Console - Appwrite</title>
|
||||
</svelte:head>
|
||||
|
||||
<Shell
|
||||
showSideNavigation={$page.url.pathname !== '/console' &&
|
||||
!$page?.params.organization &&
|
||||
|
||||
@@ -5,6 +5,6 @@ import type { LayoutLoad } from './$types';
|
||||
export const load: LayoutLoad = async () => {
|
||||
return {
|
||||
header: Header,
|
||||
breadcrumb: Breadcrumbs
|
||||
breadcrumbs: Breadcrumbs
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,105 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { Empty, Pagination } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableCellHead,
|
||||
TableCell,
|
||||
TableCellText
|
||||
} from '$lib/elements/table';
|
||||
import { Container } from '$lib/layout';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import { Activity } from '$lib/layout';
|
||||
import type { PageData } from './$types';
|
||||
import { PAGE_LIMIT } from '$lib/constants';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
const getBrowser = (clientCode: string) => {
|
||||
return sdkForConsole.avatars.getBrowser(clientCode, 40, 40);
|
||||
};
|
||||
const path = '/console/account/activity';
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
{#if data.logs.total}
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableCellHead>Date</TableCellHead>
|
||||
<TableCellHead>Event</TableCellHead>
|
||||
<TableCellHead>Client</TableCellHead>
|
||||
<TableCellHead>Location</TableCellHead>
|
||||
<TableCellHead>IP</TableCellHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.logs.logs as log}
|
||||
<TableRow>
|
||||
<TableCellText title="Date">{toLocaleDateTime(log.time)}</TableCellText>
|
||||
<TableCellText title="Event">{log.event}</TableCellText>
|
||||
|
||||
<TableCell title="Client">
|
||||
{#if log.clientName}
|
||||
<div class="u-flex u-cross-center u-gap-12">
|
||||
<div class="avatar is-small">
|
||||
<img
|
||||
height="20"
|
||||
width="20"
|
||||
src={getBrowser(log.clientCode).toString()}
|
||||
alt={log.clientName} />
|
||||
</div>
|
||||
<p
|
||||
class="text u-trim"
|
||||
title={`${log.clientName} ${log.clientVersion} on ${log.osName} ${log.osVersion}`}>
|
||||
{log.clientName}
|
||||
{log.clientVersion}
|
||||
on {log.osName}
|
||||
{log.osVersion}
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="u-flex u-cross-center u-gap-12">
|
||||
<span class="avatar is-color-empty" />
|
||||
<p class="text u-trim">Unknown</p>
|
||||
</div>
|
||||
{/if}
|
||||
</TableCell>
|
||||
|
||||
<TableCellText title="Location">
|
||||
{#if log.countryCode !== '--'}
|
||||
{log.countryName}
|
||||
{:else}
|
||||
Unknown
|
||||
{/if}
|
||||
</TableCellText>
|
||||
<TableCellText title="IP">{log.ip}</TableCellText>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{:else}
|
||||
<Empty>
|
||||
<div class="u-flex u-flex-vertical u-cross-center">
|
||||
<div class="common-section">
|
||||
<p>No logs available</p>
|
||||
</div>
|
||||
<div class="common-section">
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetLogs"
|
||||
>Documentation</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Empty>
|
||||
{/if}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {data.logs.total}</p>
|
||||
<Pagination
|
||||
limit={PAGE_LIMIT}
|
||||
path="/console/account/activity"
|
||||
offset={data.offset}
|
||||
sum={data.logs.total} />
|
||||
</div>
|
||||
</Container>
|
||||
<Activity {path} logs={data.logs} offset={data.offset} />
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Copy, Tab, Tabs } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { Tab, Tabs } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { isTabSelected } from '$lib/helpers/load';
|
||||
import { Cover, CoverTitle } from '$lib/layout';
|
||||
@@ -44,12 +43,6 @@
|
||||
<CoverTitle>
|
||||
{$user.name}
|
||||
</CoverTitle>
|
||||
<Copy value={$user.$id}>
|
||||
<Pill button>
|
||||
<span class="icon-duplicate" aria-hidden="true" />
|
||||
Project ID
|
||||
</Pill>
|
||||
</Copy>
|
||||
<div class="u-margin-inline-start-auto">
|
||||
<Button secondary on:click={logout}>Logout</Button>
|
||||
</div>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
</svelte:fragment>
|
||||
</CardContainer>
|
||||
{:else}
|
||||
<Empty isButton single on:click={() => (addOrganization = true)}>
|
||||
<Empty single on:click={() => (addOrganization = true)}>
|
||||
<p>Create a new organization</p>
|
||||
</Empty>
|
||||
{/if}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetsessions">
|
||||
href="https://appwrite.io/docs/server/auth?sdk=nodejs-default#usersGetsessions">
|
||||
Documentation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</Pill>
|
||||
</div>
|
||||
{:else}
|
||||
<CustomId bind:show={showCustomId} name="organization" bind:id />
|
||||
<CustomId bind:show={showCustomId} name="Organization" bind:id />
|
||||
{/if}
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
<svelte:head>
|
||||
<title>Onboarding - Appwrite</title>
|
||||
</svelte:head>
|
||||
|
||||
<slot />
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
try {
|
||||
loading = true;
|
||||
const org = await createOrganization();
|
||||
const project = await sdkForConsole.projects.create(id ?? ID.unique(), name, org.$id);
|
||||
const project = await sdkForConsole.projects.create(
|
||||
id ?? ID.unique(),
|
||||
name,
|
||||
org.$id,
|
||||
'default'
|
||||
);
|
||||
await invalidate(Dependencies.ACCOUNT);
|
||||
goto(`/console/project-${project.$id}`);
|
||||
} catch ({ message }) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import Header from './header.svelte';
|
||||
import Breadcrumbs from './breadcrumbs.svelte';
|
||||
import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import type { LayoutLoad } from './$types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export const load: LayoutLoad = async ({ params, depends }) => {
|
||||
export const load: LayoutLoad = async ({ params, parent, depends }) => {
|
||||
await parent();
|
||||
depends(Dependencies.ORGANIZATION);
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { GridItem1, Heading, Empty, CardContainer, Pagination } from '$lib/components';
|
||||
@@ -8,7 +7,6 @@
|
||||
import CreateProject from '../createProject.svelte';
|
||||
import CreateOrganization from '../../createOrganization.svelte';
|
||||
import type { PageData } from './$types';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import { CARD_LIMIT } from '$lib/constants';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
@@ -17,10 +15,6 @@
|
||||
let showCreate = false;
|
||||
let addOrganization = false;
|
||||
|
||||
const projectCreated = async (event: CustomEvent<Models.Project>) => {
|
||||
await goto(`${base}/console/project-${event.detail.$id}`);
|
||||
};
|
||||
|
||||
const getPlatformInfo = (platform: string) => {
|
||||
let name: string, icon: string;
|
||||
if (platform.includes('flutter')) {
|
||||
@@ -44,6 +38,12 @@
|
||||
}
|
||||
return { name, icon };
|
||||
};
|
||||
|
||||
function filterPlatforms(platforms: { name: string; icon: string }[]) {
|
||||
return platforms.filter(
|
||||
(value, index, self) => index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
@@ -71,15 +71,14 @@
|
||||
<svelte:fragment slot="title">
|
||||
{project.name}
|
||||
</svelte:fragment>
|
||||
{@const platformList = project.platforms.map((platform) => platform.type)}
|
||||
{@const platforms = Array.from(new Set(platformList))}
|
||||
{@const platforms = filterPlatforms(
|
||||
project.platforms.map((platform) => getPlatformInfo(platform.type))
|
||||
)}
|
||||
{#each platforms as platform, i}
|
||||
{#if i < 3}
|
||||
<Pill>
|
||||
<span
|
||||
class={`icon-${getPlatformInfo(platform).icon}`}
|
||||
aria-hidden="true" />
|
||||
{getPlatformInfo(platform).name}
|
||||
<span class={`icon-${platform.icon}`} aria-hidden="true" />
|
||||
{platform.name}
|
||||
</Pill>
|
||||
{/if}
|
||||
{/each}
|
||||
@@ -96,7 +95,7 @@
|
||||
</svelte:fragment>
|
||||
</CardContainer>
|
||||
{:else}
|
||||
<Empty isButton single on:click={() => (showCreate = true)}>
|
||||
<Empty single on:click={() => (showCreate = true)}>
|
||||
<p>Create a new project</p>
|
||||
</Empty>
|
||||
{/if}
|
||||
@@ -112,7 +111,4 @@
|
||||
|
||||
<CreateOrganization bind:show={addOrganization} />
|
||||
|
||||
<CreateProject
|
||||
bind:show={showCreate}
|
||||
teamId={$page.params.organization}
|
||||
on:created={projectCreated} />
|
||||
<CreateProject bind:show={showCreate} teamId={$page.params.organization} />
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
url,
|
||||
name
|
||||
);
|
||||
invalidate(Dependencies.ORGANIZATION);
|
||||
invalidate(Dependencies.ACCOUNT);
|
||||
showCreate = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { Modal, CustomId } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { InputText, Button, FormList } from '$lib/elements/forms';
|
||||
@@ -15,20 +16,27 @@
|
||||
let name: string;
|
||||
let showCustomId = false;
|
||||
let error: string;
|
||||
let isCreating = false;
|
||||
|
||||
const create = async () => {
|
||||
try {
|
||||
const project = await sdkForConsole.projects.create(id ?? 'unique()', name, teamId);
|
||||
isCreating = true;
|
||||
const project = await sdkForConsole.projects.create(
|
||||
id ?? 'unique()',
|
||||
name,
|
||||
teamId,
|
||||
'default'
|
||||
);
|
||||
dispatch('created', project);
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${name} has been created`
|
||||
});
|
||||
id = name = null;
|
||||
showCustomId = false;
|
||||
show = false;
|
||||
await goto(`/console/project-${project.$id}`);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
} finally {
|
||||
isCreating = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -36,7 +44,13 @@
|
||||
<Modal {error} on:submit={create} size="big" bind:show>
|
||||
<svelte:fragment slot="header">Create Project</svelte:fragment>
|
||||
<FormList>
|
||||
<InputText id="name" label="Name" bind:value={name} required autofocus={true} />
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
bind:value={name}
|
||||
required
|
||||
autofocus={true}
|
||||
disabled={isCreating} />
|
||||
{#if !showCustomId}
|
||||
<div>
|
||||
<Pill button on:click={() => (showCustomId = !showCustomId)}>
|
||||
@@ -51,6 +65,6 @@
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button submit>Create</Button>
|
||||
<Button submit disabled={isCreating}>Create</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
let showDelete = false;
|
||||
|
||||
const url = `${$page.url.origin}/console/`;
|
||||
const deleted = () => invalidate(Dependencies.ORGANIZATION);
|
||||
const deleted = () => invalidate(Dependencies.ACCOUNT);
|
||||
const resend = async (member: Models.Membership) => {
|
||||
try {
|
||||
await sdkForConsole.teams.createMembership(
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
async function updateName() {
|
||||
try {
|
||||
await sdkForConsole.teams.update($organization.$id, name);
|
||||
invalidate(Dependencies.ORGANIZATION);
|
||||
await invalidate(Dependencies.ORGANIZATION);
|
||||
addNotification({
|
||||
message: 'Name has been updated',
|
||||
type: 'success'
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { UploadBox } from '$lib/components';
|
||||
import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { stats } from './store';
|
||||
|
||||
let unsubscribe: { (): void };
|
||||
|
||||
onMount(() => {
|
||||
unsubscribe = sdkForConsole.client.subscribe(['project', 'console'], (response) => {
|
||||
if (response.events.includes('stats.connections')) {
|
||||
for (const [projectId, value] of Object.entries(response.payload)) {
|
||||
stats.add(projectId, [new Date(response.timestamp).toISOString(), value]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svelte:head>
|
||||
<title>Auth - Appwrite</title>
|
||||
</svelte:head>
|
||||
|
||||
<slot />
|
||||
+10
-27
@@ -34,7 +34,7 @@
|
||||
let showCreate = false;
|
||||
const projectId = $page.params.project;
|
||||
const userCreated = async (event: CustomEvent<Models.User<Record<string, unknown>>>) => {
|
||||
await goto(`${base}/console/project-${projectId}/authentication/user-${event.detail.$id}`);
|
||||
await goto(`${base}/console/project-${projectId}/auth/user-${event.detail.$id}`);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<TableBody>
|
||||
{#each data.users.users as user}
|
||||
<TableRowLink
|
||||
href={`${base}/console/project-${projectId}/authentication/user-${user.$id}`}>
|
||||
href={`${base}/console/project-${projectId}/auth/user-${user.$id}`}>
|
||||
<TableCell title="Name">
|
||||
<div class="u-flex u-gap-12 u-cross-center">
|
||||
{#if user.email || user.phone}
|
||||
@@ -126,39 +126,22 @@
|
||||
offset={data.offset}
|
||||
limit={PAGE_LIMIT}
|
||||
sum={data.users.total}
|
||||
path={`/console/project-${projectId}/authentication`} />
|
||||
path={`/console/project-${projectId}/auth`} />
|
||||
</div>
|
||||
{:else if data.search}
|
||||
<EmptySearch>
|
||||
<div class="u-text-center">
|
||||
<b>Sorry, we couldn’t find ‘{data.search}’</b>
|
||||
<b>Sorry, we couldn't find '{data.search}'</b>
|
||||
<p>There are no users that match your search.</p>
|
||||
</div>
|
||||
<Button href={`/console/project-${projectId}/authentication`} secondary>
|
||||
Clear Search
|
||||
</Button>
|
||||
<Button href={`/console/project-${projectId}/auth`} secondary>Clear Search</Button>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty isButton single on:click={() => (showCreate = true)}>
|
||||
<div
|
||||
class="common-section"
|
||||
use:event={{
|
||||
name: 'console_users',
|
||||
action: 'click_create',
|
||||
parameters: {
|
||||
type: 'user'
|
||||
}
|
||||
}}>
|
||||
<div class="u-text-center common-section">
|
||||
<p>Create your first User to get started.</p>
|
||||
<p>Need a hand? Check out our documentation.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 common-section u-main-center">
|
||||
<Button external href="#/" text>Documentation</Button>
|
||||
<Button secondary>Create User</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Empty>
|
||||
<Empty
|
||||
single
|
||||
href="https://appwrite.io/docs/server/users"
|
||||
target="user"
|
||||
on:click={() => (showCreate = true)} />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
+19
-19
@@ -6,19 +6,20 @@
|
||||
import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { onMount } from 'svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let showModal = false;
|
||||
export let provider: Provider;
|
||||
|
||||
let id: string = null;
|
||||
let active = false;
|
||||
let appId: string = null;
|
||||
let enabled: boolean = null;
|
||||
let keyID: string = null;
|
||||
let teamID: string = null;
|
||||
let p8: string = null;
|
||||
|
||||
onMount(() => {
|
||||
id ??= provider.id;
|
||||
active ??= provider.active;
|
||||
appId ??= provider.appId;
|
||||
enabled ??= provider.enabled;
|
||||
if (provider.secret) ({ keyID, teamID, p8 } = JSON.parse(provider.secret));
|
||||
});
|
||||
|
||||
@@ -30,19 +31,18 @@
|
||||
await sdkForConsole.projects.updateOAuth2(
|
||||
projectId,
|
||||
provider.name.toLowerCase(),
|
||||
id,
|
||||
secret
|
||||
appId,
|
||||
secret,
|
||||
enabled
|
||||
);
|
||||
provider.active = active;
|
||||
provider.id = id;
|
||||
provider.secret = secret;
|
||||
showModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${provider.name} authentication has been ${
|
||||
provider.active ? 'enabled' : 'disabled'
|
||||
provider.enabled ? 'enabled' : 'disabled'
|
||||
}`
|
||||
});
|
||||
provider = null;
|
||||
invalidate(Dependencies.PROJECT);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
$: secret = keyID && teamID && p8 ? JSON.stringify({ keyID, teamID, p8 }) : provider.secret;
|
||||
</script>
|
||||
|
||||
<Modal {error} on:submit={update} size="big" bind:show={showModal}>
|
||||
<Modal {error} on:submit={update} size="big" show on:close>
|
||||
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
|
||||
<FormList>
|
||||
<p>
|
||||
@@ -61,13 +61,13 @@
|
||||
visit the docs.
|
||||
</a>
|
||||
</p>
|
||||
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
|
||||
<InputSwitch id="state" bind:value={enabled} label={enabled ? 'Enabled' : 'Disabled'} />
|
||||
<InputText
|
||||
id="bundleID"
|
||||
label="Bundle ID"
|
||||
autofocus={true}
|
||||
placeholder="com.company.appname"
|
||||
bind:value={id} />
|
||||
bind:value={appId} />
|
||||
<InputText id="keyID" label="Key ID" placeholder="SHAB13ROFN" bind:value={keyID} />
|
||||
<InputText id="teamID" label="Team ID" placeholder="ELA2CD3AED" bind:value={teamID} />
|
||||
<InputTextarea id="p8" label="P8 File" placeholder="" bind:value={p8} />
|
||||
@@ -83,12 +83,12 @@
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
|
||||
<Button secondary on:click={() => (provider = null)}>Cancel</Button>
|
||||
<Button
|
||||
disabled={(secret === provider.secret &&
|
||||
active === provider.active &&
|
||||
id === provider.id) ||
|
||||
!(id && keyID && teamID && p8)}
|
||||
enabled === provider.enabled &&
|
||||
appId === provider.appId) ||
|
||||
!(appId && keyID && teamID && p8)}
|
||||
submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+19
-19
@@ -6,19 +6,20 @@
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { onMount } from 'svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let showModal = false;
|
||||
export let provider: Provider;
|
||||
|
||||
let id: string = null;
|
||||
let active = false;
|
||||
let appId: string = null;
|
||||
let enabled: boolean = null;
|
||||
let clientSecret: string = null;
|
||||
let auth0Domain: string = null;
|
||||
let error: string;
|
||||
|
||||
onMount(() => {
|
||||
id ??= provider.id;
|
||||
active ??= provider.active;
|
||||
appId ??= provider.appId;
|
||||
enabled ??= provider.enabled;
|
||||
if (provider.secret) ({ clientSecret, auth0Domain } = JSON.parse(provider.secret));
|
||||
});
|
||||
|
||||
@@ -28,19 +29,18 @@
|
||||
await sdkForConsole.projects.updateOAuth2(
|
||||
projectId,
|
||||
provider.name.toLowerCase(),
|
||||
id,
|
||||
secret
|
||||
appId,
|
||||
secret,
|
||||
enabled
|
||||
);
|
||||
provider.active = active;
|
||||
provider.id = id;
|
||||
provider.secret = secret;
|
||||
showModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${provider.name} authentication has been ${
|
||||
provider.active ? 'enabled' : 'disabled'
|
||||
provider.enabled ? 'enabled' : 'disabled'
|
||||
}`
|
||||
});
|
||||
provider = null;
|
||||
invalidate(Dependencies.PROJECT);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
}
|
||||
@@ -52,7 +52,7 @@
|
||||
: provider.secret;
|
||||
</script>
|
||||
|
||||
<Modal {error} size="big" bind:show={showModal} on:submit={update}>
|
||||
<Modal {error} size="big" show on:submit={update} on:close>
|
||||
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
|
||||
<FormList>
|
||||
<p>
|
||||
@@ -61,13 +61,13 @@
|
||||
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
|
||||
>visit the docs.</a>
|
||||
</p>
|
||||
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
|
||||
<InputSwitch id="state" bind:value={enabled} label={enabled ? 'Enabled' : 'Disabled'} />
|
||||
<InputText
|
||||
id="clientID"
|
||||
label="Client ID"
|
||||
autofocus={true}
|
||||
placeholder="Enter ID"
|
||||
bind:value={id} />
|
||||
bind:value={appId} />
|
||||
<InputPassword
|
||||
id="secret"
|
||||
label="Client Secret"
|
||||
@@ -92,12 +92,12 @@
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
|
||||
<Button secondary on:click={() => (provider = null)}>Cancel</Button>
|
||||
<Button
|
||||
disabled={(secret === provider.secret &&
|
||||
active === provider.active &&
|
||||
id === provider.id) ||
|
||||
!(id && clientSecret && auth0Domain)}
|
||||
enabled === provider.enabled &&
|
||||
appId === provider.appId) ||
|
||||
!(appId && clientSecret && auth0Domain)}
|
||||
submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+21
-18
@@ -6,21 +6,23 @@
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { onMount } from 'svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let showModal = false;
|
||||
export let provider: Provider;
|
||||
|
||||
const projectId = $page.params.project;
|
||||
|
||||
let active = false;
|
||||
let id: string = null;
|
||||
let enabled: boolean = null;
|
||||
let appId: string = null;
|
||||
let secret: string = null;
|
||||
|
||||
onMount(() => {
|
||||
active ??= provider.active;
|
||||
id ??= provider.id;
|
||||
enabled ??= provider.enabled;
|
||||
appId ??= provider.appId;
|
||||
secret ??= provider.secret;
|
||||
});
|
||||
|
||||
let error: string;
|
||||
|
||||
const update = async () => {
|
||||
@@ -28,26 +30,25 @@
|
||||
await sdkForConsole.projects.updateOAuth2(
|
||||
projectId,
|
||||
provider.name.toLowerCase(),
|
||||
id,
|
||||
secret
|
||||
appId,
|
||||
secret,
|
||||
enabled
|
||||
);
|
||||
provider.active = active;
|
||||
provider.id = id;
|
||||
provider.secret = secret;
|
||||
showModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${provider.name} authentication has been ${
|
||||
provider.active ? 'enabled' : 'disabled'
|
||||
provider.enabled ? 'enabled' : 'disabled'
|
||||
}`
|
||||
});
|
||||
provider = null;
|
||||
invalidate(Dependencies.PROJECT);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<Modal {error} size="big" bind:show={showModal} on:submit={update}>
|
||||
<Modal {error} size="big" show on:submit={update} on:close>
|
||||
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
|
||||
<FormList>
|
||||
<p>
|
||||
@@ -56,13 +57,13 @@
|
||||
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
|
||||
>visit the docs.</a>
|
||||
</p>
|
||||
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
|
||||
<InputSwitch id="state" bind:value={enabled} label={enabled ? 'Enabled' : 'Disabled'} />
|
||||
<InputText
|
||||
id="appID"
|
||||
label="App ID"
|
||||
autofocus={true}
|
||||
placeholder="Enter ID"
|
||||
bind:value={id} />
|
||||
bind:value={appId} />
|
||||
<InputPassword
|
||||
id="secret"
|
||||
label="App Secret"
|
||||
@@ -82,11 +83,13 @@
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
|
||||
<Button secondary on:click={() => (provider = null)}>Cancel</Button>
|
||||
<Button
|
||||
disabled={!id ||
|
||||
disabled={!appId ||
|
||||
!secret ||
|
||||
(id === provider.id && secret === provider.secret && active === provider.active)}
|
||||
(appId === provider.appId &&
|
||||
secret === provider.secret &&
|
||||
enabled === provider.enabled)}
|
||||
submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+19
-20
@@ -6,19 +6,20 @@
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { onMount } from 'svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let showModal = false;
|
||||
export let provider: Provider;
|
||||
|
||||
let id: string = null;
|
||||
let active = false;
|
||||
let appId: string = null;
|
||||
let enabled: boolean = null;
|
||||
let clientSecret: string = null;
|
||||
let tenantID: string = null;
|
||||
let error: string;
|
||||
|
||||
onMount(() => {
|
||||
id ??= provider.id;
|
||||
active ??= provider.active;
|
||||
appId ??= provider.appId;
|
||||
enabled ??= provider.enabled;
|
||||
if (provider.secret) ({ clientSecret, tenantID } = JSON.parse(provider.secret));
|
||||
});
|
||||
|
||||
@@ -29,20 +30,18 @@
|
||||
await sdkForConsole.projects.updateOAuth2(
|
||||
projectId,
|
||||
provider.name.toLowerCase(),
|
||||
id,
|
||||
secret
|
||||
appId,
|
||||
secret,
|
||||
enabled
|
||||
);
|
||||
provider.active = active;
|
||||
provider.id = id;
|
||||
provider.secret = secret;
|
||||
|
||||
showModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${provider.name} authentication has been ${
|
||||
provider.active ? 'enabled' : 'disabled'
|
||||
provider.enabled ? 'enabled' : 'disabled'
|
||||
}`
|
||||
});
|
||||
provider = null;
|
||||
invalidate(Dependencies.PROJECT);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
}
|
||||
@@ -52,7 +51,7 @@
|
||||
clientSecret && tenantID ? JSON.stringify({ clientSecret, tenantID }) : provider.secret;
|
||||
</script>
|
||||
|
||||
<Modal {error} on:submit={update} size="big" bind:show={showModal}>
|
||||
<Modal {error} on:submit={update} size="big" show on:close>
|
||||
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
|
||||
<FormList>
|
||||
<p>
|
||||
@@ -62,13 +61,13 @@
|
||||
visit the docs.
|
||||
</a>
|
||||
</p>
|
||||
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
|
||||
<InputSwitch id="state" bind:value={enabled} label={enabled ? 'Enabled' : 'Disabled'} />
|
||||
<InputText
|
||||
id="appID"
|
||||
label="Application (client) ID"
|
||||
autofocus={true}
|
||||
placeholder="Enter ID"
|
||||
bind:value={id} />
|
||||
bind:value={appId} />
|
||||
<InputPassword
|
||||
id="secret"
|
||||
label="Client Secret"
|
||||
@@ -93,12 +92,12 @@
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
|
||||
<Button secondary on:click={() => (provider = null)}>Cancel</Button>
|
||||
<Button
|
||||
disabled={(secret === provider.secret &&
|
||||
active === provider.active &&
|
||||
id === provider.id) ||
|
||||
!(id && clientSecret && tenantID)}
|
||||
enabled === provider.enabled &&
|
||||
appId === provider.appId) ||
|
||||
!(appId && clientSecret && tenantID)}
|
||||
submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+17
-18
@@ -6,19 +6,20 @@
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { onMount } from 'svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let showModal = false;
|
||||
export let provider: Provider;
|
||||
|
||||
let id: string = null;
|
||||
let active = false;
|
||||
let appId: string = null;
|
||||
let enabled: boolean = null;
|
||||
let clientSecret: string = null;
|
||||
let oktaDomain: string = null;
|
||||
let authorizationServerId: string = null;
|
||||
|
||||
onMount(() => {
|
||||
id ??= provider.id;
|
||||
active ??= provider.active;
|
||||
appId ??= provider.appId;
|
||||
enabled ??= provider.enabled;
|
||||
if (provider.secret)
|
||||
({ clientSecret, oktaDomain, authorizationServerId } = JSON.parse(provider.secret));
|
||||
});
|
||||
@@ -32,19 +33,17 @@
|
||||
await sdkForConsole.projects.updateOAuth2(
|
||||
projectId,
|
||||
provider.name.toLowerCase(),
|
||||
id,
|
||||
appId,
|
||||
secret
|
||||
);
|
||||
provider.active = active;
|
||||
provider.id = id;
|
||||
provider.secret = secret;
|
||||
showModal = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${provider.name} authentication has been ${
|
||||
provider.active ? 'enabled' : 'disabled'
|
||||
provider.enabled ? 'enabled' : 'disabled'
|
||||
}`
|
||||
});
|
||||
provider = null;
|
||||
invalidate(Dependencies.PROJECT);
|
||||
} catch ({ message }) {
|
||||
error = message;
|
||||
}
|
||||
@@ -56,7 +55,7 @@
|
||||
: provider.secret;
|
||||
</script>
|
||||
|
||||
<Modal {error} on:submit={update} size="big" bind:show={showModal}>
|
||||
<Modal {error} on:submit={update} size="big" show on:close>
|
||||
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
|
||||
<FormList>
|
||||
<p>
|
||||
@@ -65,13 +64,13 @@
|
||||
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
|
||||
>visit the docs.</a>
|
||||
</p>
|
||||
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
|
||||
<InputSwitch id="state" bind:value={enabled} label={enabled ? 'Enabled' : 'Disabled'} />
|
||||
<InputText
|
||||
id="appID"
|
||||
label="Client ID"
|
||||
autofocus={true}
|
||||
placeholder="Enter ID"
|
||||
bind:value={id} />
|
||||
bind:value={appId} />
|
||||
<InputPassword
|
||||
id="secret"
|
||||
label="Client Secret"
|
||||
@@ -102,12 +101,12 @@
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
|
||||
<Button secondary on:click={() => (provider = null)}>Cancel</Button>
|
||||
<Button
|
||||
disabled={(secret === provider.secret &&
|
||||
active === provider.active &&
|
||||
id === provider.id) ||
|
||||
!(id && clientSecret && oktaDomain && authorizationServerId)}
|
||||
enabled === provider.enabled &&
|
||||
appId === provider.appId) ||
|
||||
!(appId && clientSecret && oktaDomain && authorizationServerId)}
|
||||
submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
title: $project?.name
|
||||
},
|
||||
{
|
||||
href: `/console/project-${$project?.$id}/authentication`,
|
||||
title: 'Authentication'
|
||||
href: `/console/project-${$project?.$id}/auth`,
|
||||
title: 'Auth'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
import { Cover, CoverTitle } from '$lib/layout';
|
||||
|
||||
const projectId = $page.params.project;
|
||||
const path = `/console/project-${projectId}/authentication`;
|
||||
const path = `/console/project-${projectId}/auth`;
|
||||
const tabs = [
|
||||
{
|
||||
href: path,
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
<Cover>
|
||||
<svelte:fragment slot="header">
|
||||
<CoverTitle>Authentication</CoverTitle>
|
||||
<CoverTitle>Auth</CoverTitle>
|
||||
</svelte:fragment>
|
||||
<Tabs>
|
||||
{#each tabs as tab}
|
||||
+10
-14
@@ -11,16 +11,14 @@
|
||||
import { event } from '$lib/actions/analytics';
|
||||
import type { Provider } from '$lib/stores/oauth-providers';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
const projectId = $page.params.project;
|
||||
let showModal = false;
|
||||
|
||||
onMount(async () => {
|
||||
$: {
|
||||
authMethods.load($project);
|
||||
OAuthProviders.load($project);
|
||||
});
|
||||
}
|
||||
|
||||
const authUpdate = async (box: AuthMethod) => {
|
||||
try {
|
||||
@@ -46,7 +44,7 @@
|
||||
{#if $authMethods && $OAuthProviders}
|
||||
<Container>
|
||||
<CardGrid>
|
||||
<Heading tag="h2" size="7">Authentication Methods</Heading>
|
||||
<Heading tag="h2" size="7">Auth Methods</Heading>
|
||||
<p>Enable the authentication methods you wish to use.</p>
|
||||
<svelte:fragment slot="aside">
|
||||
<form class="form">
|
||||
@@ -56,9 +54,7 @@
|
||||
label={box.label}
|
||||
id={box.method}
|
||||
bind:value={box.value}
|
||||
on:change={() => {
|
||||
authUpdate(box);
|
||||
}} />
|
||||
on:change={() => authUpdate(box)} />
|
||||
{/each}
|
||||
</ul>
|
||||
</form>
|
||||
@@ -67,12 +63,11 @@
|
||||
<section class="common-section">
|
||||
<h2 class="heading-level-6 common-section">OAuth2 Providers</h2>
|
||||
<ul class="grid-box common-section">
|
||||
{#each $OAuthProviders.providers as provider}
|
||||
{#each $OAuthProviders.providers.sort( (a, b) => (a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1) ) as provider}
|
||||
<button
|
||||
class="card u-flex u-flex-vertical u-cross-center"
|
||||
on:click={() => {
|
||||
selectedProvider = provider;
|
||||
showModal = true;
|
||||
}}
|
||||
use:event={{
|
||||
name: 'console_users',
|
||||
@@ -91,8 +86,8 @@
|
||||
</div>
|
||||
<p class="u-margin-block-start-8">{provider.name}</p>
|
||||
<div class="u-margin-block-start-24">
|
||||
<Pill success={provider.active}>
|
||||
{provider.active ? 'enabled' : 'disabled'}
|
||||
<Pill success={provider.enabled}>
|
||||
{provider.enabled ? 'enabled' : 'disabled'}
|
||||
</Pill>
|
||||
</div>
|
||||
</button>
|
||||
@@ -105,6 +100,7 @@
|
||||
{#if selectedProvider}
|
||||
<svelte:component
|
||||
this={selectedProvider.component}
|
||||
provider={selectedProvider}
|
||||
bind:showModal />
|
||||
bind:provider={selectedProvider}
|
||||
on:close={() => (selectedProvider = null)}
|
||||
showModal />
|
||||
{/if}
|
||||
+9
-28
@@ -27,9 +27,7 @@
|
||||
|
||||
const project = $page.params.project;
|
||||
const teamCreated = async (event: CustomEvent<Models.Team>) => {
|
||||
await goto(
|
||||
`${base}/console/project-${project}/authentication/teams/team-${event.detail.$id}`
|
||||
);
|
||||
await goto(`${base}/console/project-${project}/auth/teams/team-${event.detail.$id}`);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -58,7 +56,7 @@
|
||||
<TableBody>
|
||||
{#each data.teams.teams as team}
|
||||
<TableRowLink
|
||||
href={`${base}/console/project-${project}/authentication/teams/team-${team.$id}`}>
|
||||
href={`${base}/console/project-${project}/auth/teams/team-${team.$id}`}>
|
||||
<TableCell title="ID">
|
||||
<div class="u-flex u-gap-12">
|
||||
<AvatarInitials size={32} name={team.name} />
|
||||
@@ -77,7 +75,7 @@
|
||||
<p class="text">Total results: {data.teams.total}</p>
|
||||
<Pagination
|
||||
limit={PAGE_LIMIT}
|
||||
path={`/console/project-${$page.params.project}/authentication/teams`}
|
||||
path={`/console/project-${$page.params.project}/auth/teams`}
|
||||
offset={data.offset}
|
||||
sum={data.teams.total} />
|
||||
</div>
|
||||
@@ -87,33 +85,16 @@
|
||||
<b>Sorry, we couldn’t find ‘{data.search}’</b>
|
||||
<p>There are no teams that match your search.</p>
|
||||
</div>
|
||||
<Button
|
||||
secondary
|
||||
href={`/console/project-${$page.params.project}/authentication/teams`}>
|
||||
<Button secondary href={`/console/project-${$page.params.project}/auth/teams`}>
|
||||
Clear Search
|
||||
</Button>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty isButton single on:click={() => (showCreate = true)}>
|
||||
<div
|
||||
class="common-section"
|
||||
use:event={{
|
||||
name: 'console_users',
|
||||
action: 'click_create',
|
||||
parameters: {
|
||||
type: 'team'
|
||||
}
|
||||
}}>
|
||||
<div class="u-text-center common-section">
|
||||
<p>Create your first Team to get started.</p>
|
||||
<p>Need a hand? Check out our documentation.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 common-section u-main-center">
|
||||
<Button external href="#/" text>Documentation</Button>
|
||||
<Button secondary>Create team</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Empty>
|
||||
<Empty
|
||||
single
|
||||
on:click={() => (showCreate = true)}
|
||||
href="https://appwrite.io/docs/client/teams"
|
||||
target="team" />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ export const load: PageLoad = async ({ params, parent, url }) => {
|
||||
return {
|
||||
offset,
|
||||
search,
|
||||
page,
|
||||
teams: sdkForProject.teams.list(
|
||||
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')],
|
||||
search
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { page } from '$app/stores';
|
||||
import { Activity } from '$lib/layout';
|
||||
|
||||
export let data: PageData;
|
||||
const path = `/console/project-${$page.params.project}/auth/teams/team-${$page.params.team}/activity`;
|
||||
</script>
|
||||
|
||||
<Activity {path} logs={data.logs} offset={data.offset} />
|
||||
+3
-3
@@ -14,11 +14,11 @@
|
||||
title: $project?.name
|
||||
},
|
||||
{
|
||||
href: `/console/project-${$project?.$id}/authentication`,
|
||||
title: 'Authentication'
|
||||
href: `/console/project-${$project?.$id}/auth`,
|
||||
title: 'Auth'
|
||||
},
|
||||
{
|
||||
href: `/console/project-${$project?.$id}/authentication/teams-${$team?.$id}`,
|
||||
href: `/console/project-${$project?.$id}/auth/teams-${$team?.$id}`,
|
||||
title: $team?.name
|
||||
}
|
||||
];
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
let error: string;
|
||||
|
||||
const create = async () => {
|
||||
const url = `${$page.url.origin}/console/project-${$page.params.project}/authentication/teams-${$page.params.team}/members`;
|
||||
const url = `${$page.url.origin}/console/project-${$page.params.project}/auth/teams-${$page.params.team}/members`;
|
||||
|
||||
try {
|
||||
const user = await sdkForProject.teams.createMembership(
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
showDelete = false;
|
||||
dispatch('deleted');
|
||||
await goto(
|
||||
`${base}/console/project-${$page.params.project}/authentication/teams/team-${selectedMembership.teamId}/members`
|
||||
`${base}/console/project-${$page.params.project}/auth/teams/team-${selectedMembership.teamId}/members`
|
||||
);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
try {
|
||||
await sdkForProject.teams.delete(team.$id);
|
||||
showDelete = false;
|
||||
await goto(`${base}/console/project-${$page.params.project}/authentication/teams`);
|
||||
await goto(`${base}/console/project-${$page.params.project}/auth/teams`);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
|
||||
const projectId = $page.params.project;
|
||||
const teamId = $page.params.team;
|
||||
const path = `/console/project-${projectId}/authentication/teams/team-${teamId}`;
|
||||
const path = `/console/project-${projectId}/auth/teams/team-${teamId}`;
|
||||
const tabs = [
|
||||
{
|
||||
href: path,
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<Cover>
|
||||
<svelte:fragment slot="header">
|
||||
<CoverTitle href={`/console/project-${projectId}/authentication/teams`}>
|
||||
<CoverTitle href={`/console/project-${projectId}/auth/teams`}>
|
||||
{$team?.name}
|
||||
</CoverTitle>
|
||||
<Copy value={$team?.$id}>
|
||||
+9
-9
@@ -29,9 +29,7 @@
|
||||
const project = $page.params.project;
|
||||
|
||||
async function memberCreated(event: CustomEvent<Models.Membership>) {
|
||||
await goto(
|
||||
`${base}/console/project-${project}/authentication/teams-${event.detail.teamId}/members`
|
||||
);
|
||||
await goto(`${base}/console/project-${project}/auth/teams-${event.detail.teamId}/members`);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -53,7 +51,7 @@
|
||||
<TableBody>
|
||||
{#each data.memberships.memberships as membership}
|
||||
<TableRowLink
|
||||
href={`${base}/console/project-${project}/authentication/user-${membership.userId}`}>
|
||||
href={`${base}/console/project-${project}/auth/user-${membership.userId}`}>
|
||||
<TableCellText title="Name">
|
||||
<div class="u-flex u-gap-12">
|
||||
<AvatarInitials size={32} name={membership.userName} />
|
||||
@@ -83,7 +81,7 @@
|
||||
<p class="text">Total results: {data.memberships.total}</p>
|
||||
<Pagination
|
||||
limit={PAGE_LIMIT}
|
||||
path={`/console/project-${$page.params.project}/authentication/teams/team-${$page.params.team}/members`}
|
||||
path={`/console/project-${$page.params.project}/auth/teams/team-${$page.params.team}/members`}
|
||||
offset={data.offset}
|
||||
sum={data.memberships.total} />
|
||||
</div>
|
||||
@@ -95,13 +93,15 @@
|
||||
</div>
|
||||
<Button
|
||||
secondary
|
||||
href={`/console/project-${$page.params.project}/authentication/teams/team-${$page.params.team}/members`}
|
||||
href={`/console/project-${$page.params.project}/auth/teams/team-${$page.params.team}/members`}
|
||||
>Clear Search</Button>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty isButton single on:click={() => (showCreate = true)}>
|
||||
<p>Add your first member to get started</p>
|
||||
</Empty>
|
||||
<Empty
|
||||
single
|
||||
href="https://appwrite.io/docs/client/teams?sdk=web-default#teamsCreateMembership"
|
||||
target="membership"
|
||||
on:click={() => (showCreate = true)} />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
<Usage
|
||||
title="Users"
|
||||
path={`/console/project-${$page.params.project}/authentication/usage`}
|
||||
path={`/console/project-${$page.params.project}/auth/usage`}
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
+9
-4
@@ -28,8 +28,10 @@
|
||||
|
||||
$: if (prefs) {
|
||||
if (JSON.stringify(prefs) !== JSON.stringify(Object.entries($user.prefs))) {
|
||||
if (prefs[prefs.length - 1][0] && prefs[prefs.length - 1][1]) {
|
||||
if (!!prefs[prefs.length - 1][0] && !!prefs[prefs.length - 1][1]) {
|
||||
arePrefsDisabled = false;
|
||||
} else {
|
||||
arePrefsDisabled = true;
|
||||
}
|
||||
} else {
|
||||
arePrefsDisabled = true;
|
||||
@@ -264,14 +266,16 @@
|
||||
</DropListItem>
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
{:else if !$user.phone}
|
||||
{:else if $user.email}
|
||||
<Button secondary on:click={() => updateVerificationEmail()}>
|
||||
{$user.emailVerification ? 'Unverify' : 'Verify'} account
|
||||
</Button>
|
||||
{:else if !$user.email}
|
||||
{:else if $user.phone}
|
||||
test
|
||||
<Button secondary on:click={() => updateVerificationPhone()}>
|
||||
{$user.phoneVerification ? 'Unverify' : 'Verify'} account
|
||||
</Button>{/if}
|
||||
</Button>
|
||||
{/if}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
@@ -420,6 +424,7 @@
|
||||
{/if}
|
||||
</ul>
|
||||
<Button
|
||||
noMargin
|
||||
text
|
||||
on:click={() => {
|
||||
if (prefs[prefs.length - 1][0] && prefs[prefs.length - 1][1]) {
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { page } from '$app/stores';
|
||||
import { Activity } from '$lib/layout';
|
||||
|
||||
export let data: PageData;
|
||||
const path = `/console/project-${$page.params.project}/auth/user-${$page.params.user}/activity`;
|
||||
</script>
|
||||
|
||||
<Activity {path} logs={data.logs} offset={data.offset} />
|
||||
+4
-1
@@ -11,6 +11,9 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
|
||||
return {
|
||||
offset,
|
||||
logs: await sdkForProject.account.listLogs([Query.limit(PAGE_LIMIT), Query.offset(offset)])
|
||||
logs: await sdkForProject.users.listLogs(params.user, [
|
||||
Query.limit(PAGE_LIMIT),
|
||||
Query.offset(offset)
|
||||
])
|
||||
};
|
||||
};
|
||||
+3
-3
@@ -14,11 +14,11 @@
|
||||
title: $project?.name
|
||||
},
|
||||
{
|
||||
href: `/console/project-${$project?.$id}/authentication`,
|
||||
title: 'Authentication'
|
||||
href: `/console/project-${$project?.$id}/auth`,
|
||||
title: 'Auth'
|
||||
},
|
||||
{
|
||||
href: `/console/project-${$project?.$id}/authentication/user-${$user?.$id}`,
|
||||
href: `/console/project-${$project?.$id}/auth/user-${$user?.$id}`,
|
||||
title: $user?.name
|
||||
}
|
||||
];
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
message: `All memberships have been deleted`
|
||||
});
|
||||
await goto(
|
||||
`${base}/console/project-${$page.params.project}/authentication/${$user.$id}/membeships`
|
||||
`${base}/console/project-${$page.params.project}/auth/${$user.$id}/membeships`
|
||||
);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user