diff --git a/.env.local.default b/.env.local.default index 4d9454f2cd..3afb4c94d7 100644 --- a/.env.local.default +++ b/.env.local.default @@ -17,7 +17,7 @@ KEY=certs/key.pem # Client variables --------------- APP_TITLE="IR Engine" -APP_LOGO=https://etherealengine-static.s3-us-east-1.amazonaws.com/logo.png +APP_LOGO=https://preview.ir.world/static/ir.svg APP_URL=https://localhost:3000 APP_HOST=localhost:3000 APP_PORT=3000 @@ -226,6 +226,12 @@ OPENSEARCH_HOST=http://localhost:9200 # Switch to `true` to enable local file system operations FS_PROJECT_SYNC_ENABLED=true +# Metabase variables +METABASE_SITE_URL= +METABASE_SECRET_KEY= +METABASE_CRASH_DASHBOARD_ID= +METABASE_EXPIRATION= + # Zendesk key for user authentication ZENDESK_KEY_NAME= ZENDESK_SECRET= diff --git a/.github/workflows/dev-deploy.yml b/.github/workflows/dev-deploy.yml deleted file mode 100755 index 41c5901310..0000000000 --- a/.github/workflows/dev-deploy.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: dev-deploy - -on: - push: - branches: [dev] -jobs: - secrets-gate-run: - runs-on: ubuntu-latest - outputs: - ok: ${{ steps.check-secrets-run.outputs.ok }} - steps: - - name: check for secrets needed to run workflows - id: check-secrets-run - run: | - if [ ${{ secrets.DEPLOYMENTS_ENABLED }} == 'true' ]; then - echo "ok=enabled" >> $GITHUB_OUTPUT - fi - secrets-gate-webhook: - runs-on: ubuntu-latest - outputs: - ok: ${{ steps.check-secrets-webhook.outputs.ok }} - steps: - - name: check for secrets needed to run workflows - id: check-secrets-webhook - run: | - if [ ${{ secrets.SEND_FINISHED_WEBHOOK }} == 'true' ]; then - echo "ok=enabled" >> $GITHUB_OUTPUT - fi - dev-deploy: - needs: - - secrets-gate-run - if: ${{ needs.secrets-gate-run.outputs.ok == 'enabled' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Setup Helm - run: scripts/setup_helm_builder.sh - - name: Setup AWS - run: scripts/setup_aws_builder.sh $EKS_AWS_ACCESS_KEY_ID $EKS_AWS_ACCESS_KEY_SECRET $AWS_REGION $CLUSTER_NAME - env: - EKS_AWS_ACCESS_KEY_ID: ${{ secrets.EKS_AWS_ACCESS_KEY_ID }} - EKS_AWS_ACCESS_KEY_SECRET: ${{ secrets.EKS_AWS_ACCESS_KEY_SECRET }} - AWS_REGION: ${{ secrets.AWS_REGION }} - CLUSTER_NAME: ${{ secrets.CLUSTER_NAME }} - - name: Space debug - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - - name: move package.json - run: mv package.json package.jsonmoved - - name: npm-install 'cli', @aws-sdk/client-ecr(-public), and @kubernetes/client-node - run: npm install cli @aws-sdk/client-ecr @aws-sdk/client-ecr-public @kubernetes/client-node - - name: restore package.json - run: mv package.jsonmoved package.json - - name: Expose GitHub Runtime - uses: crazy-max/ghaction-github-runtime@v2 - - name: Build and Push Docker Image - run: bash scripts/build_docker_builder.sh dev $GITHUB_SHA $AWS_REGION $PRIVATE_REPO - env: - STORAGE_AWS_ACCESS_KEY_ID: ${{ secrets.STORAGE_AWS_ACCESS_KEY_ID }} - STORAGE_AWS_ACCESS_KEY_SECRET: ${{ secrets.STORAGE_AWS_ACCESS_KEY_SECRET }} - REPO_NAME: ${{ secrets.DEV_REPO_NAME }} - AWS_REGION: ${{ secrets.AWS_REGION }} - REPO_URL: ${{ secrets.DEV_REPO_URL }} - REPO_PROVIDER: ${{ secrets.REPO_PROVIDER }} - PRIVATE_REPO: ${{ secrets.PRIVATE_REPO }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} - - name: Deploy to EKS - run: bash scripts/deploy_builder.sh dev $GITHUB_SHA - - name: Job succeeded - if: ${{ needs.secrets-gate-webhook.outputs.ok == 'enabled' }} - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - env: - JOB_STATUS: ${{ job.status }} - WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} - HOOK_OS_NAME: ${{ runner.os }} - WORKFLOW_NAME: ${{ github.workflow }} - run: | - git clone https://github.com/DiscordHooks/github-actions-discord-webhook.git webhook - bash webhook/send.sh $JOB_STATUS $WEBHOOK_URL - shell: bash diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml deleted file mode 100755 index 1539bc63f5..0000000000 --- a/.github/workflows/prod-deploy.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: prod-deploy -on: - push: - branches: - [main] -jobs: - secrets-gate-run: - runs-on: ubuntu-latest - outputs: - ok: ${{ steps.check-secrets-run.outputs.ok }} - steps: - - name: check for secrets needed to run workflows - id: check-secrets-run - run: | - if [ ${{ secrets.DEPLOYMENTS_ENABLED }} == 'true' ]; then - echo "ok=enabled" >> $GITHUB_OUTPUT - fi - secrets-gate-webhook: - runs-on: ubuntu-latest - outputs: - ok: ${{ steps.check-secrets-webhook.outputs.ok }} - steps: - - name: check for secrets needed to run workflows - id: check-secrets-webhook - run: | - if [ ${{ secrets.SEND_FINISHED_WEBHOOK }} == 'true' ]; then - echo "ok=enabled" >> $GITHUB_OUTPUT - fi - prod-deploy: - needs: - - secrets-gate-run - if: ${{ needs.secrets-gate-run.outputs.ok == 'enabled' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Setup Helm - run: scripts/setup_helm_builder.sh - - name: Setup AWS - run: scripts/setup_aws_builder.sh $EKS_AWS_ACCESS_KEY_ID $EKS_AWS_ACCESS_KEY_SECRET $AWS_REGION $CLUSTER_NAME - env: - EKS_AWS_ACCESS_KEY_ID: ${{ secrets.EKS_AWS_ACCESS_KEY_ID }} - EKS_AWS_ACCESS_KEY_SECRET: ${{ secrets.EKS_AWS_ACCESS_KEY_SECRET }} - AWS_REGION: ${{ secrets.AWS_REGION }} - CLUSTER_NAME: ${{ secrets.CLUSTER_NAME }} - - name: Space debug - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - - name: move package.json - run: mv package.json package.jsonmoved - - name: npm-install 'cli', @aws-sdk/client-ecr(-public), and @kubernetes/client-node - run: npm install cli @aws-sdk/client-ecr @aws-sdk/client-ecr-public @kubernetes/client-node - - name: restore package.json - run: mv package.jsonmoved package.json - - name: Expose GitHub Runtime - uses: crazy-max/ghaction-github-runtime@v2 - - name: Build and Push Docker Image - run: bash scripts/build_docker_builder.sh prod $GITHUB_SHA $AWS_REGION $PRIVATE_REPO - env: - STORAGE_AWS_ACCESS_KEY_ID: ${{ secrets.STORAGE_AWS_ACCESS_KEY_ID }} - STORAGE_AWS_ACCESS_KEY_SECRET: ${{ secrets.STORAGE_AWS_ACCESS_KEY_SECRET }} - REPO_NAME: ${{ secrets.PROD_REPO_NAME }} - AWS_REGION: ${{ secrets.AWS_REGION }} - REPO_URL: ${{ secrets.PROD_REPO_URL }} - REPO_PROVIDER: ${{ secrets.REPO_PROVIDER }} - PRIVATE_REPO: ${{ secrets.PRIVATE_REPO }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} - - name: Deploy to EKS - run: bash scripts/deploy_builder.sh prod $GITHUB_SHA - - name: Job succeeded - if: ${{ needs.secrets-gate-webhook.outputs.ok == 'enabled' }} - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - env: - JOB_STATUS: ${{ job.status }} - WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} - HOOK_OS_NAME: ${{ runner.os }} - WORKFLOW_NAME: ${{ github.workflow }} - run: | - git clone https://github.com/DiscordHooks/github-actions-discord-webhook.git webhook - bash webhook/send.sh $JOB_STATUS $WEBHOOK_URL - shell: bash diff --git a/.gitignore b/.gitignore index 782641d740..46100ba328 100755 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ coverage # nyc test coverage .nyc_output +coverage/ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt diff --git a/nycrc.json b/nycrc.json new file mode 100644 index 0000000000..db87db8445 --- /dev/null +++ b/nycrc.json @@ -0,0 +1,35 @@ +{ + "extension": [ + ".ts", + ".tsx" + ], + "exclude": [ + "**/*.d.ts", + "**/*.test.ts", + "**/*.test.tsx" + ], + "check-coverage": true, + "per-file": true, + "statements": 80, + "branches": 80, + "functions": 80, + "lines": 80, + "watermarks": { + "statements": [ + 80, + 95 + ], + "branches": [ + 80, + 95 + ], + "functions": [ + 80, + 95 + ], + "lines": [ + 80, + 95 + ] + } +} diff --git a/package.json b/package.json index 801479f8f2..7cf384e3d4 100755 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "check-eslint": "eslint --quiet .", "checkout-dev": "lerna exec 'git checkout dev' --parallel --no-bail", "clean-node-modules": "npx rimraf node_modules && npx rimraf package-lock.json && npx lerna exec npx rimraf node_modules && npx lerna exec npx rimraf package-lock.json", - "coverage": "nyc npm run test", "create-root-package-json": "cross-env ts-node --swc scripts/create-root-package-json", "create-project": "cross-env ts-node --swc scripts/create-project", "depcheck": "lerna exec --no-bail --stream -- depcheck", @@ -83,6 +82,11 @@ "test": "cross-env TEST=true lerna run --scope '@etherealengine/*' --ignore '@etherealengine/server-core' test && lerna run --scope '@etherealengine/server-core' test && lerna run --ignore '@etherealengine/*' test", "test-e2e": "ts-node --swc scripts/run_e2e_tests.ts", "test:ci": "cpy --no-overwrite --rename=.env.local '.env.local.default' . && cross-env CI=true npm run test", + "test-coverage": "npm run test-coverage-generate ; npm run test-coverage-launch", + "test-coverage-generate": "nyc --nycrc-path ./nycrc.json --reporter=html npm run test", + "test-coverage-launch": "./scripts/test-coverage-launch.sh", + "test-coverage-check": "nyc --nycrc-path ./nycrc.json --check-coverage --per-file --silent --clean false npm run test", + "test-coverage-cli-report": "nyc --nycrc-path ./nycrc.json --reporter=text --skip-full true npm run test", "validate": "npm run lint && lerna run validate", "version-increment": "lerna version --conventional-commits --yes", "version-increment-no-tag": "lerna version --conventional-commits --yes --no-git-tag-version", @@ -109,6 +113,7 @@ "@eslint/eslintrc": "3.1.0", "@eslint/js": "9.5.0", "@ianvs/prettier-plugin-sort-imports": "4.1.0", + "@istanbuljs/nyc-config-typescript": "^1.0.2", "@swc/core": "1.3.41", "@testing-library/react": "15.0.4", "@types/app-root-path": "1.2.4", @@ -145,7 +150,7 @@ }, "dependencies": { "@aws-sdk/client-ecr": "^3.319.0", - "@aws-sdk/client-s3": "3.614.0", + "@aws-sdk/client-s3": "^3.319.0", "@feathersjs/errors": "5.0.5", "@feathersjs/feathers": "5.0.5", "@feathersjs/schema": "5.0.5", diff --git a/packages/client-core/i18n/en/admin.json b/packages/client-core/i18n/en/admin.json index 34b7ac35ac..d40aa031d7 100755 --- a/packages/client-core/i18n/en/admin.json +++ b/packages/client-core/i18n/en/admin.json @@ -83,9 +83,12 @@ "all": "All", "refresh": "Refresh", "name": "Name", + "lastUpdatedBy": "Last updated by user id: {{userId}} on {{updatedAt}}", "fillRequiredFields": "Please fill all required field", "fixErrorFields": "Please fix all errors", - "logOut": "Log Out" + "logOut": "Log Out", + "newestFirst": "Newest First", + "oldestFirst": "Oldest First" }, "analytics": { "loading": "Loading analytics...", @@ -102,6 +105,10 @@ "activity": "Activity", "users": "Users" }, + "crashReport": { + "title": "Crash Report", + "loading": "Loading crash report..." + }, "group": { "createGroup": "Create Group", "name": "Name", @@ -199,6 +206,7 @@ "name": "Name", "projectVersion": "Version", "enabled": "Enabled", + "visibility": "Visibility", "commitSHA": "Commit SHA", "commitDate": "Commit Date", "actions": "Actions" @@ -208,8 +216,10 @@ "repo": "Repo", "access": "Access", "invalidateCache": "Invalidate Cache", - "update": "Update" + "update": "Update", + "history": "History" }, + "projectHistory": "Project History", "addProject": "Add Project", "updateProject": "Update Project", "downloadProject": "Download Project", @@ -532,7 +542,6 @@ "delete": "Delete", "add": "Add", "noSettingsMessage": "No settings available", - "lastUpdatedBy": "Last updated by user id: {{userId}}", "duplicateKey": "Duplicate keys cannot exist", "keyName": "Key Name", "value": "Value" @@ -556,12 +565,19 @@ "port": "Port", "processInterval": "Process Interval" }, - "plugins": "Plugins", + "metabase": { + "header": "Metabase", + "subtitle": "Edit Metabase Settings", + "siteUrl": "Site Url", + "secretKey": "Secret Key", + "expiration": "Expiration", + "crashDashboardId": "Crash Dashboard Id" + }, "zendesk": { "header": "Zendesk", "subtitle": "Edit Zendesk Settings" - }, + }, "keyName": "key Name", "kid": "Key Id" }, @@ -623,6 +639,7 @@ "avatar": "Avatar", "accountIdentifier": "Linked Accounts", "lastLogin": "Last Login", + "acceptedTOS": "TOS Agreed", "isGuest": "Is Guest", "action": "Action" }, diff --git a/packages/client-core/i18n/en/common.json b/packages/client-core/i18n/en/common.json index f63d0fe9e0..2e1c978439 100755 --- a/packages/client-core/i18n/en/common.json +++ b/packages/client-core/i18n/en/common.json @@ -47,6 +47,8 @@ "loadingAllowed": "Loading allowed routes...", "loadingXRSystems": "Loading immersive session...", "connectingToWorld": "Connecting to world...", + "needToAgreeTOS": "You need to agree the terms of service to access chat.", + "needToLogIn": "You need to log in to access chat.", "connectingToMedia": "Connecting to media...", "entering": "Entering world...", "loading": "Loading...", @@ -130,7 +132,8 @@ "error": { "loading-error": "Failed to load user data", "validation-error": "Please input valid {{type}}", - "login-error": "Failed to login" + "login-error": "Failed to login", + "expiredToken": "The token has expired." }, "table": { "refetching": "Refetching Data...", diff --git a/packages/client-core/i18n/en/editor.json b/packages/client-core/i18n/en/editor.json index 1b4aa3b8d2..cbd6e57567 100755 --- a/packages/client-core/i18n/en/editor.json +++ b/packages/client-core/i18n/en/editor.json @@ -1,5 +1,6 @@ { "loading": "Loading Project", + "loadingNode": "Loading {{name}} Editor...", "loadingError": "Error loading project", "loadingErrorMsg": "There was an error when loading the project.", "selectSceneMsg": "Select a Scene in the Project to Start", @@ -25,6 +26,7 @@ "uploadingSceneMsg": "Uploading scene: {{percentage}}%", "envMapError": "Error loading cubemap images {{files}}", "lbl-return": "Return", + "loadingAssets": "Loading Assets", "loadingScenes": "Loading Scenes", "loadingScenesWithProgress": "Scene Loading... {{progress}}% ({{assetsLeft}} assets left)", "help": "Help", @@ -70,7 +72,7 @@ "unknownStatus": "Unknown Status", "CORS": "Possibly a CORS error", "urlFetchError": "Failed to fetch \"{{url}}\"", - "invalidSceneName": "Provide a valid scene name. Only alphanumerics, hyphens and underscores are allowed. (max length 64)" + "invalidSceneName": "Scene name must be 4-64 characters long, using only alphanumeric characters, hyphens, and underscores." }, "viewport": { "title": "Viewport", @@ -109,9 +111,9 @@ "gizmo": { "pointer": "Pointer", "description": "Transform Gizmo", - "translate": "[T] Translate", - "rotate": "[R] Rotate", - "scale": "[Y] Scale", + "translate": "[W] Translate", + "rotate": "[E] Rotate", + "scale": "[R] Scale", "combined": "[U] Combined Transform" }, "transformSpace": { @@ -566,7 +568,7 @@ }, "hemisphere": { "name": "Hemisphere Light", - "description": "A light which illuminates the scene from directly overhead.", + "description": "A light which illuminates the scene with a sky color from above and a ground color from below.", "lbl-skyColor": "Sky Color", "lbl-groundColor": "Ground Color", "lbl-intensity": "Intensity" @@ -727,9 +729,17 @@ } }, "cameraSettings": { - "name": "Camera", + "name": "Camera Settings", "description": "Change the camera settings for this scene." }, + "cameraComponent": { + "name": "Camera", + "description": "Camera Component", + "lbl-fov": "FOV", + "lbl-aspect": "Aspect", + "lbl-near": "Near", + "lbl-far": "Far" + }, "postprocessing": { "name": "Post Processing Effect", "enabled": "Enabled", @@ -815,7 +825,11 @@ "lbl-loading": "Loading Screen", "info-loading": "Change the loading screen", "lbl-colors": "Colors", - "lbl-killHeight": "Kill Height" + "lbl-killHeight": "Kill Height", + "lbl-spectate": "Force Spectator", + "info-spectate": "Disable avatars and force the user to spectate the scene", + "lbl-uuid": "Spectate Entity", + "info-uuid": "Optional entity to spectate" }, "scene": { "name": "Scene", @@ -1163,7 +1177,7 @@ "point-light": "A light which emits in all directions from a single point.", "spot-light": "Creates a light that shines in a specific direction.", "directional-light": "Creates a light that emits evenly in a single direction.", - "hemisphere-light": "A light which illuminates the scene from directly overhead.", + "hemisphere-light": "A light which illuminates the scene with a sky color from above and a ground color from below.", "particle-system": "Creates a particle emitter.", "system": "Inserts code into the scene by creating a new Entity Component System based on the provided .ts file", "visual-script": "Customizes state and behavior of entities through a visual node connections.", @@ -1194,15 +1208,17 @@ "viewAssetProperties": "View Properties", "refresh": "Refresh", "back": "Back", - "loadingFiles": "Loading files", - "loadingProjects": "Loading projects", + "loadingFiles": "Loading Files", + "loadingProjects": "Loading Projects", "compress": "Compress", "convert": "Convert", "downloadProject": "Download Project", "uploadAssets": "Upload Assets", "uploadFiles": "Upload Files", "uploadFolder": "Upload Folder", - "search-placeholder": "Search folders", + "uploadingFiles": "Uploading Files ({{completed}}/{{total}})", + "downloadingProject": "Downloading Project ({{completed}}/{{total}})", + "search-placeholder": "Search", "generatingThumbnails": "Generating Thumbnails ({{count}} remaining)", "file": "File", "directory": "Directory", @@ -1251,7 +1267,7 @@ }, "scene-assets": { "no-category": "No category selected", - "search-placeholder": "Search for an asset ...", + "search-placeholder": "Search", "preview": "Preview", "info-drag-drop": "Drag and Drop these items into the scene", "settings": "Settings", @@ -1263,12 +1279,14 @@ "info": "The scene Hierarchy contains all element currently in your scene (assets, lighting, items from the tool menu, etc).", "lbl-rename": "Rename", "lbl-renameScene": "Rename Scene", + "lbl-edited": "Edited", "lbl-duplicate": "Duplicate", "lbl-group": "Group", "lbl-copy": "Copy", "lbl-paste": "Paste", "lbl-delete": "Delete", - "lbl-deleteScene": "Are you sure you want to delete '{{sceneName}}' scene?", + "lbl-deleteScene": "Delete Scene", + "lbl-deleteSceneDescription": "Are you sure you want to delete '{{sceneName}}' scene?", "lbl-expandAll": "Expand All", "lbl-collapseAll": "Collapse All", "lbl-explode": "Explode Objects", @@ -1343,7 +1361,10 @@ "lbl-thumbnail": "Generate thumbnail & envmap", "lbl-confirm": "Save Scene", "info-confirm": "Are you sure you want to save the scene?", - "info-question": "Do you want to save the current scene?" + "info-question": "Do you want to save the current scene?", + "unsavedChanges": { + "title": "Unsaved Changes" + } }, "saveNewScene": { "title": "Save As", diff --git a/packages/client-core/i18n/en/social.json b/packages/client-core/i18n/en/social.json index 2b97d733f8..cff3dd7693 100755 --- a/packages/client-core/i18n/en/social.json +++ b/packages/client-core/i18n/en/social.json @@ -185,6 +185,9 @@ "video": { "back": "Back" }, + "user": { + "reportUser": "Report User" + }, "terms": { "confirmTerms": "I agree to Terms of Service", "confirmPolicy": "I agree to Privacy Policy" diff --git a/packages/client-core/i18n/en/user.json b/packages/client-core/i18n/en/user.json index 62be7cb06d..829d1b087d 100755 --- a/packages/client-core/i18n/en/user.json +++ b/packages/client-core/i18n/en/user.json @@ -222,6 +222,11 @@ "issueVC": "Issue a VC", "requestVC": "Request a VC", "addSocial": "Connect your Social Logins", + "logIn": "Log In", + "agreeTOS": "I agree to the ", + "termsOfService": "Infinite Reality Terms of Service", + "confirmAge13": "I am 13 years of age or older", + "confirmAge18": "I am 18 years of age or older", "removeSocial": "Remove Social Logins", "connections": { "title": "Connections", @@ -265,7 +270,8 @@ "apiKeyCopied": "API Key copied", "refreshApiKey": "Refresh API Key", "privacyPolicy": "Privacy Policy", - "helpChat": "Help Chat" + "helpChat": "Help Chat", + "reportWorld": "Report World" }, "oauth": { "authenticating": "Authenticating...", @@ -306,7 +312,8 @@ "setting": "Settings", "server": "Server", "recordings": "Recordings", - "channels": "Channels" + "channels": "Channels", + "crashReport": "Crash Report" }, "resource": { "createResource": "Create Resource" diff --git a/packages/client-core/src/admin/DefaultAdminRoutes.tsx b/packages/client-core/src/admin/DefaultAdminRoutes.tsx index 2086403285..b620160628 100644 --- a/packages/client-core/src/admin/DefaultAdminRoutes.tsx +++ b/packages/client-core/src/admin/DefaultAdminRoutes.tsx @@ -27,6 +27,7 @@ import React, { lazy } from 'react' import { HiOutlineCube } from 'react-icons/hi' import { HiMapPin, + HiMiniShieldExclamation, HiOutlineCog6Tooth, HiOutlineGlobeAlt, HiOutlineMegaphone, @@ -66,6 +67,8 @@ const Settings = lazy(() => import('./components/settings')) const Channels = lazy(() => import('./components/channel')) +const CrashReport = lazy(() => import('./components/crash-report')) + export const DefaultAdminRoutes: Record = { settings: { name: 'user:dashboard.setting', @@ -150,5 +153,12 @@ export const DefaultAdminRoutes: Record = { component: Channels, access: false, icon: + }, + crashes: { + name: 'user:dashboard.crashReport', + scope: 'server', + component: CrashReport, + access: false, + icon: } } diff --git a/packages/client-core/src/admin/adminRoutes.tsx b/packages/client-core/src/admin/adminRoutes.tsx index c8c5f2e50d..9643b85486 100644 --- a/packages/client-core/src/admin/adminRoutes.tsx +++ b/packages/client-core/src/admin/adminRoutes.tsx @@ -29,9 +29,8 @@ import { Link, Route, Routes, useLocation } from 'react-router-dom' import { ThemeState } from '@etherealengine/client-core/src/common/services/ThemeService' import { getMutableState, getState, NO_PROXY, useHookstate, useMutableState } from '@etherealengine/hyperflux' -import { AuthState } from '../user/services/AuthService' +import { AuthService, AuthState } from '../user/services/AuthService' import { AllowedAdminRoutesState } from './AllowedAdminRoutesState' -import Projects from './components/project' import '@etherealengine/engine/src/EngineModule' @@ -41,13 +40,19 @@ import { HiMiniMoon, HiMiniSun } from 'react-icons/hi2' import Button from '@etherealengine/ui/src/primitives/tailwind/Button' import PopupMenu from '@etherealengine/ui/src/primitives/tailwind/PopupMenu' +import Tooltip from '@etherealengine/ui/src/primitives/tailwind/Tooltip' import { RouterState } from '../common/services/RouterService' import { DefaultAdminRoutes } from './DefaultAdminRoutes' const $allowed = lazy(() => import('@etherealengine/client-core/src/admin/allowedRoutes')) const AdminTopBar = () => { + const { t } = useTranslation() const theme = useHookstate(getMutableState(ThemeState)).theme + const selfUser = getState(AuthState).user + const tooltip = `${selfUser.name} (${selfUser.identityProviders + .map((item) => `${item.type}: ${item.accountIdentifier}`) + .join(', ')}) ${selfUser.id}` const toggleTheme = () => { const currentTheme = getState(ThemeState).theme @@ -57,7 +62,7 @@ const AdminTopBar = () => { return (
iR Engine Logo -
+
+ + +
) @@ -150,7 +160,6 @@ const AdminRoutes = () => {
} /> - {} />}
diff --git a/packages/client-core/src/admin/allowedRoutes.tsx b/packages/client-core/src/admin/allowedRoutes.tsx index c1efaf962a..7de99ca715 100644 --- a/packages/client-core/src/admin/allowedRoutes.tsx +++ b/packages/client-core/src/admin/allowedRoutes.tsx @@ -29,8 +29,8 @@ import { Route, Routes, useLocation } from 'react-router-dom' import { NO_PROXY, useMutableState } from '@etherealengine/hyperflux' +import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' import { Redirect } from '../common/components/Redirect' -import { LoadingCircle } from '../components/LoadingCircle' import { AllowedAdminRoutesState } from './AllowedAdminRoutesState' const AllowedRoutes = () => { @@ -43,13 +43,25 @@ const AllowedRoutes = () => { const currentRoute = allowedRoutes[path] + const allowedRoutesKeys = Object.keys(allowedRoutes) + if (!path) { + for (const key of allowedRoutesKeys) { + const allowedRoute = allowedRoutes[key] + if (allowedRoute?.value && allowedRoute?.value?.access) { + return + } + } + } + if (currentRoute?.value && currentRoute.redirect.value) return const Element = currentRoute?.get(NO_PROXY)?.component const allowed = currentRoute?.access?.value return ( - }> + } + > {allowed && Element && } />} ) diff --git a/packages/client-core/src/admin/common/constants/project.ts b/packages/client-core/src/admin/common/constants/project.ts index a27723aac0..d851c82931 100644 --- a/packages/client-core/src/admin/common/constants/project.ts +++ b/packages/client-core/src/admin/common/constants/project.ts @@ -27,7 +27,7 @@ import { t } from 'i18next' import { ITableHeadCell } from '../Table' -type IdType = 'name' | 'projectVersion' | 'enabled' | 'commitSHA' | 'commitDate' | 'actions' +type IdType = 'name' | 'projectVersion' | 'enabled' | 'visibility' | 'commitSHA' | 'commitDate' | 'actions' export type ProjectRowType = Record @@ -38,7 +38,8 @@ interface IProjectColumn extends ITableHeadCell { export const projectsColumns: IProjectColumn[] = [ { id: 'name', sortable: true, label: t('admin:components.project.columns.name') }, { id: 'projectVersion', label: t('admin:components.project.columns.projectVersion') }, - { id: 'enabled', label: t('admin:components.project.columns.enabled') }, + { id: 'enabled', sortable: true, label: t('admin:components.project.columns.enabled') }, + { id: 'visibility', sortable: true, label: t('admin:components.project.columns.visibility') }, { id: 'commitSHA', label: t('admin:components.project.columns.commitSHA') }, { id: 'commitDate', sortable: true, label: t('admin:components.project.columns.commitDate') }, { id: 'actions', label: t('admin:components.project.columns.actions') } diff --git a/packages/client-core/src/admin/common/constants/user.ts b/packages/client-core/src/admin/common/constants/user.ts index 6cd145be31..2ad252fd87 100644 --- a/packages/client-core/src/admin/common/constants/user.ts +++ b/packages/client-core/src/admin/common/constants/user.ts @@ -27,7 +27,16 @@ import { t } from 'i18next' import { ITableHeadCell } from '../Table' -type IdType = 'select' | 'id' | 'name' | 'accountIdentifier' | 'lastLogin' | 'isGuest' | 'action' | 'avatar' +type IdType = + | 'select' + | 'id' + | 'name' + | 'accountIdentifier' + | 'lastLogin' + | 'acceptedTOS' + | 'isGuest' + | 'action' + | 'avatar' export type UserRowType = Record @@ -40,7 +49,8 @@ export const userColumns: IUserColumn[] = [ { id: 'name', sortable: true, label: t('admin:components.user.columns.name') }, { id: 'avatar', label: t('admin:components.user.columns.avatar') }, { id: 'accountIdentifier', label: t('admin:components.user.columns.accountIdentifier') }, - { id: 'lastLogin', sortable: true, label: t('admin:components.user.columns.lastLogin') }, + { id: 'lastLogin', label: t('admin:components.user.columns.lastLogin') }, + { id: 'acceptedTOS', sortable: true, label: t('admin:components.user.columns.acceptedTOS') }, { id: 'isGuest', sortable: true, label: t('admin:components.user.columns.isGuest') }, { id: 'action', label: t('admin:components.user.columns.action') } ] diff --git a/packages/client-core/src/admin/components/crash-report/index.tsx b/packages/client-core/src/admin/components/crash-report/index.tsx new file mode 100644 index 0000000000..16c10ab064 --- /dev/null +++ b/packages/client-core/src/admin/components/crash-report/index.tsx @@ -0,0 +1,76 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import { metabaseUrlPath } from '@etherealengine/common/src/schema.type.module' +import { useHookstate } from '@etherealengine/hyperflux' +import { useMutation } from '@etherealengine/spatial/src/common/functions/FeathersHooks' +import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' +import Text from '@etherealengine/ui/src/primitives/tailwind/Text' +import { isEmpty } from 'lodash' +import React, { useEffect } from 'react' +import { useTranslation } from 'react-i18next' + +export default function CrashReport() { + const { t } = useTranslation() + const metabaseMutation = useMutation(metabaseUrlPath) + const iframeUrl = useHookstate('') + + useEffect(() => { + metabaseMutation + .create( + {}, + { + query: { + action: 'crash' + } + } + ) + .then(async (url) => { + iframeUrl.set(url) + }) + }, []) + + return ( + <> +
+ + {t('admin:components.crashReport.title')} + +
+
+ {isEmpty(iframeUrl.value) && ( +
+ +
+ )} + {!isEmpty(iframeUrl.value) && ( +
+