From b30a0a4108e339ff66370d84a40f797e0e31d861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20Lis=C3=A9?= Date: Tue, 18 May 2021 18:41:00 -0700 Subject: [PATCH] NRPT-707: Add feature flags (#861) --- .../src/app/import/import.component.ts | 3 ++ angular/projects/admin-nrpti/src/env.js | 3 ++ api/migrations/20210507195356-featureFlag.js | 43 +++++++++++++++++++ api/src/controllers/config.js | 7 ++- api/src/models/featureFlag.js | 20 +++++++++ api/src/models/index.js | 1 + 6 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 api/migrations/20210507195356-featureFlag.js create mode 100644 api/src/models/featureFlag.js diff --git a/angular/projects/admin-nrpti/src/app/import/import.component.ts b/angular/projects/admin-nrpti/src/app/import/import.component.ts index daefa2339..5d04b8407 100644 --- a/angular/projects/admin-nrpti/src/app/import/import.component.ts +++ b/angular/projects/admin-nrpti/src/app/import/import.component.ts @@ -99,6 +99,9 @@ export class ImportComponent implements OnInit, OnDestroy { self.importService.refreshData(); }); + // Feature flagging + this.buttonActions['nris-emli'] = this.configService.config['FEATURE_FLAG']['nris-emli-importer']; + this.disableSourceSystem(); } diff --git a/angular/projects/admin-nrpti/src/env.js b/angular/projects/admin-nrpti/src/env.js index 15cd4d334..7edea80d0 100644 --- a/angular/projects/admin-nrpti/src/env.js +++ b/angular/projects/admin-nrpti/src/env.js @@ -18,6 +18,9 @@ // This is a hardcoded variable that does not come from the backend window.__env.APPLICATION = 'NRPTI'; + window.__env.FEATURE_FLAG = { + "nris-emli-importer": false + }; // Import component defaults window.__env.IMPORT_TABLE_INTERVAL = 15000; diff --git a/api/migrations/20210507195356-featureFlag.js b/api/migrations/20210507195356-featureFlag.js new file mode 100644 index 000000000..06fc9c96a --- /dev/null +++ b/api/migrations/20210507195356-featureFlag.js @@ -0,0 +1,43 @@ +'use strict'; + +let dbm; +let type; +let seed; + +/** + * We receive the dbmigrate dependency from dbmigrate initially. + * This enables us to not have to rely on NODE_PATH. + */ +exports.setup = function(options, seedLink) { + dbm = options.dbmigrate; + type = dbm.dataType; + seed = seedLink; +} + +exports.up = async function(db) { + console.log('**** Adding feature flag ****'); + const mClient = await db.connection.connect(db.connectionString, { native_parser: true }); + + try { + const nrpti = await mClient.collection('nrpti'); + await nrpti.insertOne({ + _schemaName: 'FeatureFlag', + data: { + "nris-emli-importer": "true" + } + }); + console.log('**** Finished adding flag ****'); + } catch (error) { + console.error(`Migration did not complete. Error processing records: ${error.message}`); + } + + mClient.close(); +} + +exports.down = function(db) { + return null; +} + +exports._meta = { + "version": 1 +} diff --git a/api/src/controllers/config.js b/api/src/controllers/config.js index bb854d9dd..c8b397112 100644 --- a/api/src/controllers/config.js +++ b/api/src/controllers/config.js @@ -7,6 +7,7 @@ const BcmiConfig = require('./config/bcmi'); const NrcedConfig = require('./config/nrced'); const LngConfig = require('./config/lng'); const NrptiConfig = require('./config/nrpti'); +const { featureFlag: FeatureFlag } = require('../models/index'); const CheckRole = function (roles, roleName, includeSysadmin = false) { if (includeSysadmin) { @@ -31,7 +32,7 @@ exports.protectedOptions = function (args, res, next) { * @returns {object} */ exports.publicGetConfig = async function (args, res, next) { - console.log("Got configuration data"); + console.log("Sent configuration data"); let configurationData = {}; configurationData['API_LOCATION'] = process.env.API_LOCATION; @@ -48,6 +49,10 @@ exports.publicGetConfig = async function (args, res, next) { configurationData['IMPORT_TABLE_INTERVAL'] = process.env.IMPORT_TABLE_INTERVAL; configurationData['DEFAULT_IMPORT_TABLE_QUERY_PARAMS'] = process.env.DEFAULT_IMPORT_TABLE_QUERY_PARAMS; + // TODO: Put this in each respective application sub-section so we can feature-flag for each app + // independently. + configurationData['FEATURE_FLAG'] = await FeatureFlag.findOne({ _schemaName: 'FeatureFlag' }); + // get project specific confguration // fetch the latest business area specific CommunicationPackage // attach it to the configuration data under "COMMUNICATIONS" diff --git a/api/src/models/featureFlag.js b/api/src/models/featureFlag.js new file mode 100644 index 000000000..e38a51e08 --- /dev/null +++ b/api/src/models/featureFlag.js @@ -0,0 +1,20 @@ +const mongoose = require('mongoose'); + +module.exports = require('../utils/model-schema-generator')( + 'FeatureFlag', + { + _schemaName: { type: String, default: 'FeatureFlag', index: true }, + data: { type: mongoose.SchemaTypes.Mixed, default: '{}' }, + + addedBy: { type: String, default: null }, + dateAdded: { type: Date, default: Date.now() }, + + updatedBy: { type: String, default: null }, + dateUpdated: { type: Date, default: null }, + + // Permissions + write: [{ type: String, trim: true, default: 'sysadmin' }], + read: [{ type: String, trim: true, default: 'public' }] + }, + 'nrpti' +); diff --git a/api/src/models/index.js b/api/src/models/index.js index 4b54bdaf4..8b45ee940 100644 --- a/api/src/models/index.js +++ b/api/src/models/index.js @@ -8,6 +8,7 @@ exports.epicProject = require('./epicProject'); exports.configData = require('./configData'); exports.mapLayerInfo = require('./mapLayerInfo'); exports.metric = require('./metric'); +exports.featureFlag = require('./featureFlag'); // master require('./master');