mirror of
https://github.com/rowyio/rowy.git
synced 2026-07-13 13:59:05 +02:00
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
# Stage 1
|
||||
FROM node:8 as react-build
|
||||
WORKDIR /www
|
||||
COPY . ./
|
||||
RUN yarn
|
||||
RUN yarn build
|
||||
|
||||
# Stage 2 - the production environment
|
||||
FROM nginx:alpine
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=react-build /app/build /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
38
app.json
Normal file
38
app.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "foo-app",
|
||||
"env": {
|
||||
"BACKGROUND_COLOR": {
|
||||
"description": "specify a css color",
|
||||
"value": "#fefefe",
|
||||
"required": false
|
||||
},
|
||||
"TITLE": {
|
||||
"description": "title for your site"
|
||||
},
|
||||
"APP_SECRET": {
|
||||
"generator": "secret"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"allow-unauthenticated": false,
|
||||
"memory": "512Mi",
|
||||
"cpu": "1"
|
||||
},
|
||||
"build": {
|
||||
"skip": false
|
||||
},
|
||||
"hooks": {
|
||||
"prebuild": {
|
||||
"commands": ["./my-custom-prebuild"]
|
||||
},
|
||||
"postbuild": {
|
||||
"commands": ["./my-custom-postbuild"]
|
||||
},
|
||||
"precreate": {
|
||||
"commands": ["echo 'test'"]
|
||||
},
|
||||
"postcreate": {
|
||||
"commands": ["./setup.sh"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"functions": {
|
||||
"predeploy": [
|
||||
"npm --prefix \"$RESOURCE_DIR\" run fetchConfig",
|
||||
"npm --prefix \"$RESOURCE_DIR\" run lint",
|
||||
"npm --prefix \"$RESOURCE_DIR\" run build"
|
||||
]
|
||||
|
||||
@@ -3,44 +3,57 @@ import * as fs from "fs";
|
||||
import * as admin from "firebase-admin";
|
||||
// Initialize Firebase Admin
|
||||
|
||||
const serviceAccount = require(`./firebase-credentials.json`);
|
||||
console.log(`Running on ${serviceAccount.project_id}`);
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
databaseURL: `https://${serviceAccount.project_id}.firebaseio.com`,
|
||||
});
|
||||
const db = admin.firestore();
|
||||
const serviceAccount = requireIfExists(`./firebase-credentials.json`);
|
||||
|
||||
const docConfig2json = async (docPath: string, jsonPath: string) => {
|
||||
const doc = await db.doc(docPath).get();
|
||||
const data = doc.data();
|
||||
const jsonData = JSON.stringify(data ? data.config : "");
|
||||
fs.writeFileSync(jsonPath, jsonData);
|
||||
};
|
||||
function requireIfExists(module) {
|
||||
try {
|
||||
return require(module);
|
||||
} catch (error) {
|
||||
// pass and try next file
|
||||
console.log("serviceAccount json not found");
|
||||
return false;
|
||||
}
|
||||
// throw('None of the provided modules exist.')
|
||||
}
|
||||
if (serviceAccount) {
|
||||
console.log(`Running on ${serviceAccount.project_id}`);
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
databaseURL: `https://${serviceAccount.project_id}.firebaseio.com`,
|
||||
});
|
||||
const db = admin.firestore();
|
||||
|
||||
// Initialize Cloud Firestore Database
|
||||
const docConfig2json = async (docPath: string, jsonPath: string) => {
|
||||
const doc = await db.doc(docPath).get();
|
||||
const data = doc.data();
|
||||
const jsonData = JSON.stringify(data ? data.config : "[]");
|
||||
fs.writeFileSync(jsonPath, jsonData);
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_HISTORY_",
|
||||
"./src/history/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_ALGOLIA_",
|
||||
"./src/algolia/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_COLLECTION_SYNC_",
|
||||
"./src/collectionSync/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_SNAPSHOT_SYNC_",
|
||||
"./src/snapshotSync/config.json"
|
||||
);
|
||||
return true;
|
||||
};
|
||||
// Initialize Cloud Firestore Database
|
||||
|
||||
main()
|
||||
.catch(err => console.log(err))
|
||||
.then(() => console.log("this will succeed"))
|
||||
.catch(() => "obligatory catch");
|
||||
const main = async () => {
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_HISTORY_",
|
||||
"./src/history/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_ALGOLIA_",
|
||||
"./src/algolia/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_COLLECTION_SYNC_",
|
||||
"./src/collectionSync/config.json"
|
||||
);
|
||||
await docConfig2json(
|
||||
"_FIRETABLE_/_SETTINGS_/_CONFIG_/_SNAPSHOT_SYNC_",
|
||||
"./src/snapshotSync/config.json"
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
main()
|
||||
.catch(err => console.log(err))
|
||||
.then(() => console.log("this will succeed"))
|
||||
.catch(() => "obligatory catch");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
"serve": "npm run build && firebase serve --only functions",
|
||||
"shell": "npm run build && firebase functions:shell",
|
||||
"start": "npm run shell",
|
||||
"deploy": "firebase deploy",
|
||||
"deploy": "firebase deploy --only functions:exportTable",
|
||||
"deployFT": "firebase deploy",
|
||||
"logs": "firebase functions:log"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -24,7 +24,6 @@ const cloneDoc = (targetCollection: string, fieldsToSync: string[]) => (
|
||||
) => {
|
||||
const docId = snapshot.id;
|
||||
const docData = snapshot.data();
|
||||
console.log(docData);
|
||||
if (!docData) return false; // returns if theres no data in the doc
|
||||
const syncData = fieldsToSync.reduce(docReducer(docData), {});
|
||||
if (Object.keys(syncData).length === 0) return false; // returns if theres nothing to sync
|
||||
@@ -33,6 +32,10 @@ const cloneDoc = (targetCollection: string, fieldsToSync: string[]) => (
|
||||
/\{\{(.*?)\}\}/g,
|
||||
replacer(docData)
|
||||
);
|
||||
if (collectionPath.includes("//")) {
|
||||
console.log(`${collectionPath} is an invalid collection path`);
|
||||
return false;
|
||||
}
|
||||
db.collection(collectionPath)
|
||||
.doc(docId)
|
||||
.set({ ...syncData, syncedAt: new Date() }, { merge: true })
|
||||
@@ -57,18 +60,17 @@ const syncDoc = (targetCollection: string, fieldsToSync: string[]) => async (
|
||||
/\{\{(.*?)\}\}/g,
|
||||
replacer(docData)
|
||||
);
|
||||
|
||||
if (collectionPath.includes("//")) {
|
||||
console.log(`${collectionPath} is an invalid collection path`);
|
||||
return false;
|
||||
}
|
||||
if (Object.keys(syncData).length === 0) return false; // returns if theres nothing to sync
|
||||
const targetDoc = await db
|
||||
.collection(collectionPath)
|
||||
.doc(docId)
|
||||
.get();
|
||||
if (!targetDoc.exists) return false;
|
||||
const targetDocData = targetDoc.data();
|
||||
console.log(`syncing ${docId}`, targetDoc.exists, {
|
||||
targetDocData,
|
||||
docData,
|
||||
syncData,
|
||||
});
|
||||
db.collection(collectionPath)
|
||||
.doc(docId)
|
||||
.update({ ...syncData, syncedAt: new Date() })
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export { exportTable } from "./export";
|
||||
|
||||
import algoliaFnsGenerator from "./algolia";
|
||||
import * as algoliaConfig from "./algolia/config.json";
|
||||
import collectionSyncFnsGenerator from "./collectionSync";
|
||||
@@ -12,31 +14,30 @@ import * as collectionHistoryConfig from "./history/config.json";
|
||||
import permissionControlFnsGenerator from "./permissions";
|
||||
import * as permissionsConfig from "./permissions/config.json";
|
||||
|
||||
import synonymsFnsGenerator from "./synonyms";
|
||||
import synonymsConfig from "./synonyms/config";
|
||||
|
||||
export { exportTable } from "./export";
|
||||
export { triggerCloudBuild } from "./buildTriggers";
|
||||
export { scheduledFirestoreBackup, callableFirestoreBackup } from "./backup";
|
||||
import * as callableFns from "./callable";
|
||||
|
||||
export const callable = callableFns;
|
||||
export const FT_algolia = algoliaConfig.reduce((acc: any, collection) => {
|
||||
export const FT_algolia = algoliaConfig.reduce((acc: any, collection: any) => {
|
||||
return { ...acc, [collection.name]: algoliaFnsGenerator(collection) };
|
||||
}, {});
|
||||
|
||||
export const FT_sync = collectionSyncConfig.reduce((acc: any, collection) => {
|
||||
return {
|
||||
...acc,
|
||||
[`${`${`${collection.source}`
|
||||
.replace(/\//g, "_")
|
||||
.replace(/_{.*?}_/g, "_")}`}2${`${`${collection.target}`
|
||||
.replace(/\//g, "_")
|
||||
.replace(/_{.*?}_/g, "_")}`}`]: collectionSyncFnsGenerator(collection),
|
||||
};
|
||||
}, {});
|
||||
export const FT_sync = collectionSyncConfig.reduce(
|
||||
(acc: any, collection: any) => {
|
||||
return {
|
||||
...acc,
|
||||
[`${`${`${collection.source}`
|
||||
.replace(/\//g, "_")
|
||||
.replace(/_{.*?}_/g, "_")}`}2${`${`${collection.target}`
|
||||
.replace(/\//g, "_")
|
||||
.replace(/_{.*?}_/g, "_")}`}`]: collectionSyncFnsGenerator(collection),
|
||||
};
|
||||
},
|
||||
{}
|
||||
);
|
||||
export const FT_snapshotSync = snapshotSyncConfig.reduce(
|
||||
(acc: any, collection) => {
|
||||
(acc: any, collection: any) => {
|
||||
if (collection.fnName) {
|
||||
return {
|
||||
...acc,
|
||||
@@ -56,7 +57,7 @@ export const FT_snapshotSync = snapshotSyncConfig.reduce(
|
||||
);
|
||||
|
||||
export const FT_history = collectionHistoryConfig.reduce(
|
||||
(acc: any, collection) => {
|
||||
(acc: any, collection: any) => {
|
||||
return {
|
||||
...acc,
|
||||
[collection.name
|
||||
@@ -68,7 +69,7 @@ export const FT_history = collectionHistoryConfig.reduce(
|
||||
);
|
||||
|
||||
export const FT_permissions = permissionsConfig.reduce(
|
||||
(acc: any, collection) => {
|
||||
(acc: any, collection: any) => {
|
||||
return {
|
||||
...acc,
|
||||
[collection.name]: permissionControlFnsGenerator(collection),
|
||||
@@ -76,12 +77,3 @@ export const FT_permissions = permissionsConfig.reduce(
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
export const FT_synonyms = synonymsConfig.reduce((acc: any, collection) => {
|
||||
return {
|
||||
...acc,
|
||||
[collection.name
|
||||
.replace(/\//g, "_")
|
||||
.replace(/_{.*?}_/g, "_")]: synonymsFnsGenerator(collection),
|
||||
};
|
||||
}, {});
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{ "name": "userPermissions", "customTokenFields": ["regions", "roles"] }]
|
||||
[]
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
import * as algoliasearch from "algoliasearch";
|
||||
|
||||
import { env } from "../config";
|
||||
import * as _ from "lodash";
|
||||
const client = algoliasearch(env.algolia.app, env.algolia.key);
|
||||
|
||||
const generateAlgoliaKey = (fieldName: string, value: string) =>
|
||||
client.generateSecuredApiKey(
|
||||
env.algolia.search, // Make sure to use a search key
|
||||
{
|
||||
filters: `${fieldName}:${value}`,
|
||||
}
|
||||
);
|
||||
|
||||
const cohort2algoliaKey = (cohort: string) =>
|
||||
generateAlgoliaKey("cohort", cohort);
|
||||
|
||||
const tableConnect2ids = records => {
|
||||
if (records) {
|
||||
return records.map(r => r.snapshot.objectID);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
const cohort2region = (cohort: string) =>
|
||||
cohort.toUpperCase().replace(/\d+.*$/, "");
|
||||
|
||||
const locations = [
|
||||
{ location: "Sydney", region: "SYD" },
|
||||
{ location: "Singapore", region: "SG" },
|
||||
{ location: "Amsterdam", region: "AMS" },
|
||||
{ location: "Oslo", region: "OSL" },
|
||||
{ location: "New York", region: "NYC" },
|
||||
{ location: "London", region: "LON" },
|
||||
{ location: "Nairobi", region: "NAI" },
|
||||
{ location: "Stockholm", region: "STO" },
|
||||
];
|
||||
|
||||
const location2region = (location: string) => {
|
||||
const _location = _.find(locations, { location });
|
||||
|
||||
return _location ? _location.region : "GLOBAL";
|
||||
};
|
||||
const cohort2location = (cohort: string) => {
|
||||
const _region = cohort2region(cohort);
|
||||
switch (_region) {
|
||||
case "SYD":
|
||||
return "Sydney";
|
||||
case "SG":
|
||||
return "Singapore";
|
||||
case "AMS":
|
||||
return "Amsterdam";
|
||||
case "OSL":
|
||||
return "Oslo";
|
||||
case "LON":
|
||||
return "London";
|
||||
case "STO":
|
||||
return "Stockholm";
|
||||
case "NYC":
|
||||
return "New York";
|
||||
case "NAI":
|
||||
return "Nairobi";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const cohort2regionCollections = (collections: string[]) =>
|
||||
collections.map(collection => ({
|
||||
name: collection,
|
||||
groups: [
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
const config = [
|
||||
{
|
||||
name: "advisors",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "location",
|
||||
synonymField: "region",
|
||||
transformer: location2region,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "icManagement/{icId}/icMembers/{memberId}/votes",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "team",
|
||||
synonymField: "teamName",
|
||||
transformer: team => (team[0] ? team[0].teamName : ""),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "cohorts",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "algoliaKey",
|
||||
transformer: (cohort: string) =>
|
||||
client.generateSecuredApiKey(
|
||||
env.algolia.search, // Make sure to use a search key
|
||||
{
|
||||
filters: `cohort:${cohort} OR cohort:Global`,
|
||||
restrictIndices: [
|
||||
"teams",
|
||||
"founders",
|
||||
"students",
|
||||
"hubResources",
|
||||
"advisors",
|
||||
"partnerships",
|
||||
],
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "demoDayAlgoliaKey",
|
||||
transformer: (cohort: string) =>
|
||||
client.generateSecuredApiKey(
|
||||
env.algolia.search, // Make sure to use a search key
|
||||
{
|
||||
filters: `cohort:${cohort} AND showOnDemoDayWebsite:true`,
|
||||
restrictIndices: ["portfolio"],
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
listenerField: "location",
|
||||
synonymField: "demoDayAntlerBiosAlgoliaKey",
|
||||
transformer: (location: string) =>
|
||||
client.generateSecuredApiKey(
|
||||
env.algolia.search, // Make sure to use a search key
|
||||
{
|
||||
filters: `location:"${location}"`,
|
||||
restrictIndices: ["antlerBios"],
|
||||
}
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "icManagement",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "icPage",
|
||||
transformer: (cohort, doc) => {
|
||||
if (doc.icType === "IC" || doc.icType === "Delayed IC") {
|
||||
return `https://firepage.antler.co/IC/${cohort}`;
|
||||
} else return "";
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "algoliaKey",
|
||||
transformer: cohort2algoliaKey,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "portfolio",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "location",
|
||||
transformer: cohort2location,
|
||||
},
|
||||
{
|
||||
listenerField: "id",
|
||||
synonymField: "onePager",
|
||||
transformer: id => `https://firepage.antler.co/portfolio/${id}`,
|
||||
},
|
||||
{
|
||||
listenerField: "coach",
|
||||
synonymField: "coachID",
|
||||
transformer: tableConnect2ids,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "teams",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "coach",
|
||||
synonymField: "coachID",
|
||||
transformer: tableConnect2ids,
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
{
|
||||
listenerField: "id",
|
||||
synonymField: "ddPage",
|
||||
transformer: id => `https://firepage.antler.co/DD/${id}`,
|
||||
},
|
||||
{
|
||||
isForced: true,
|
||||
listenerField: "icResult",
|
||||
synonymField: "isDecided",
|
||||
transformer: icResult => {
|
||||
if (icResult && ["Yes", "No"].includes(icResult)) return true;
|
||||
else return false;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "profiles",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "email",
|
||||
synonymField: "isInternal",
|
||||
transformer: email => email.includes("@antler.co"),
|
||||
},
|
||||
{
|
||||
listenerField: "cohort",
|
||||
synonymField: "region",
|
||||
transformer: cohort2region,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "demodays",
|
||||
groups: [
|
||||
{
|
||||
listenerField: "cohortDoc",
|
||||
synonymField: "cohort",
|
||||
transformer: cohortDoc => cohortDoc?.[0]?.snapshot?.cohort,
|
||||
},
|
||||
],
|
||||
},
|
||||
...cohort2regionCollections([
|
||||
"hubResources",
|
||||
"sprintSubmissions",
|
||||
"trackoutApplications",
|
||||
"portfolioEnquiries",
|
||||
]),
|
||||
];
|
||||
export default config;
|
||||
@@ -1,95 +0,0 @@
|
||||
import * as functions from "firebase-functions";
|
||||
|
||||
import { db } from "../config";
|
||||
|
||||
type synonymGroup = {
|
||||
isForced: boolean | undefined;
|
||||
listenerField: string;
|
||||
synonymField: string;
|
||||
transformer: Function;
|
||||
};
|
||||
|
||||
const synonyms = (docData, groups: synonymGroup[]) =>
|
||||
groups.reduce(async (acc: any, currGroup) => {
|
||||
const newValue = await currGroup.transformer(
|
||||
docData[currGroup.listenerField],
|
||||
docData
|
||||
);
|
||||
if (
|
||||
docData[currGroup.listenerField] &&
|
||||
docData[currGroup.synonymField] !== newValue
|
||||
) {
|
||||
return {
|
||||
...(await acc),
|
||||
[currGroup.synonymField]: newValue,
|
||||
};
|
||||
} else return await acc;
|
||||
}, {});
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const addSynonymOnUpdate = (groups: synonymGroup[]) => async (
|
||||
change: functions.Change<FirebaseFirestore.DocumentSnapshot>
|
||||
) => {
|
||||
const beforeData = change.before.data();
|
||||
const afterData = change.after.data();
|
||||
|
||||
if (!beforeData || !afterData) {
|
||||
return false;
|
||||
}
|
||||
const changedGroups = groups.reduce((acc: synonymGroup[], currGroup) => {
|
||||
if (
|
||||
currGroup.isForced ||
|
||||
beforeData[currGroup.listenerField] !== afterData[currGroup.listenerField]
|
||||
) {
|
||||
return [...acc, currGroup];
|
||||
} else {
|
||||
return acc;
|
||||
}
|
||||
}, []);
|
||||
if (changedGroups.length === 0) {
|
||||
return false; // no changes detected
|
||||
}
|
||||
const updates = await synonyms(
|
||||
{ ...afterData, id: change.after.id },
|
||||
changedGroups
|
||||
);
|
||||
if (Object.values(updates).length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
const docPath = change.after.ref.path;
|
||||
return db.doc(docPath).update(updates);
|
||||
}
|
||||
};
|
||||
|
||||
const addSynonymOnCreate = (groups: synonymGroup[]) => async (
|
||||
snapshot: FirebaseFirestore.DocumentSnapshot
|
||||
) => {
|
||||
const docData = snapshot.data();
|
||||
if (!docData) {
|
||||
return false;
|
||||
}
|
||||
const updates = await synonyms({ ...docData, id: snapshot.id }, groups);
|
||||
if (Object.keys(updates).length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
const docPath = snapshot.ref.path;
|
||||
return db.doc(docPath).update(updates);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param collection configuration object
|
||||
*/
|
||||
const synonymsFnsGenerator = collection => ({
|
||||
onCreate: functions.firestore
|
||||
.document(`${collection.name}/{docId}`)
|
||||
.onCreate(addSynonymOnCreate(collection.groups)),
|
||||
onUpdate: functions.firestore
|
||||
.document(`${collection.name}/{docId}`)
|
||||
.onUpdate(addSynonymOnUpdate(collection.groups)),
|
||||
});
|
||||
|
||||
export default synonymsFnsGenerator;
|
||||
@@ -12,10 +12,14 @@ steps:
|
||||
entrypoint: yarn
|
||||
args: ["install"]
|
||||
dir: "cloud_functions/functions"
|
||||
- name: node:10.15.1
|
||||
entrypoint: yarn
|
||||
args: ["fetchConfig"]
|
||||
dir: "cloud_functions/functions"
|
||||
- name: node:10.15.1
|
||||
entrypoint: yarn
|
||||
args:
|
||||
- "deploy"
|
||||
- "deployFT"
|
||||
- "--project"
|
||||
- "${_PROJECT_ID}"
|
||||
- "--token"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { Suspense } from "react";
|
||||
import clsx from "clsx";
|
||||
import { FormatterProps } from "react-data-grid";
|
||||
|
||||
import { makeStyles, createStyles } from "@material-ui/core";
|
||||
|
||||
Reference in New Issue
Block a user