diff --git a/package-lock.json b/package-lock.json index c34a6fd60..88b774b26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.1.0", "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", @@ -72,7 +73,6 @@ "react-quill": "^2.0.0", "react-select": "^5.3.2", "react-simple-code-editor": "^0.11.0", - "react-tooltip": "^5.7.4", "react-use": "^17.4.0", "redis": "^4.4.0", "styled-components": "^6.1.8", @@ -6302,6 +6302,418 @@ } } }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.0.tgz", + "integrity": "sha512-2wdgj6eKNVoFNFtYv2xwkzhIJPlJ5L2aV0eKTZHi5dUVrGy+MhgoV8IyyeFpkZQrwwFzbFlnWl1bwyjVBCNapQ==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.0.tgz", + "integrity": "sha512-0tXZ5O6qAVvuN9SWP0X+zadHf9hzHiMf/vxOU+kXO+fbtS8lS57MXa6EmikDxk9s/Bmkk80+dcxgbvisIyeqxg==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + }, + "node_modules/@radix-ui/react-popover/node_modules/react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz", @@ -31118,19 +31530,6 @@ } } }, - "node_modules/react-tooltip": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.15.0.tgz", - "integrity": "sha512-OiH870zteP4T5B/J7cUGz37aY8C0Cny/i1qcLXevL+wZlW09mfjdcQ6FKP9OMMsRlszRwieOqAPT9l8rWz+BtA==", - "dependencies": { - "@floating-ui/dom": "^1.0.0", - "classnames": "^2.3.0" - }, - "peerDependencies": { - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -41990,6 +42389,202 @@ "react-remove-scroll": "2.5.5" } }, + "@radix-ui/react-popover": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.0.tgz", + "integrity": "sha512-2wdgj6eKNVoFNFtYv2xwkzhIJPlJ5L2aV0eKTZHi5dUVrGy+MhgoV8IyyeFpkZQrwwFzbFlnWl1bwyjVBCNapQ==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "dependencies": { + "@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "requires": {} + }, + "@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "requires": {} + }, + "@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + } + }, + "@radix-ui/react-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "requires": {} + }, + "@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "requires": { + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "requires": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + } + }, + "@radix-ui/react-portal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.0.tgz", + "integrity": "sha512-0tXZ5O6qAVvuN9SWP0X+zadHf9hzHiMf/vxOU+kXO+fbtS8lS57MXa6EmikDxk9s/Bmkk80+dcxgbvisIyeqxg==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "requires": { + "@radix-ui/react-slot": "1.1.0" + } + }, + "@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0" + } + }, + "@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "requires": {} + }, + "@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "requires": { + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "requires": { + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "requires": {} + }, + "@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "requires": { + "@radix-ui/rect": "1.1.0" + } + }, + "@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "requires": { + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + }, + "react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "requires": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + } + } + } + }, "@radix-ui/react-popper": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz", @@ -60321,15 +60916,6 @@ "tslib": "^2.0.0" } }, - "react-tooltip": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.15.0.tgz", - "integrity": "sha512-OiH870zteP4T5B/J7cUGz37aY8C0Cny/i1qcLXevL+wZlW09mfjdcQ6FKP9OMMsRlszRwieOqAPT9l8rWz+BtA==", - "requires": { - "@floating-ui/dom": "^1.0.0", - "classnames": "^2.3.0" - } - }, "react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/package.json b/package.json index 117b60815..904f89590 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.1.0", "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", @@ -97,7 +98,6 @@ "react-quill": "^2.0.0", "react-select": "^5.3.2", "react-simple-code-editor": "^0.11.0", - "react-tooltip": "^5.7.4", "react-use": "^17.4.0", "redis": "^4.4.0", "styled-components": "^6.1.8", diff --git a/src/__tests__/_/setupGlobals.ts b/src/__tests__/_/setupGlobals.ts index 05cccad34..8f8aff59a 100644 --- a/src/__tests__/_/setupGlobals.ts +++ b/src/__tests__/_/setupGlobals.ts @@ -16,3 +16,14 @@ Object.defineProperty(window, "matchMedia", { }); export {}; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const scrollIntoViewMock = jest.fn(); +window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; diff --git a/src/__tests__/account/logout.spec.tsx b/src/__tests__/account/logout.spec.tsx index d0f5e68fc..efab03982 100644 --- a/src/__tests__/account/logout.spec.tsx +++ b/src/__tests__/account/logout.spec.tsx @@ -29,7 +29,7 @@ describe("pages/account/logout", () => { ); await userEvent.click( - await screen.findByRole("button", { name: "Log Out" }) + await screen.findByRole("option", { name: "Log Out" }) ); await waitFor(() => { diff --git a/src/components/app/button/soft.tsx b/src/components/app/button/soft.tsx index e9650b220..feae1d4ac 100644 --- a/src/components/app/button/soft.tsx +++ b/src/components/app/button/soft.tsx @@ -34,7 +34,9 @@ export function SoftButton({ ) : (
- {labelString} + + {labelString} +
); diff --git a/src/components/app/button/types.d.ts b/src/components/app/button/types.d.ts index f19e089c9..e92c3018f 100644 --- a/src/components/app/button/types.d.ts +++ b/src/components/app/button/types.d.ts @@ -23,4 +23,6 @@ export interface IGroupActionButton extends IActionButton { export interface IMenuActionItem extends IGroupActionButton { subtle?: boolean; destructive?: boolean; + active?: boolean; + secondaryAction?: () => void; } diff --git a/src/components/app/content-layout/index.tsx b/src/components/app/content-layout/index.tsx index 2764097c0..aeeb64ba1 100644 --- a/src/components/app/content-layout/index.tsx +++ b/src/components/app/content-layout/index.tsx @@ -1,20 +1,9 @@ import { ReactElement, ReactNode } from "react"; -import styled from "styled-components"; -import { BREAKPOINTS } from "@/frontend/design-system/constants"; interface IProps { children: ReactNode; } -export const GridRoot = styled.div` - display: grid; - grid-gap: 16px; - grid-template-columns: 2fr 8fr; - @media (max-width: ${BREAKPOINTS.md}) { - grid-template-columns: 1fr; - } -`; - type TContentLayout = ((params: IProps) => ReactElement) & { Left: (params: IProps) => ReactElement; Right: (params: IProps) => ReactElement; @@ -23,16 +12,20 @@ type TContentLayout = ((params: IProps) => ReactElement) & { // eslint-disable-next-line react/function-component-definition export const ContentLayout: TContentLayout = ({ children }: IProps) => { - return {children}; + return ( +
+ {children} +
+ ); }; ContentLayout.Left = function SectionLeft({ children }: IProps) { - return
{children}
; + return
{children}
; }; ContentLayout.Right = function SectionRight({ children }: IProps) { return ( -
+
{children}
); diff --git a/src/components/app/drop-drop-menu/index.tsx b/src/components/app/drop-drop-menu/index.tsx index cc0811d70..11df3435b 100644 --- a/src/components/app/drop-drop-menu/index.tsx +++ b/src/components/app/drop-drop-menu/index.tsx @@ -1,6 +1,5 @@ import { useState, useEffect, useMemo } from "react"; import { ChevronDown, MoreVertical } from "react-feather"; - import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -11,12 +10,14 @@ import { useToggle } from "@/frontend/hooks/state/useToggleState"; import { MenuSection } from "@/components/app/menu-section"; import { IMenuActionItem } from "../button/types"; import { SoftButton } from "../button/soft"; +import { cn } from "@/lib/utils"; export interface IProps { menuItems: IMenuActionItem[]; ariaLabel: string; disabled?: boolean; ellipsis?: true; + contentClassName?: string; className?: string; } @@ -24,18 +25,28 @@ export function DropDownMenu({ menuItems: menuItems$1, ellipsis, ariaLabel, + contentClassName, className, }: IProps) { - const menuItems = useMemo(() => { - return [...menuItems$1].sort((a, b) => { - return (a.order || 0) - (b.order || 0); - }); - }, [menuItems$1]); - const [currentMenuItem, setCurrentMenuItem] = useState( - menuItems?.[0] + menuItems$1[0] ); + const menuItems: IMenuActionItem[] = useMemo(() => { + return [...menuItems$1] + .sort((a, b) => { + return (a.order || 0) - (b.order || 0); + }) + .map((menuItem) => { + return { + ...menuItem, + secondaryAction: () => { + setCurrentMenuItem(menuItem); + }, + }; + }); + }, [menuItems$1]); + useEffect(() => { setCurrentMenuItem(menuItems[0]); }, [JSON.stringify(menuItems)]); @@ -48,12 +59,6 @@ export function DropDownMenu({ return ; } - // TODO - // const onMenuItemClick = (menuIndex: number) => { - // const menuItem = menuItems[menuIndex]; - // setCurrentMenuItem(menuItem); - // }; - const { isOn: isOpen, toggle } = useToggle(false); return ( @@ -81,8 +86,11 @@ export function DropDownMenu({ )} - - + +
diff --git a/src/components/app/form/input/Stories.tsx b/src/components/app/form/input/Stories.tsx index ba434e950..2dea3dded 100644 --- a/src/components/app/form/input/Stories.tsx +++ b/src/components/app/form/input/Stories.tsx @@ -9,7 +9,6 @@ import { TestProviders } from "__tests__/_/Provider"; import { FormInput } from "./text"; import { FormNumberInput } from "./number"; import { FormRichTextArea } from "../../../../frontend/design-system/components/Form/RichText"; -import { FormDateInput } from "../../../../frontend/design-system/components/Form/Date"; import { FormTextArea } from "./textarea"; import { FormMultiSelect, @@ -24,6 +23,7 @@ import { DELETE_BUTTON_PROPS } from "../../button/constants"; import { FormPasswordInput } from "./password"; import { FormButton } from "../../button/form"; import { ActionButtons } from "../../button/action"; +import { FormDateInput } from "./date"; function DemoForm() { return ( diff --git a/src/components/app/form/input/date.tsx b/src/components/app/form/input/date.tsx new file mode 100644 index 000000000..5e774acbc --- /dev/null +++ b/src/components/app/form/input/date.tsx @@ -0,0 +1,138 @@ +import { FieldMetaState } from "react-final-form"; +import * as React from "react"; +import { format } from "date-fns"; +import { Calendar as CalendarIcon } from "react-feather"; +import { Trans, msg } from "@lingui/macro"; +import { + LabelAndError, + generateClassNames, + generateFormArias, +} from "@/components/app/form/input/label-and-error"; +import { ISharedFormInput } from "@/components/app/form/input/types"; +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { SoftButton } from "@/components/app/button/soft"; +import { useToggle } from "@/frontend/hooks/state/useToggleState"; + +interface IFormDateInput extends ISharedFormInput { + minDate?: Date; + maxDate?: Date; +} + +interface IProps { + minDate?: Date; + maxDate?: Date; + onChange: (value: Date | null) => void; + value: Date; + id?: string; + disabled?: boolean; + className?: string; + meta?: FieldMetaState; +} + +export const dateWithoutTimezone = (date: Date) => { + const tzoffset = date.getTimezoneOffset() * 60000; // offset in milliseconds + const withoutTimezone = new Date(date.valueOf() - tzoffset) + .toISOString() + .slice(0, -1); + return new Date(withoutTimezone); +}; + +export function ControlledFormDateInput({ + minDate, + maxDate, + onChange, + value, + id, + disabled, + className, + meta, +}: IProps) { + const isOpen = useToggle(); + + const onChangeRemoveTimeZone = (inputValue: Date | null) => { + onChange(dateWithoutTimezone(inputValue)); + }; + + return ( + + + + + + onChange(null)} + label={msg`Clear`} + className="w-full mt-3" + size="sm" + disabled={!value} + /> + } + /> + + + ); +} +// TODO fix date +export function FormDateInput(formInput: IFormDateInput) { + const { input, disabled, meta, minDate, maxDate } = formInput; + let { value } = input; + if (value && typeof value === "string") { + value = new Date(value); + input.onChange(value); + } + return ( + + + + ); +} diff --git a/src/components/app/form/schema/_RenderFormInput.tsx b/src/components/app/form/schema/_RenderFormInput.tsx index ec7569cff..8bd45eee0 100644 --- a/src/components/app/form/schema/_RenderFormInput.tsx +++ b/src/components/app/form/schema/_RenderFormInput.tsx @@ -1,5 +1,4 @@ import { FormSelect } from "frontend/design-system/components/Form/Select"; -import { FormDateInput } from "frontend/design-system/components/Form/Date"; import { AsyncFormSelect } from "frontend/design-system/components/Form/Select/Async"; import { FormCodeEditor } from "frontend/design-system/components/Form/CodeEditor"; import { FormFileInput } from "frontend/design-system/components/Form/File"; @@ -13,6 +12,7 @@ import { FormSelectButton } from "../input/select-button"; import { FormPasswordInput } from "../input/password"; import { FormTextArea } from "../input/textarea"; import { FormSwitch } from "../input/switch"; +import { FormDateInput } from "../input/date"; export function RenderFormInput(props: IRenderFormInputProps) { const { diff --git a/src/components/app/form/schema/form-grid.tsx b/src/components/app/form/schema/form-grid.tsx index a1c71fb21..5237b44e1 100644 --- a/src/components/app/form/schema/form-grid.tsx +++ b/src/components/app/form/schema/form-grid.tsx @@ -1,14 +1,8 @@ -import { gridItem, gridRoot } from "frontend/design-system/constants/grid"; +import { gridItem } from "frontend/design-system/constants/grid"; import { ReactNode } from "react"; import { GridSpanSizes } from "shared/types/ui"; import styled from "styled-components"; -const Root = styled.div` - ${gridRoot} - grid-auto-rows: auto; - align-items: center; -`; - // TOOD fix const Container = styled.div` // container-type: inline-size; @@ -17,7 +11,7 @@ const Container = styled.div` export const FormGrid = { Root: ({ children }: { children: ReactNode }) => ( - {children} +
{children}
), Item: styled.div<{ diff --git a/src/components/app/menu-section.tsx b/src/components/app/menu-section.tsx index 78f5b17fa..52718696d 100644 --- a/src/components/app/menu-section.tsx +++ b/src/components/app/menu-section.tsx @@ -2,6 +2,7 @@ import { useLingui } from "@lingui/react"; import Link from "next/link"; import { Loader } from "react-feather"; import { VariantProps } from "class-variance-authority"; +import { useRouter } from "next/router"; import { Card } from "@/components/ui/card"; import { CommandItem, Command, CommandList } from "@/components/ui/command"; import { cn } from "@/lib/utils"; @@ -12,16 +13,14 @@ import { SystemIcon } from "./system-icons"; export interface IProps { menuItems: IMenuActionItem[]; - currentMenuItem?: string; size?: VariantProps["size"]; } -export function MenuSection({ - menuItems, - currentMenuItem, - size = "lg", -}: IProps) { +export function MenuSection({ menuItems, size = "lg" }: IProps) { const { _ } = useLingui(); + const router = useRouter(); + + const currentPath = router.asPath.split("?")[0]; const confirmAlert = useConfirmAlert(); @@ -41,7 +40,9 @@ export function MenuSection({ ({ label, action, + active, systemIcon, + secondaryAction, subtle, id, variant = "ghost", @@ -50,9 +51,9 @@ export function MenuSection({ isMakingRequest, shouldConfirmAlert, }) => { - const active = ( - typeof action === "string" ? action : "" - ).includes(currentMenuItem); + const isActive = + active || + (typeof action === "string" ? action : "") === currentPath; const content = ( <> @@ -61,7 +62,7 @@ export function MenuSection({ ) : ( { + secondaryAction?.(); if (shouldConfirmAlert) { return confirmAlert({ title: shouldConfirmAlert, diff --git a/src/components/app/system-icons.tsx b/src/components/app/system-icons.tsx index 8a5400b28..e9c688035 100644 --- a/src/components/app/system-icons.tsx +++ b/src/components/app/system-icons.tsx @@ -14,6 +14,10 @@ export function SystemIcon({ icon, label, strokeWidth, className }: IProps) { return null; } + if (icon === "none") { + return null; + } + const iconSvg = systemIconToSVG(icon, strokeWidth); return ( {new Date(filterValue?.value || "").toString() !== "Invalid Date" ? ( <> + {/* TODO date not changing */} { setFilter({ diff --git a/src/components/app/table/filters/_FilterWrapper.tsx b/src/components/app/table/filters/_FilterWrapper.tsx index 7f697010b..4e31b0de9 100644 --- a/src/components/app/table/filters/_FilterWrapper.tsx +++ b/src/components/app/table/filters/_FilterWrapper.tsx @@ -40,36 +40,38 @@ export function FilterWrapper({ const { systemIcon, label: filterLabel } = FILTER_TYPE_CONFIG[filterType]; return ( - - e.stopPropagation()}> + + + + } + > +
+
{children}
+ { + clearFilter(undefined); + }} + size="sm" + systemIcon="Close" + label={msg`Reset`} />
- } - > -
-
{children}
- { - clearFilter(undefined); - }} - size="sm" - systemIcon="Close" - label={msg`Reset`} - /> -
-
+
+ ); } diff --git a/src/components/app/table/filters/index.tsx b/src/components/app/table/filters/index.tsx index ababed3ea..42a4b8bc0 100644 --- a/src/components/app/table/filters/index.tsx +++ b/src/components/app/table/filters/index.tsx @@ -69,12 +69,14 @@ export function TableFilter({ columnLabel={view} filterType={type._type} > - {operators.length > 1 && ( - + {operators.length > 0 && ( +
+ +
)} ; -function Calendar({ - className, - classNames, - showOutsideDays = true, - ...props -}: CalendarProps) { +function Calendar({ className, classNames, ...props }: CalendarProps) { return ( .day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" : "[&:has([aria-selected])]:rounded-md" ), day: cn( buttonVariants({ variant: "ghost" }), - "h-8 w-8 p-0 font-normal aria-selected:opacity-100" + "h-8 w-8 p-0 font-normal hover:bg-primary-shade-light hover:text-primary hover:shadow aria-selected:opacity-100" ), day_range_start: "day-range-start", day_range_end: "day-range-end", day_selected: - "bg-primary text-primary-text hover:bg-primary hover:text-primary-text focus:bg-primary focus:text-primary", - day_today: "bg-primary text-primary-text", + "bg-primary text-primary-text hover:bg-primary hover:text-primary-text focus:bg-primary focus:text-primary-text", + day_today: "shadow-lg bg-hover", day_outside: - "day-outside text-muted opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted aria-selected:opacity-30", + "day-outside text-muted opacity-50 aria-selected:bg-primary/50 aria-selected:text-muted aria-selected:opacity-30", day_disabled: "text-muted opacity-50", day_range_middle: "aria-selected:bg-primary aria-selected:text-primary-text", @@ -69,47 +65,3 @@ function Calendar({ Calendar.displayName = "Calendar"; export { Calendar }; - -// "use client" - -// import * as React from "react" -// import { format } from "date-fns" -// import { Calendar as CalendarIcon } from "lucide-react" - -// import { cn } from "@/lib/utils" -// import { Button } from "@/components/ui/button" -// import { Calendar } from "@/components/ui/calendar" -// import { -// Popover, -// PopoverContent, -// PopoverTrigger, -// } from "@/components/ui/popover" - -// export function DatePickerDemo() { -// const [date, setDate] = React.useState() - -// return ( -// -// -// -// -// -// -// -// -// ) -// } diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx new file mode 100644 index 000000000..a1ca4e817 --- /dev/null +++ b/src/components/ui/popover.tsx @@ -0,0 +1,32 @@ +/* eslint-disable react/prop-types */ +import * as React from "react"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; + +import { cn } from "@/lib/utils"; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverAnchor = PopoverPrimitive.Anchor; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }; diff --git a/src/frontend/design-system/components/Form/CodeEditor/index.tsx b/src/frontend/design-system/components/Form/CodeEditor/index.tsx index 6ad8bd511..5373b7dce 100644 --- a/src/frontend/design-system/components/Form/CodeEditor/index.tsx +++ b/src/frontend/design-system/components/Form/CodeEditor/index.tsx @@ -13,14 +13,13 @@ import { generateClassNames, } from "@/components/app/form/input/label-and-error"; import { PrismTokenStyles } from "@/components/app/render-code/styles"; +import { cn } from "@/lib/utils"; interface IFormCodeEditor extends ISharedFormInput { language?: "javascript"; } const Wrapper = styled.div` - border: 1px solid ${USE_ROOT_COLOR("border-color")}; - &.invalid { border-color: ${SYSTEM_COLORS.danger} !important; } @@ -57,7 +56,13 @@ export function FormCodeEditor(formInput: IFormCodeEditor) { return ( - + void; - value: Date; - id?: string; - isClearable?: boolean; - disabled?: boolean; - className?: string; - meta?: FieldMetaState; -} - -export function ControlledFormDateInput({ - minDate, - maxDate, - onChange, - value, - isClearable, - id, - disabled, - className, - meta, -}: IProps) { - return ( - - { - onChange(value$1); - }} - {...generateFormArias(meta)} - showTwoColumnMonthYearPicker - isClearable={isClearable} - selected={value} - id={id} - minDate={minDate} - maxDate={maxDate} - className={className} - disabled={disabled} - /> - - ); -} - -export function FormDateInput(formInput: IFormDateInput) { - const { input, disabled, meta, required, minDate, maxDate } = formInput; - let { value } = input; - if (value && typeof value === "string") { - value = new Date(value); - input.onChange(value); - } - return ( - - { - input.onChange(value$1); - }} - isClearable={!required} - value={value} - id={input.name} - minDate={minDate} - maxDate={maxDate} - meta={meta} - disabled={disabled} - /> - - ); -} diff --git a/src/frontend/design-system/components/IntermediateCheckBox/index.tsx b/src/frontend/design-system/components/IntermediateCheckBox/index.tsx index 1559843fb..96271ee18 100644 --- a/src/frontend/design-system/components/IntermediateCheckBox/index.tsx +++ b/src/frontend/design-system/components/IntermediateCheckBox/index.tsx @@ -1,28 +1,10 @@ -import styled from "styled-components"; - import { CheckSquare, Icon as IconType, MinusSquare, Square, } from "react-feather"; -import { USE_ROOT_COLOR } from "frontend/design-system/theme/root"; - -const IconWrapper = styled.span<{ $disabled?: boolean }>` - align-self: center; - width: 16px; - height: 16px; - border-radius: 2px; - cursor: ${(props) => (props.$disabled ? "not-allowed" : "pointer")}; - color: ${(props) => - props.$disabled - ? USE_ROOT_COLOR("muted-text") - : USE_ROOT_COLOR("primary-color")}; -`; - -const Icon = styled.i` - height: 18px; -`; +import { cn } from "@/lib/utils"; type CheckboxState = "checked" | "unchecked" | "partial"; @@ -35,11 +17,11 @@ export interface IProps { const IconPerState: Record< IProps["state"], - { IconCmp: IconType; label: boolean | "mixed" } + { IconCmp: IconType; ariaChecked: boolean | "mixed" } > = { - checked: { IconCmp: CheckSquare, label: true }, - partial: { IconCmp: MinusSquare, label: "mixed" }, - unchecked: { IconCmp: Square, label: false }, + checked: { IconCmp: CheckSquare, ariaChecked: true }, + partial: { IconCmp: MinusSquare, ariaChecked: "mixed" }, + unchecked: { IconCmp: Square, ariaChecked: false }, }; export function IntermediateCheckBox({ @@ -48,20 +30,26 @@ export function IntermediateCheckBox({ disabled, label, }: IProps) { + const { IconCmp, ariaChecked } = IconPerState[state]; return ( - { e.stopPropagation(); onClick(state); }} > - - + +
); } diff --git a/src/frontend/design-system/constants/grid.ts b/src/frontend/design-system/constants/grid.ts index 164c1a652..9505f9d97 100644 --- a/src/frontend/design-system/constants/grid.ts +++ b/src/frontend/design-system/constants/grid.ts @@ -16,15 +16,6 @@ export const mapToUnitOptions = (values: number[]) => { export const gridHeightToPx = (unit: GridHeightSizes) => +unit * 100; -export const gridRoot = css` - display: grid; - column-gap: 16px; - grid-template-columns: repeat(12, 1fr); - @container (width < ${BREAKPOINTS.md}) { - grid-template-columns: 1fr; - } -`; - export const gridItem = css<{ $span: GridSpanSizes; }>` diff --git a/src/frontend/views/Dashboard/List/_BaseDashboard.tsx b/src/frontend/views/Dashboard/List/_BaseDashboard.tsx index 0f9b0b1ea..6820ea43d 100644 --- a/src/frontend/views/Dashboard/List/_BaseDashboard.tsx +++ b/src/frontend/views/Dashboard/List/_BaseDashboard.tsx @@ -7,14 +7,9 @@ import { useDomainMessages } from "frontend/lib/crud-config"; import { LANG_DOMAINS } from "frontend/lib/crud-config/lang-domains"; import { ViewStateMachine } from "@/components/app/view-state-machine"; import { useDashboardWidgets } from "../dashboard.store"; -import { dashboardGridRoot } from "../styles"; import { DashboardSkeleton } from "../Skeleton"; import { DashboardWidget } from "../Widget"; -const Root = styled.div` - ${dashboardGridRoot}; -`; - const Container = styled.div` container-type: inline-size; `; @@ -53,11 +48,11 @@ export function BaseDashboard({ dashboardId, manageLink }: IProps) { loader={} > - +
{widgets.data.map((config) => ( ))} - +
diff --git a/src/frontend/views/Dashboard/Manage/_BaseManageDashboard.tsx b/src/frontend/views/Dashboard/Manage/_BaseManageDashboard.tsx index a19e7591b..636d5003f 100644 --- a/src/frontend/views/Dashboard/Manage/_BaseManageDashboard.tsx +++ b/src/frontend/views/Dashboard/Manage/_BaseManageDashboard.tsx @@ -16,15 +16,11 @@ import { useDashboardWidgets, useDeleteDashboardWidgetMutation, } from "../dashboard.store"; -import { dashboardGridRoot } from "../styles"; import { DashboardSkeleton } from "../Skeleton"; import { DashboardWidget } from "../Widget"; const Root = styled.div` container-type: inline-size; - .list { - ${dashboardGridRoot}; - } `; interface IProps { @@ -85,7 +81,7 @@ export function BaseManageDashboard({ dashboardId, doneLink, title }: IProps) { diff --git a/src/frontend/views/Dashboard/Skeleton.tsx b/src/frontend/views/Dashboard/Skeleton.tsx index f941ace98..1e6200310 100644 --- a/src/frontend/views/Dashboard/Skeleton.tsx +++ b/src/frontend/views/Dashboard/Skeleton.tsx @@ -1,28 +1,23 @@ -import styled from "styled-components"; import { TableSkeleton } from "@/components/app/skeleton/table"; -import { dashboardGridRoot, WidgetRoot } from "./styles"; +import { WidgetRoot } from "./styles"; import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; -const Root = styled.div` - ${dashboardGridRoot}; -`; - export function DashboardSkeleton() { return ( - +
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => ( ))} - - +
+
- +
); } diff --git a/src/frontend/views/Dashboard/Widget/_components/WidgetHeader/index.tsx b/src/frontend/views/Dashboard/Widget/_components/WidgetHeader/index.tsx index a2017bd67..39bbb697f 100644 --- a/src/frontend/views/Dashboard/Widget/_components/WidgetHeader/index.tsx +++ b/src/frontend/views/Dashboard/Widget/_components/WidgetHeader/index.tsx @@ -35,7 +35,7 @@ export function WidgetHeader({ return (
-
+
{setting && ( @@ -67,10 +67,11 @@ export function WidgetHeader({ {hasRelativeDate && !isPreview && ( ({ id: value, label, - systemIcon: null, + systemIcon: "Filter", action: () => { setWidgetRelativeDate({ widgetId, diff --git a/src/frontend/views/Dashboard/styles.ts b/src/frontend/views/Dashboard/styles.ts index 89ec1294c..291233b79 100644 --- a/src/frontend/views/Dashboard/styles.ts +++ b/src/frontend/views/Dashboard/styles.ts @@ -1,13 +1,6 @@ -import { gridItem, gridRoot } from "frontend/design-system/constants/grid"; +import { gridItem } from "frontend/design-system/constants/grid"; import { GridSpanSizes } from "shared/types/ui"; -import styled, { css } from "styled-components"; - -export const dashboardGridRoot = css` - ${gridRoot} - user-select: none; - row-gap: 16px; - grid-auto-rows: minmax(110px, auto); -`; +import styled from "styled-components"; export const WidgetRoot = styled.div<{ $span: GridSpanSizes; diff --git a/src/frontend/views/account/_Base.tsx b/src/frontend/views/account/_Base.tsx index 3b451fab7..13e5c6b06 100644 --- a/src/frontend/views/account/_Base.tsx +++ b/src/frontend/views/account/_Base.tsx @@ -1,4 +1,3 @@ -import { useRouter } from "next/router"; import { ReactNode } from "react"; import { AppLayout } from "frontend/_layouts/app"; import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; @@ -14,7 +13,6 @@ interface IProps { } export function BaseAccountLayout({ children }: IProps) { - const router = useRouter(); const portalAccountMenu = usePortalAccountMenu(); const baseMenuItems: IMenuActionItem[] = [ @@ -55,10 +53,7 @@ export function BaseAccountLayout({ children }: IProps) { - + {children} diff --git a/src/frontend/views/data/Details/_Layout.tsx b/src/frontend/views/data/Details/_Layout.tsx index 4bcb758d9..89b8a96fa 100644 --- a/src/frontend/views/data/Details/_Layout.tsx +++ b/src/frontend/views/data/Details/_Layout.tsx @@ -10,14 +10,15 @@ import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; import { useEntityDictionPlurals } from "frontend/hooks/entity/entity.queries"; import { DataStates } from "frontend/lib/data/types"; import { ContentLayout } from "@/components/app/content-layout"; -import { ListManager } from "@/components/app/list-manager"; -import { IListMangerItemProps } from "@/components/app/list-manager/list-manager-item"; - import { useEntityViewStateMachine } from "../hooks/useEntityViewStateMachine"; import { getEntitiesRelationsCount } from "./utils"; import { useEntityActionMenuItems } from "../../entity/constants"; -import { Card, CardContent } from "@/components/ui/card"; import { IMenuActionItem } from "@/components/app/button/types"; +import { MenuSection } from "@/components/app/menu-section"; +import { ViewStateMachine } from "@/components/app/view-state-machine"; +import { ListSkeleton } from "@/components/app/skeleton/list"; +import { fakeMessageDescriptor } from "@/translations/fake"; +import { Card, CardContent } from "@/components/ui/card"; export const DETAILS_LAYOUT_KEY = "___DETAILS_KEY__"; @@ -82,17 +83,6 @@ export function DetailsLayout({ ...relatedEntities, ]; - const relatedEntitiesLabelMap = Object.fromEntries( - listItems.map((relatedEntity) => [ - relatedEntity.name, - relatedEntity.referencelabel || - getEntitiesDictionPlurals( - relatedEntity.name, - relatedEntitiesMap[relatedEntity.name].type === "toOne" - ), - ]) - ); - const { isLoading, error } = referenceFields; const viewState = useEntityViewStateMachine({ @@ -106,52 +96,63 @@ export function DetailsLayout({ - - - relatedEntitiesLabelMap[name]} - render={(menuItem) => { - if (menuItem.name === DETAILS_LAYOUT_KEY) { - const props: IListMangerItemProps = { - label: menuItem.label, - active: menuKey === DETAILS_LAYOUT_KEY, - action: NAVIGATION_LINKS.ENTITY.DETAILS(entity, entityId), - }; - return props; - } - const entityType = - relatedEntitiesMap[menuItem.name]?.type || "toOne"; - const entityCount = getEntitiesRelationsCount( - entityType, - relatedEntitiesCounts.data[menuItem.name] + + + + + + } + > + { + const label = + menuItem.referencelabel || + getEntitiesDictionPlurals( + menuItem.name, + relatedEntitiesMap[menuItem.name].type === "toOne" ); - - const props: IListMangerItemProps = { - label: `${menuItem.label} ${entityCount}`, - active: menuKey === menuItem.name, - action: NAVIGATION_LINKS.ENTITY.RELATION_TABLE( - entity, - entityId, - menuItem.name, - entityType === "toOne" ? "one" : "many" - ), + if (menuItem.name === DETAILS_LAYOUT_KEY) { + const props: IMenuActionItem = { + id: "details", + systemIcon: "none", + label: fakeMessageDescriptor(label), + active: menuKey === DETAILS_LAYOUT_KEY, + action: NAVIGATION_LINKS.ENTITY.DETAILS(entity, entityId), }; - return props; - }} - /> - - + } + const entityType = + relatedEntitiesMap[menuItem.name]?.type || "toOne"; + const entityCount = getEntitiesRelationsCount( + entityType, + relatedEntitiesCounts.data[menuItem.name] + ); + + const props: IMenuActionItem = { + label: fakeMessageDescriptor(`${label} ${entityCount}`), + id: menuItem.name, + systemIcon: "none", + active: menuKey === menuItem.name, + action: NAVIGATION_LINKS.ENTITY.RELATION_TABLE( + entity, + entityId, + menuItem.name, + entityType === "toOne" ? "one" : "many" + ), + }; + + return props; + })} + /> + {children} diff --git a/src/frontend/views/data/Table/portal/main.tsx b/src/frontend/views/data/Table/portal/main.tsx index f0547073d..69377017e 100644 --- a/src/frontend/views/data/Table/portal/main.tsx +++ b/src/frontend/views/data/Table/portal/main.tsx @@ -22,12 +22,12 @@ export const useSyncPaginatedDataState = () => {}; export function TableViewComponent({ entity }: { entity: string }) { noop(entity); - return ; + return null; } export function TableTopComponent({ entity }: { entity: string }) { noop(entity); - return ; + return null; } export const usePortalTableColumns = (entity: string) => { diff --git a/src/frontend/views/entity/_Base.tsx b/src/frontend/views/entity/_Base.tsx index 4e63c8a66..97792c5b0 100644 --- a/src/frontend/views/entity/_Base.tsx +++ b/src/frontend/views/entity/_Base.tsx @@ -1,5 +1,4 @@ import { useNavigationStack } from "frontend/lib/routing/useNavigationStack"; -import { useRouter } from "next/router"; import { ReactNode } from "react"; import { useEntitySlug } from "frontend/hooks/entity/entity.config"; import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; @@ -86,7 +85,6 @@ interface IProps { export function BaseEntitySettingsLayout({ children, actionItems }: IProps) { const entity = useEntitySlug(); const { canGoBack, goBack } = useNavigationStack(); - const router = useRouter(); const menuItems = useMutateBaseEntitySettingsMenu( entity, @@ -108,10 +106,7 @@ export function BaseEntitySettingsLayout({ children, actionItems }: IProps) { )} - + {children} diff --git a/src/frontend/views/integrations/_Base.tsx b/src/frontend/views/integrations/_Base.tsx index c218e2749..52dd1fe8b 100644 --- a/src/frontend/views/integrations/_Base.tsx +++ b/src/frontend/views/integrations/_Base.tsx @@ -1,5 +1,4 @@ import { useRouteParam } from "frontend/lib/routing/useRouteParam"; -import { useRouter } from "next/router"; import { ReactNode } from "react"; import { AppLayout } from "frontend/_layouts/app"; import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; @@ -13,6 +12,9 @@ import { } from "./actions/actions.store"; import { fakeMessageDescriptor } from "@/translations/fake"; import { MenuSection } from "@/components/app/menu-section"; +import { ListSkeleton } from "@/components/app/skeleton/list"; +import { ViewStateMachine } from "@/components/app/view-state-machine"; +import { Card, CardContent } from "@/components/ui/card"; interface IProps { children: ReactNode; @@ -28,26 +30,35 @@ export function BaseActionsLayout({ children }: IProps) { const integrationsList = useIntegrationsList(); const activeIntegrations = useActiveIntegrations(); - const router = useRouter(); - return ( - { - const isActive = activeIntegrations.data.includes(menuitem.key); - return { - id: menuitem.key, - action: NAVIGATION_LINKS.INTEGRATIONS.ACTIONS(menuitem.key), - label: fakeMessageDescriptor(menuitem.title), - subtle: !isActive, - active: menuitem.key === currentKey, - systemIcon: isActive ? "Zap" : "ZapOff", - }; - })} - currentMenuItem={router.asPath.split("?")[0]} - /> + + + + + + } + > + { + const isActive = activeIntegrations.data.includes(menuitem.key); + return { + id: menuitem.key, + action: NAVIGATION_LINKS.INTEGRATIONS.ACTIONS(menuitem.key), + label: fakeMessageDescriptor(menuitem.title), + subtle: !isActive, + active: menuitem.key === currentKey, + systemIcon: isActive ? "Zap" : "ZapOff", + }; + })} + /> + {children} diff --git a/src/frontend/views/settings/_Base.tsx b/src/frontend/views/settings/_Base.tsx index da690afc8..75ea73927 100644 --- a/src/frontend/views/settings/_Base.tsx +++ b/src/frontend/views/settings/_Base.tsx @@ -1,6 +1,4 @@ -import { useRouter } from "next/router"; import { ReactNode } from "react"; - import { AppLayout } from "frontend/_layouts/app"; import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; import { msg } from "@lingui/macro"; @@ -66,16 +64,12 @@ const baseMenuItems: IMenuActionItem[] = [ ]; export function BaseSettingsLayout({ children }: IProps) { - const router = useRouter(); const menuItems = useMutateBaseSettingsMenu(baseMenuItems); return ( - + {children} diff --git a/src/shared/constants/Icons.tsx b/src/shared/constants/Icons.tsx index 1a63b0e9c..c36adb4f0 100644 --- a/src/shared/constants/Icons.tsx +++ b/src/shared/constants/Icons.tsx @@ -92,11 +92,11 @@ export const SystemIcons = { Sliders: ``, }; -export type SystemIconsKeys = keyof typeof SystemIcons; +export type SystemIconsKeys = keyof typeof SystemIcons | "none"; export const SystemIconsList = typescriptSafeObjectDotKeys(SystemIcons).sort( (a, b) => a.localeCompare(b) -); +) as unknown as SystemIconsKeys[]; export const systemIconToSVG = (icon: string, strokeWidth = 2) => { let iconPath = SystemIcons[icon]; diff --git a/src/styles/globals.css b/src/styles/globals.css index b37382c65..406977885 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -66,4 +66,10 @@ @apply focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary; @apply disabled:cursor-not-allowed disabled:bg-soft disabled:opacity-70; } + .grid-root { + @apply grid gap-4 grid-cols-1 md:grid-cols-12; + } + .dashboard-grid-root { + @apply grid-root select-none auto-rows-[minmax(100px,auto)]; + } }