Skip to content

Commit

Permalink
Various experimental changes
Browse files Browse the repository at this point in the history
  • Loading branch information
big213 committed Mar 20, 2022
1 parent 61f62b3 commit 571a469
Show file tree
Hide file tree
Showing 68 changed files with 860 additions and 672 deletions.
1 change: 1 addition & 0 deletions .github/workflows/frontend-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
SITE_CONTACT_EMAIL: [email protected]
SITE_DISCORD_LINK: https://discord.gg/CpSWfub9y6
SITE_GITHUB_REPOSITORY_URL: https://github.com/big213/giraffeql.com
LOGO_HAS_LIGHT_VARIANT:
- name: Deploy to Firebase
uses: w9jds/firebase-action@master
with:
Expand Down
2 changes: 1 addition & 1 deletion backend/deploy.md.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ firebase functions:config:set pg.user="user" pg.password="password" pg.database=

# set base config

firebase functions:config:set base.origins="https://example.com"
firebase functions:config:set base.origins="https://example.com" base.timeout_seconds="60"

# set serveImage config

Expand Down
3 changes: 2 additions & 1 deletion backend/env.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"cache_bucket": "giraffeql-boilerplate.appspot.com/cache"
},
"base": {
"origins": "https://boilerplate.giraffeql.com"
"origins": "https://boilerplate.giraffeql.com",
"timeout_seconds": "60"
}
}
3 changes: 2 additions & 1 deletion backend/functions/src/schema/core/helpers/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,8 @@ export async function updateTableRow(
// handle set fields and convert to actual sql fields, if aliased
const sqlFields = {};
for (const fieldname in sqlQuery.fields) {
const sqlOptions = currentTypeDef.definition.fields[fieldname].sqlOptions;
const sqlOptions =
currentTypeDef.definition.fields[fieldname]?.sqlOptions;
if (!sqlOptions) throw new Error(`'${fieldname}' is not a sql field`);

sqlFields[sqlOptions.field ?? fieldname] = sqlOptions.parseValue
Expand Down
36 changes: 30 additions & 6 deletions backend/functions/src/schema/core/helpers/typeDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,19 +465,42 @@ export function generateEnumField(

export function generateKeyValueArray(
params: {
name?: string;
valueType?: GiraffeqlScalarType;
allowNullValue?: boolean;
} & GenerateFieldParams
) {
const {
name,
valueType = Scalars.string,
allowNullValue = false,
...remainingParams
} = params;

let finalObjectName: string;

// if name is defined, check if it is not already defined
if (name) {
finalObjectName = name;
if (inputTypeDefs.has(name)) {
throw new GiraffeqlInitializationError({
message: `Input type with name: '${name}' already exists`,
});
}
} else {
finalObjectName = "keyValueObject";
let iteration = 0;
// if no name, generate an appropriate name by adding an incrementing number
while (inputTypeDefs.has(finalObjectName)) {
finalObjectName += String(iteration);
iteration++;
}
}

// generate the input type if not exists
if (!inputTypeDefs.has("keyValueObject")) {
if (!inputTypeDefs.has(finalObjectName)) {
new GiraffeqlInputType({
name: "keyValueObject",
name: finalObjectName,
description: "Object Input with key and value properties",
fields: {
key: new GiraffeqlInputFieldType({
Expand All @@ -486,16 +509,17 @@ export function generateKeyValueArray(
}),
value: new GiraffeqlInputFieldType({
type: valueType,
required: !allowNullValue,
required: true,
allowNull: allowNullValue,
}),
},
});
}

// generate the object type if not exists
if (!objectTypeDefs.has("keyValueObject")) {
if (!objectTypeDefs.has(finalObjectName)) {
new GiraffeqlObjectType({
name: "keyValueObject",
name: finalObjectName,
description: "Object with key and value properties",
fields: {
key: {
Expand All @@ -512,7 +536,7 @@ export function generateKeyValueArray(

return generateArrayField({
allowNullElement: false,
type: new GiraffeqlObjectTypeLookup("keyValueObject"),
type: new GiraffeqlObjectTypeLookup(finalObjectName),
...remainingParams,
});
}
Expand Down
15 changes: 15 additions & 0 deletions backend/functions/src/schema/core/services/normal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import {
SqlOrderByObject,
SqlSelectQuery,
SqlSelectQueryObject,
SqlSumQuery,
SqlUpdateQuery,
SqlWhereFieldOperator,
SqlWhereObject,
sumTableRows,
updateTableRow,
} from "../helpers/sql";
import { permissionsCheck } from "../helpers/permissions";
Expand Down Expand Up @@ -687,6 +689,19 @@ export class NormalService extends BaseService {
return recordsCount;
}

// sum a field for the records matching the criteria
async sumSqlRecord(
sqlQuery: Omit<SqlSumQuery, "table">,
fieldPath?: string[]
): Promise<any> {
const sum = await sumTableRows({
...sqlQuery,
table: this.typename,
});

return sum;
}

async createSqlRecord(
sqlQuery: Omit<SqlInsertQuery, "table">,
fieldPath?: string[]
Expand Down
6 changes: 4 additions & 2 deletions backend/functions/src/schema/models/github/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,15 @@ query {
repository(name: "${env.github.repository}") {
latestRelease {
tagName
createdAt
}
}
}
}
}
`);

return response.viewer.organization.repository.latestRelease?.tagName;
return response.viewer.organization.repository.latestRelease;
} else {
// if no organization specified, lookup repository directly
const response = await sendGraphqlRequest(`
Expand All @@ -145,13 +146,14 @@ query {
repository(name: "${env.github.repository}") {
latestRelease {
tagName
createdAt
}
}
}
}
`);

return response.viewer.repository.latestRelease?.tagName;
return response.viewer.repository.latestRelease;
}
} catch (err) {
throw new GiraffeqlBaseError({
Expand Down
5 changes: 3 additions & 2 deletions backend/functions/src/schema/models/user/rootResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ export default {
allowNull: false,
type: User.typeDefLookup,
resolver: ({ req, fieldPath, args, query }) => {
if (!req.user?.id) throw new Error("Login required");
if (!req.user) throw new Error("Login required");

return User.getRecord({
req,
fieldPath,
args: { id: req.user?.id },
args: { id: req.user!.id },
query,
isAdmin: true,
});
Expand Down
35 changes: 22 additions & 13 deletions backend/functions/src/schema/models/user/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,15 @@ export class UserService extends PaginatedService {
// args should be validated already
const validatedArgs = <any>args;
//check if record exists
const item = await this.getFirstSqlRecord({
select: ["id", "role", "firebaseUid"],
where: {
id: data!.id,
const item = await this.getFirstSqlRecord(
{
select: ["id", "role", "firebaseUid"],
where: {
id: data!.id,
},
},
});
fieldPath
);

// make sure email field, if provided, matches the firebase user email
if ("email" in validatedArgs) {
Expand Down Expand Up @@ -260,10 +263,13 @@ export class UserService extends PaginatedService {
// args should be validated already
const validatedArgs = <any>args;
// check if record exists, get ID
const item = await this.getFirstSqlRecord({
select: ["id", "role", "firebaseUid"],
where: validatedArgs.item,
});
const item = await this.getFirstSqlRecord(
{
select: ["id", "role", "firebaseUid"],
where: validatedArgs.item,
},
fieldPath
);

// convert any lookup/joined fields into IDs
await this.handleLookupArgs(validatedArgs.fields, fieldPath);
Expand Down Expand Up @@ -333,10 +339,13 @@ export class UserService extends PaginatedService {
const validatedArgs = <any>args;

// confirm existence of item and get ID
const item = await this.getFirstSqlRecord({
select: ["id", "firebaseUid"],
where: validatedArgs,
});
const item = await this.getFirstSqlRecord(
{
select: ["id", "firebaseUid"],
where: validatedArgs,
},
fieldPath
);

// first, fetch the requested query, if any
const requestedResults = this.isEmptyQuery(query)
Expand Down
6 changes: 5 additions & 1 deletion frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ VER=DEV

#required
SITE_NAME="Giraffeql Boilerplate"
SITE_DESCRIPTION="Giraffeql Boilerplate is a basic boilerplate site for showcasing the Giraffeql API querying language in a basic and extendable implementation."
SITE_DESCRIPTION="Giraffeql Boilerplate is a basic boilerplate site for showcasing the Giraffeql API querying language in a basic and extendable implementation"

#optional
SITE_IMAGE_URL=https://cdn.giraffeql.com/permanent/android-chrome-512x512.png
SITE_CONTACT_EMAIL=[email protected]
SITE_DISCORD_LINK=https://discord.gg/CpSWfub9y6
SITE_GITHUB_REPOSITORY_URL=https://github.com/big213/giraffeql-boilerplate

#logo
#if this is enabled, must have a variant for logo-vertical-light.png and logo-horizontal-light.png in static folder
#LOGO_HAS_LIGHT_VARIANT=true

#dev
API_URL=http://localhost:5001/giraffeql-boilerplate/us-central1/api
IMAGE_SERVING_URL=https://cdn.giraffeql.com
Expand Down
30 changes: 21 additions & 9 deletions frontend/components/common/versionCheckText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<div>
<a @click="copyIdTokenToClipboard()">{{ getBuildInfo() }}</a>
<v-icon
v-if="hasNewerVersion"
v-if="hasNewerVersion && showNewerVersionIcon"
title="A newer version of this site is available. Click to reload."
color="pink"
@click="reloadPage()"
>mdi-sync-alert</v-icon
>
<v-snackbar
v-model="open"
v-model="snackbarStatus"
multi-line
bottom
right
Expand All @@ -27,7 +27,7 @@
>
Refresh
</v-btn>
<v-btn color="pink" text v-bind="attrs" @click="open = false">
<v-btn color="pink" text v-bind="attrs" @click="snackbarStatus = false">
Close
</v-btn>
</template>
Expand All @@ -44,10 +44,11 @@ import 'firebase/auth'
export default {
data() {
return {
open: false,
snackbarStatus: false,
currentVersion: null,
latestVersion: null,
hasNewerVersion: false,
showNewerVersionIcon: false,
}
},
Expand All @@ -56,17 +57,28 @@ export default {
executeGiraffeql(this, {
getRepositoryLatestVersion: true,
}).then((res) => {
this.latestVersion = res
if (this.latestVersion && this.currentVersion !== this.latestVersion) {
this.latestVersion = res.tagName
if (this.hasNewerVersion) {
// only open the snackbar if not DEV
if (this.currentVersion !== 'DEV') {
this.open = true
// only show the snackbar if it has been at least 3 minutes since the release. if it has been more than 3 mins, show immediately
setTimeout(() => {
this.snackbarStatus = true
this.showNewerVersionIcon = true
}, Math.min(3 * 60 * 1000, Math.max(0, 3 * 60 * 1000 - (new Date() - new Date(res.createdAt)))))
} else {
this.showNewerVersionIcon = true
}
this.hasNewerVersion = true
}
})
},
computed: {
hasNewerVersion() {
return this.latestVersion && this.currentVersion !== this.latestVersion
},
},
methods: {
reloadPage() {
location.reload()
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/interface/crud/crudRecordInterface.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<v-toolbar flat color="accent" dense>
<v-icon left>{{ icon || recordInfo.icon || 'mdi-domain' }}</v-icon>
<v-toolbar-title>{{
title || `${recordInfo.pluralName}`
title || recordInfo.title || recordInfo.pluralName
}}</v-toolbar-title>
<v-divider
v-if="recordInfo.addOptions"
Expand Down
20 changes: 9 additions & 11 deletions frontend/components/interface/crud/shareRecordInterface.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@
</template>

<script>
import { copyToClipboard, generateRecordRouteObject } from '~/services/base'
import { copyToClipboard, generateViewRecordRoute } from '~/services/base'
export default {
props: {
selectedItem: {
type: Object,
default: () => ({}),
},
recordInfo: {
type: Object,
Expand All @@ -47,18 +46,17 @@ export default {
computed: {
shareUrl() {
const routeObject = generateRecordRouteObject(
this.recordInfo.typename,
this.recordInfo.routeName,
this.selectedItem.id
)
return this.selectedItem && this.recordInfo.shareOptions && routeObject
? window.location.origin + this.$router.resolve(routeObject).href
return this.selectedItem
? window.location.origin +
generateViewRecordRoute(this, {
typename: this.recordInfo.typename,
routeType: 'i',
id: this.selectedItem.id,
})
: ''
},
itemIdentifier() {
return this.recordInfo.renderItem
return this.recordInfo.renderItem && this.selectedItem
? this.recordInfo.renderItem(this.selectedItem)
: null
},
Expand Down
Loading

0 comments on commit 571a469

Please sign in to comment.