From 5ff2719cdab43886dd2b3beff4bd112af51769f2 Mon Sep 17 00:00:00 2001 From: James Chang Date: Wed, 8 Nov 2023 23:46:03 -0500 Subject: [PATCH] Various frontend/backend updates --- .github/workflows/backend-deploy.yml | 7 + backend/cors.json | 2 +- backend/deploy.md.example | 2 +- backend/env.json.example | 6 +- backend/functions/package-lock.json | 14 +- backend/functions/package.json | 3 +- backend/functions/src/config/index.ts | 14 + backend/functions/src/index.ts | 25 +- .../src/schema/core/helpers/resolver.ts | 7 +- .../src/schema/models/file/typeDef.ts | 8 + .../src/scripts/executeAdminScript.ts | 8 + .../components/common/versionCheckText.vue | 12 +- .../components/dialog/editRecordDialog.vue | 10 +- .../components/dialog/selectOptionDialog.vue | 2 - frontend/components/input/genericInput.vue | 3 +- .../interface/crud/crudRecordInterface.vue | 20 +- .../components/interface/crud/hero/hero.vue | 3 +- .../components/menu/previewRecordMenu.vue | 38 +- frontend/components/navigation/footer.vue | 2 +- frontend/components/page/crudRecordPage.vue | 7 +- frontend/components/page/viewRecordPage.vue | 565 +----------------- .../components/table/nameAvatarColumn.vue | 5 +- frontend/mixins/crud.js | 13 +- frontend/mixins/hero.js | 6 + frontend/mixins/viewRecordInterface.js | 1 - frontend/mixins/viewRecordPage.js | 555 +++++++++++++++++ frontend/pages/my/view/_type.vue | 13 +- frontend/services/base.ts | 2 + frontend/services/recordInfo.ts | 1 + frontend/types/index.ts | 29 +- 30 files changed, 731 insertions(+), 652 deletions(-) create mode 100644 backend/functions/src/scripts/executeAdminScript.ts create mode 100644 frontend/mixins/viewRecordPage.js diff --git a/.github/workflows/backend-deploy.yml b/.github/workflows/backend-deploy.yml index 1ab1760..52842da 100644 --- a/.github/workflows/backend-deploy.yml +++ b/.github/workflows/backend-deploy.yml @@ -19,6 +19,13 @@ jobs: - name: Install Dependencies working-directory: ./backend/functions run: npm install + - name: Set Commit SHA + uses: w9jds/firebase-action@master + with: + args: functions:config:set base.version="${{ github.sha }}" + env: + FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + PROJECT_PATH: ./backend/functions - name: Deploy to Firebase uses: w9jds/firebase-action@master with: diff --git a/backend/cors.json b/backend/cors.json index 8ac42e4..81c5260 100644 --- a/backend/cors.json +++ b/backend/cors.json @@ -1,6 +1,6 @@ [ { - "origin": ["https://boilerplate.giraffeql.com"], + "origin": ["https://boilerplate.giraffeql.com", "http://localhost:3000"], "responseHeader": ["Content-Type"], "method": ["GET"], "maxAgeSeconds": 3600 diff --git a/backend/deploy.md.example b/backend/deploy.md.example index 0c19f5d..375b637 100644 --- a/backend/deploy.md.example +++ b/backend/deploy.md.example @@ -16,7 +16,7 @@ firebase functions:config:set base.origins="https://example.com" base.timeout_se # set serveImage config -firebase functions:config:set serve_image.bucket="x.appspot.com" serve_image.source_path="source" serve_image.cache_path="cache" serve_image.temp_path="temp" +firebase functions:config:set serve_image.bucket="x.appspot.com" serve_image.source_path="source" serve_image.cache_path="cache" serve_image.temp_path="temp" serve_image.cdn_url="https://cdn.giraffeql.com" # set stripe config diff --git a/backend/env.json.example b/backend/env.json.example index e96debe..5a855c1 100644 --- a/backend/env.json.example +++ b/backend/env.json.example @@ -21,7 +21,8 @@ "bucket": "giraffeql-boilerplate.appspot.com", "source_path": "source", "cache_path": "cache", - "temp_path": "temp" + "temp_path": "temp", + "cdn_url": "https://cdn.ozycon.com" }, "stripe": { "secret_key": "", @@ -29,6 +30,7 @@ }, "base": { "origins": "https://boilerplate.giraffeql.com", - "timeout_seconds": "60" + "timeout_seconds": "60", + "version": "DEV" } } diff --git a/backend/functions/package-lock.json b/backend/functions/package-lock.json index 5fbe60d..d72641a 100644 --- a/backend/functions/package-lock.json +++ b/backend/functions/package-lock.json @@ -9,7 +9,7 @@ "axios": "^0.21.4", "express": "^4.17.1", "firebase-admin": "^11.10.1", - "firebase-functions": "^4.4.1", + "firebase-functions": "^4.5.0", "giraffeql": "^2.0.13", "image-resizing": "^0.1.3", "knex": "^0.21.21", @@ -2850,9 +2850,9 @@ } }, "node_modules/firebase-functions": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.4.1.tgz", - "integrity": "sha512-3no53Lg12ToNlPSgLZtAFLQAz6si7ilHvzO8NC3/2EybyUwegpj5YhHwNiCw839lmAWp3znjATJDTvADFiZMrg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", + "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", "dependencies": { "@types/cors": "^2.8.5", "@types/express": "4.17.3", @@ -8924,9 +8924,9 @@ } }, "firebase-functions": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.4.1.tgz", - "integrity": "sha512-3no53Lg12ToNlPSgLZtAFLQAz6si7ilHvzO8NC3/2EybyUwegpj5YhHwNiCw839lmAWp3znjATJDTvADFiZMrg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", + "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", "requires": { "@types/cors": "^2.8.5", "@types/express": "4.17.3", diff --git a/backend/functions/package.json b/backend/functions/package.json index 3ae5906..a2dfd13 100644 --- a/backend/functions/package.json +++ b/backend/functions/package.json @@ -9,6 +9,7 @@ "generate:migration": "set DEV=1 && ts-node src/scripts/generateMigration.ts", "generate:model": "set DEV=1 && ts-node src/scripts/generateModel.ts", "grantDBPermissions": "set DEV=1 && ts-node src/scripts/grantSchemaPermissions.ts", + "executeAdminScript": "set DEV=1 && ts-node src/scripts/executeAdminScript.ts", "grantAdmin": "set DEV=1 && ts-node src/scripts/grantAdmin.ts", "shell": "npm run build && firebase functions:shell", "start": "npm run shell", @@ -23,7 +24,7 @@ "axios": "^0.21.4", "express": "^4.17.1", "firebase-admin": "^11.10.1", - "firebase-functions": "^4.4.1", + "firebase-functions": "^4.5.0", "giraffeql": "^2.0.13", "image-resizing": "^0.1.3", "knex": "^0.21.21", diff --git a/backend/functions/src/config/index.ts b/backend/functions/src/config/index.ts index 200f212..af33f6c 100644 --- a/backend/functions/src/config/index.ts +++ b/backend/functions/src/config/index.ts @@ -2,6 +2,8 @@ import * as functions from "firebase-functions"; export const isDev = !!(process.env.FUNCTIONS_EMULATOR ?? process.env.DEV); +export const projectPath = process.env.PROJECT_PATH; + export const env = isDev ? require("../../../env.json") : functions.config(); // defaults to 60 seconds @@ -9,6 +11,18 @@ export const functionTimeoutSeconds = env.base?.timeout_seconds ? Number(env.base.timeout_seconds) : 60; +export const allowedOrigins = ["http://localhost:3000"]; + +// add any additional origins +if (env.base?.origins) { + allowedOrigins.push( + ...env.base.origins + .split(",") + .map((origin) => origin.trim()) + .filter((origin) => origin) + ); +} + export const giraffeqlOptions = { debug: !!isDev, lookupValue: true, diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index a3aa7e0..af9667a 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -5,7 +5,12 @@ admin.initializeApp(); import { initializeGiraffeql, sendErrorResponse } from "giraffeql"; import "./schema"; -import { env, functionTimeoutSeconds, giraffeqlOptions } from "./config"; +import { + allowedOrigins, + env, + functionTimeoutSeconds, + giraffeqlOptions, +} from "./config"; import { validateToken, validateApiKey } from "./helpers/auth"; import { CustomSchemaGenerator } from "./helpers/schema"; @@ -14,17 +19,6 @@ const app = express(); // app.use(express.json()); -- apparently not needed on cloud functions -const allowedOrigins = ["http://localhost:3000"]; -// add any additional origins -if (env.base?.origins) { - allowedOrigins.push( - ...env.base.origins - .split(",") - .map((origin) => origin.trim()) - .filter((origin) => origin) - ); -} - // extract the user ID from all requests. app.use(async function (req, res, next) { try { @@ -50,11 +44,18 @@ app.use(async function (req, res, next) { "Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control" ); + res.header("Access-Control-Expose-Headers", "X-Api-Version"); + res.header( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS" ); + // if env.base.version is set, send that as a header + if (env.base?.version) { + res.header("x-api-version", env.base.version); + } + const apiKey = req.get("x-api-key"); if (apiKey) { diff --git a/backend/functions/src/schema/core/helpers/resolver.ts b/backend/functions/src/schema/core/helpers/resolver.ts index 77681f5..7631cfa 100644 --- a/backend/functions/src/schema/core/helpers/resolver.ts +++ b/backend/functions/src/schema/core/helpers/resolver.ts @@ -430,7 +430,8 @@ function retrieveAllRequiredFields( throw new Error(`Misconfigured giraffeql`); } - if (resolverNode.typeDef.requiredSqlFields) { + // only add the requiredSqlFields if it's not a dataloaded field + if (resolverNode.typeDef.requiredSqlFields && !isDataloader) { resolverNode.typeDef.requiredSqlFields .map((requiredField) => fieldPath.length @@ -443,8 +444,8 @@ function retrieveAllRequiredFields( } resolverNode.typeDef.sqlOptions?.joinType; - // if nested, traverse the tree - if (resolverNode.nested) { + // if nested and not dataloader, traverse the tree + if (resolverNode.nested && !isDataloader) { retrieveAllRequiredFields( resolverNode.nested, !!resolverNode.typeDef.sqlOptions, diff --git a/backend/functions/src/schema/models/file/typeDef.ts b/backend/functions/src/schema/models/file/typeDef.ts index fdf9bb0..9b95ae5 100644 --- a/backend/functions/src/schema/models/file/typeDef.ts +++ b/backend/functions/src/schema/models/file/typeDef.ts @@ -34,6 +34,14 @@ export default new GiraffeqlObjectType( allowNull: false, typeDefOptions: { addable: false, updateable: false }, }), + servingUrl: { + type: Scalars.url, + allowNull: false, + requiredSqlFields: ["location"], + resolver: ({ parentValue }) => { + return `${env.serve_image.cdn_url}/${parentValue.location}`; + }, + }, downloadUrl: { type: Scalars.url, allowNull: false, diff --git a/backend/functions/src/scripts/executeAdminScript.ts b/backend/functions/src/scripts/executeAdminScript.ts new file mode 100644 index 0000000..10b10d4 --- /dev/null +++ b/backend/functions/src/scripts/executeAdminScript.ts @@ -0,0 +1,8 @@ +import "../schema"; +// import { Admin } from "../schema/services"; + +console.log("start"); + +(async () => { + console.log("done"); +})(); diff --git a/frontend/components/common/versionCheckText.vue b/frontend/components/common/versionCheckText.vue index 703b3c4..23cb402 100644 --- a/frontend/components/common/versionCheckText.vue +++ b/frontend/components/common/versionCheckText.vue @@ -1,8 +1,10 @@ - + diff --git a/frontend/components/table/nameAvatarColumn.vue b/frontend/components/table/nameAvatarColumn.vue index 74ba0e7..a5eb570 100644 --- a/frontend/components/table/nameAvatarColumn.vue +++ b/frontend/components/table/nameAvatarColumn.vue @@ -1,7 +1,10 @@