diff --git a/CHANGELOG.md b/CHANGELOG.md index 259196fb6..be565c8cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # Release Notes +## Version 0.28.0 +**Release Date**: 20th October 2021 +### Features +1. User / Groups View added + 1. Allow the creation / definition of local Users + 2. Allow the creation / definition of OCI Groups +2. Bastion as a Service functionality added to main design canvas. +### Bug Fixes +1. Add missing policy documentation to export to markdown. + + ## Version 0.27.1 **Release Date**: 1st October 2021 ### Bug Fixes diff --git a/okitweb/static/okit/css/okit_console.css b/okitweb/static/okit/css/okit_console.css index 0ff0b79bb..9e1b36fe4 100644 --- a/okitweb/static/okit/css/okit_console.css +++ b/okitweb/static/okit/css/okit_console.css @@ -108,9 +108,11 @@ summary:focus { } .hidden { - visibility: hidden; + position: absolute; display: none; + visibility: hidden; max-height: 0; + max-width: 0; } .okit-pointer-cursor { diff --git a/okitweb/static/okit/js/okit.js b/okitweb/static/okit/js/okit.js index 6734aa5b5..b9280e5c2 100644 --- a/okitweb/static/okit/js/okit.js +++ b/okitweb/static/okit/js/okit.js @@ -406,7 +406,7 @@ class OkitSettings { this.highlight_association = true; this.show_label = 'none'; this.tooltip_type = 'simple'; - this.name_prefix = 'okit-'; + this.name_prefix = 'okit'; this.auto_save = false; this.show_ocids = false; this.validate_markdown = true; diff --git a/okitweb/static/okit/js/okit_designer_generation.js b/okitweb/static/okit/js/okit_designer_generation.js index 4447938f3..eb0a6d2f7 100644 --- a/okitweb/static/okit/js/okit_designer_generation.js +++ b/okitweb/static/okit/js/okit_designer_generation.js @@ -444,7 +444,7 @@ function exportToResourceManager() { create_or_update: $('input[name=create_update_toggle]:checked').val(), plan_or_apply: $('input[name=plan_apply_toggle]:checked').val() }; - console.info('Resource Manager Options : ' + JSON.stringify(request_json)); + // console.info('Resource Manager Options : ' + JSON.stringify(request_json)); hideNavMenu(); setBusyIcon(); $(jqId('modal_dialog_progress')).removeClass('hidden'); diff --git a/okitweb/static/okit/model/js/artefacts/bastion.js b/okitweb/static/okit/model/js/artefacts/bastion.js new file mode 100644 index 000000000..dd5a5eeda --- /dev/null +++ b/okitweb/static/okit/model/js/artefacts/bastion.js @@ -0,0 +1,76 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Bastion Javascript'); + +/* +** Define Bastion Class +*/ +class Bastion extends OkitArtifact { + /* + ** Create + */ + constructor (data={}, okitjson={}) { + super(okitjson); + // Configure default values + // # Required + this.display_name = this.generateDefaultName(okitjson.bastions.length + 1); + this.compartment_id = ''; + this.bastion_type = 'STANDARD'; + this.target_subnet_id = ''; + // # Optional + this.client_cidr_block_allow_list = []; + this.max_session_ttl_in_seconds = 180 * 60; + this.phone_book_entry = ''; + this.static_jump_host_ip_addresses = ''; + // Update with any passed data + this.merge(data); + this.convert(); + // Expose subnet_id at the top level + Object.defineProperty(this, 'subnet_id', {get: function() {return this.target_subnet_id;}, set: function(id) {this.target_subnet_id = id;}, enumerable: false }); + } + /* + ** Clone Functionality + */ + clone() { + return new Bastion(JSON.clone(this), this.getOkitJson()); + } + /* + ** Name Generation + */ + getNamePrefix() { + return super.getNamePrefix() + 'b'; + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return 'Bastion'; + } +} +/* +** Dynamically Add Model Functions +*/ +OkitJson.prototype.newBastion = function(data) { + this.getBastions().push(new Bastion(data, this)); + return this.getBastions()[this.getBastions().length - 1]; +} +OkitJson.prototype.getBastions = function() { + if (!this.bastions) { + this.bastions = []; + } + return this.bastions; +} +OkitJson.prototype.getBastion = function(id='') { + for (let artefact of this.getBastions()) { + if (artefact.id === id) { + return artefact; + } + } +return undefined; +} +OkitJson.prototype.deleteBastion = function(id) { + this.bastions = this.bastions ? this.bastions.filter((r) => r.id !== id) : [] +} + diff --git a/okitweb/static/okit/model/js/artefacts/key.js b/okitweb/static/okit/model/js/artefacts/key.js new file mode 100644 index 000000000..c427e1f54 --- /dev/null +++ b/okitweb/static/okit/model/js/artefacts/key.js @@ -0,0 +1,72 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Key Javascript'); + +/* +** Define Key Class +*/ +class Key extends OkitArtifact { + /* + ** Create + */ + constructor (data={}, okitjson={}) { + super(okitjson); + // Configure default values + this.display_name = this.generateDefaultName(okitjson.keys.length + 1); + this.compartment_id = data.parent_id; + /* + ** TODO: Add Resource / Artefact specific parameters and default + */ + // Update with any passed data + this.merge(data); + this.convert(); + // TODO: If the Resource is within a Subnet but the subnet_iss is not at the top level then raise it with the following functions if not required delete them. + // Expose subnet_id at the top level + Object.defineProperty(this, 'subnet_id', {get: function() {return this.primary_mount_target.subnet_id;}, set: function(id) {this.primary_mount_target.subnet_id = id;}, enumerable: false }); + } + /* + ** Clone Functionality + */ + clone() { + return new Key(JSON.clone(this), this.getOkitJson()); + } + /* + ** Name Generation + */ + getNamePrefix() { + return super.getNamePrefix() + 'k'; + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return 'Key'; + } +} +/* +** Dynamically Add Model Functions +*/ +OkitJson.prototype.newKey = function(data) { + this.getKeys().push(new Key(data, this)); + return this.getKeys()[this.getKeys().length - 1]; +} +OkitJson.prototype.getKeys = function() { + if (!this.keys) { + this.keys = []; + } + return this.keys; +} +OkitJson.prototype.getKey = function(id='') { + for (let artefact of this.getKeys()) { + if (artefact.id === id) { + return artefact; + } + } +return undefined; +} +OkitJson.prototype.deleteKey = function(id) { + this.keys = this.keys ? this.keys.filter((r) => r.id !== id) : [] +} + diff --git a/okitweb/static/okit/model/js/artefacts/network_load_balancer.js b/okitweb/static/okit/model/js/artefacts/network_load_balancer.js new file mode 100644 index 000000000..3f51fb7d8 --- /dev/null +++ b/okitweb/static/okit/model/js/artefacts/network_load_balancer.js @@ -0,0 +1,72 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Network Load Balancer Javascript'); + +/* +** Define Network Load Balancer Class +*/ +class NetworkLoadBalancer extends OkitArtifact { + /* + ** Create + */ + constructor (data={}, okitjson={}) { + super(okitjson); + // Configure default values + this.display_name = this.generateDefaultName(okitjson.network_load_balancers.length + 1); + this.compartment_id = data.parent_id; + /* + ** TODO: Add Resource / Artefact specific parameters and default + */ + // Update with any passed data + this.merge(data); + this.convert(); + // TODO: If the Resource is within a Subnet but the subnet_iss is not at the top level then raise it with the following functions if not required delete them. + // Expose subnet_id at the top level + Object.defineProperty(this, 'subnet_id', {get: function() {return this.primary_mount_target.subnet_id;}, set: function(id) {this.primary_mount_target.subnet_id = id;}, enumerable: false }); + } + /* + ** Clone Functionality + */ + clone() { + return new NetworkLoadBalancer(JSON.clone(this), this.getOkitJson()); + } + /* + ** Name Generation + */ + getNamePrefix() { + return super.getNamePrefix() + 'nlb'; + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return 'Network Load Balancer'; + } +} +/* +** Dynamically Add Model Functions +*/ +OkitJson.prototype.newNetworkLoadBalancer = function(data) { + this.getNetworkLoadBalancers().push(new NetworkLoadBalancer(data, this)); + return this.getNetworkLoadBalancers()[this.getNetworkLoadBalancers().length - 1]; +} +OkitJson.prototype.getNetworkLoadBalancers = function() { + if (!this.network_load_balancers) { + this.network_load_balancers = []; + } + return this.network_load_balancers; +} +OkitJson.prototype.getNetworkLoadBalancer = function(id='') { + for (let artefact of this.getNetworkLoadBalancers()) { + if (artefact.id === id) { + return artefact; + } + } +return undefined; +} +OkitJson.prototype.deleteNetworkLoadBalancer = function(id) { + this.network_load_balancers = this.network_load_balancers ? this.network_load_balancers.filter((r) => r.id !== id) : [] +} + diff --git a/okitweb/static/okit/model/js/artefacts/nosql_database.js b/okitweb/static/okit/model/js/artefacts/nosql_database.js new file mode 100644 index 000000000..07354c27d --- /dev/null +++ b/okitweb/static/okit/model/js/artefacts/nosql_database.js @@ -0,0 +1,72 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded NoSQL Database Javascript'); + +/* +** Define NoSQL Database Class +*/ +class NoSQLDatabase extends OkitArtifact { + /* + ** Create + */ + constructor (data={}, okitjson={}) { + super(okitjson); + // Configure default values + this.display_name = this.generateDefaultName(okitjson.nosql_databases.length + 1); + this.compartment_id = data.parent_id; + /* + ** TODO: Add Resource / Artefact specific parameters and default + */ + // Update with any passed data + this.merge(data); + this.convert(); + // TODO: If the Resource is within a Subnet but the subnet_iss is not at the top level then raise it with the following functions if not required delete them. + // Expose subnet_id at the top level + Object.defineProperty(this, 'subnet_id', {get: function() {return this.primary_mount_target.subnet_id;}, set: function(id) {this.primary_mount_target.subnet_id = id;}, enumerable: false }); + } + /* + ** Clone Functionality + */ + clone() { + return new NoSQLDatabase(JSON.clone(this), this.getOkitJson()); + } + /* + ** Name Generation + */ + getNamePrefix() { + return super.getNamePrefix() + 'nd'; + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return 'NoSQL Database'; + } +} +/* +** Dynamically Add Model Functions +*/ +OkitJson.prototype.newNoSQLDatabase = function(data) { + this.getNoSQLDatabases().push(new NoSQLDatabase(data, this)); + return this.getNoSQLDatabases()[this.getNoSQLDatabases().length - 1]; +} +OkitJson.prototype.getNoSQLDatabases = function() { + if (!this.nosql_databases) { + this.nosql_databases = []; + } + return this.nosql_databases; +} +OkitJson.prototype.getNoSQLDatabase = function(id='') { + for (let artefact of this.getNoSQLDatabases()) { + if (artefact.id === id) { + return artefact; + } + } +return undefined; +} +OkitJson.prototype.deleteNoSQLDatabase = function(id) { + this.nosql_databases = this.nosql_databases ? this.nosql_databases.filter((r) => r.id !== id) : [] +} + diff --git a/okitweb/static/okit/model/js/artefacts/vault.js b/okitweb/static/okit/model/js/artefacts/vault.js new file mode 100644 index 000000000..46c4691a8 --- /dev/null +++ b/okitweb/static/okit/model/js/artefacts/vault.js @@ -0,0 +1,72 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Vault Javascript'); + +/* +** Define Vault Class +*/ +class Vault extends OkitArtifact { + /* + ** Create + */ + constructor (data={}, okitjson={}) { + super(okitjson); + // Configure default values + this.display_name = this.generateDefaultName(okitjson.vaults.length + 1); + this.compartment_id = data.parent_id; + /* + ** TODO: Add Resource / Artefact specific parameters and default + */ + // Update with any passed data + this.merge(data); + this.convert(); + // TODO: If the Resource is within a Subnet but the subnet_iss is not at the top level then raise it with the following functions if not required delete them. + // Expose subnet_id at the top level + Object.defineProperty(this, 'subnet_id', {get: function() {return this.primary_mount_target.subnet_id;}, set: function(id) {this.primary_mount_target.subnet_id = id;}, enumerable: false }); + } + /* + ** Clone Functionality + */ + clone() { + return new Vault(JSON.clone(this), this.getOkitJson()); + } + /* + ** Name Generation + */ + getNamePrefix() { + return super.getNamePrefix() + 'v'; + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return 'Vault'; + } +} +/* +** Dynamically Add Model Functions +*/ +OkitJson.prototype.newVault = function(data) { + this.getVaults().push(new Vault(data, this)); + return this.getVaults()[this.getVaults().length - 1]; +} +OkitJson.prototype.getVaults = function() { + if (!this.vaults) { + this.vaults = []; + } + return this.vaults; +} +OkitJson.prototype.getVault = function(id='') { + for (let artefact of this.getVaults()) { + if (artefact.id === id) { + return artefact; + } + } +return undefined; +} +OkitJson.prototype.deleteVault = function(id) { + this.vaults = this.vaults ? this.vaults.filter((r) => r.id !== id) : [] +} + diff --git a/okitweb/static/okit/model/js/okit_model.js b/okitweb/static/okit/model/js/okit_model.js index 69f04628c..5708b57e7 100644 --- a/okitweb/static/okit/model/js/okit_model.js +++ b/okitweb/static/okit/model/js/okit_model.js @@ -1213,7 +1213,7 @@ class OkitArtifact { } getNamePrefix() { - return okitSettings ? okitSettings.name_prefix : 'okit-'; + return okitSettings ? okitSettings.name_prefix : 'okit'; } getAvailabilityDomainNumber(availability_domain) { diff --git a/okitweb/static/okit/palette/palette.json b/okitweb/static/okit/palette/palette.json index 310b5a9e0..747729b9e 100644 --- a/okitweb/static/okit/palette/palette.json +++ b/okitweb/static/okit/palette/palette.json @@ -57,6 +57,16 @@ "targets": ["oci"], "svg": "MySQLDatabaseServiceMDS.svg" }, + { + "title": "NoSQL Database", + "targets": ["oci", "hidden"], + "svg": "NoSQLDatabase.svg" + }, + { + "title": "Autonomous Data Warehouse Cloud Service", + "targets": ["hidden"], + "svg": "AutonomousDataWarehouseCloudService.svg" + }, { "title": "Exadata Database System", "targets": ["hidden"], @@ -73,6 +83,11 @@ "targets": ["oci"], "svg": "LoadBalancerLB.svg" }, + { + "title": "NetworkLoad Balancer", + "targets": ["oci", "hidden"], + "svg": "NetworkLoadBalancerLB.svg" + }, { "title": "Virtual Cloud Network", "targets": ["oci", "free tier", "pca"], @@ -176,10 +191,25 @@ "title": "Identity", "svg": "identity.svg", "resources": [ + { + "title": "Bastion", + "targets": ["oci", "pca"], + "svg": "Bastion.svg" + }, { "title": "Policy", "targets": ["oci", "pca"], "svg": "Policies.svg" + }, + { + "title": "Vault", + "targets": ["oci", "pca", "hidden"], + "svg": "KeyVault.svg" + }, + { + "title": "Key", + "targets": ["oci", "pca", "hidden"], + "svg": "KeyManagement.svg" } ] } diff --git a/okitweb/static/okit/palette/svg/Autonomous-Transaction-Processing-ATP.svg b/okitweb/static/okit/palette/svg/AutonomousTransactionProcessingATP.svg similarity index 100% rename from okitweb/static/okit/palette/svg/Autonomous-Transaction-Processing-ATP.svg rename to okitweb/static/okit/palette/svg/AutonomousTransactionProcessingATP.svg diff --git a/okitweb/static/okit/palette/svg/Bastion.svg b/okitweb/static/okit/palette/svg/Bastion.svg new file mode 100644 index 000000000..db39be846 --- /dev/null +++ b/okitweb/static/okit/palette/svg/Bastion.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/okitweb/static/okit/palette/svg/NoSQL-Database.svg b/okitweb/static/okit/palette/svg/NoSQLDatabase.svg similarity index 100% rename from okitweb/static/okit/palette/svg/NoSQL-Database.svg rename to okitweb/static/okit/palette/svg/NoSQLDatabase.svg diff --git a/okitweb/static/okit/view/designer/js/artefacts/autonomous_database.js b/okitweb/static/okit/view/designer/js/artefacts/autonomous_database.js index e57af310f..d0f07ec79 100644 --- a/okitweb/static/okit/view/designer/js/artefacts/autonomous_database.js +++ b/okitweb/static/okit/view/designer/js/artefacts/autonomous_database.js @@ -13,6 +13,7 @@ class AutonomousDatabaseView extends OkitDesignerArtefactView { } // -- Reference + get icon_definition_id() {return this.db_workload.startsWith('DW') ? OkitJsonView.toSvgIconDef('AutonomousDataWarehouseCloudService') : super.icon_definition_id;} get parent_id() { let subnet = this.getJsonView().getSubnet(this.artefact.subnet_id); if (subnet && subnet.compartment_id === this.artefact.compartment_id) { diff --git a/okitweb/static/okit/view/designer/js/artefacts/bastion.js b/okitweb/static/okit/view/designer/js/artefacts/bastion.js new file mode 100644 index 000000000..b50bca983 --- /dev/null +++ b/okitweb/static/okit/view/designer/js/artefacts/bastion.js @@ -0,0 +1,168 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Bastion View Javascript'); + +/* +** Define Bastion View Class +*/ +class BastionView extends OkitArtefactView { + constructor(artefact=null, json_view) { + if (!json_view.bastions) json_view.bastions = []; + super(artefact, json_view); + } + // -- Reference + get parent_id() { + let primary_subnet = this.getJsonView().getSubnet(this.subnet_id); + if (primary_subnet && primary_subnet.compartment_id === this.artefact.compartment_id) { + return this.subnet_id; + } else { + return this.compartment_id; + } + } + get parent() {return this.getJsonView().getSubnet(this.parent_id) ? this.getJsonView().getSubnet(this.parent_id) : this.getJsonView().getCompartment(this.parent_id);} + // Direct Subnet Access + get subnet_id() {return this.artefact.target_subnet_id;} + set subnet_id(id) {this.artefact.target_subnet_id = id;} + /* + ** SVG Processing + */ + /* + ** Property Sheet Load function + */ + loadProperties() { + const self = this; + $(jqId(PROPERTIES_PANEL)).load("propertysheets/bastion.html", () => {loadPropertiesSheet(self.artefact);}); + } + /* + ** Load and display Value Proposition + */ + loadValueProposition() { + $(jqId(VALUE_PROPOSITION_PANEL)).load("valueproposition/bastion.html"); + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return Bastion.getArtifactReference(); + } + static getDropTargets() { + return [Compartment.getArtifactReference(), Subnet.getArtifactReference()]; + } +} +/* +** Dynamically Add View Functions +*/ +OkitJsonView.prototype.dropBastionView = function(target) { + let view_artefact = this.newBastion(); + if (target.type === Subnet.getArtifactReference()) { + view_artefact.getArtefact().target_subnet_id = target.id; + view_artefact.getArtefact().compartment_id = target.compartment_id; + } else if (target.type === Compartment.getArtifactReference()) { + view_artefact.getArtefact().compartment_id = target.id; +} + view_artefact.recalculate_dimensions = true; + return view_artefact; +} +OkitJsonView.prototype.newBastion = function(obj) { + this.getBastions().push(obj ? new BastionView(obj, this) : new BastionView(this.okitjson.newBastion(), this)); + return this.getBastions()[this.getBastions().length - 1]; +} +OkitJsonView.prototype.getBastions = function() { + if (!this.bastions) { + this.bastions = []; + } + return this.bastions; +} +OkitJsonView.prototype.getBastion = function(id='') { + for (let artefact of this.getBastions()) { + if (artefact.id === id) { + return artefact; + } + } + return undefined; +} +OkitJsonView.prototype.loadBastions = function(bastions) { + for (const artefact of bastions) { + this.getBastions().push(new BastionView(new Bastion(artefact, this.okitjson), this)); + } +} +OkitJsonView.prototype.moveBastion = function(id) { + // Build Dialog + const self = this; + let bastion = this.getBastion(id); + $(jqId('modal_dialog_title')).text('Move ' + bastion.display_name); + $(jqId('modal_dialog_body')).empty(); + $(jqId('modal_dialog_footer')).empty(); + const table = d3.select(d3Id('modal_dialog_body')).append('div') + .attr('class', 'table okit-table'); + const tbody = table.append('div') + .attr('class', 'tbody'); + // Subnet + let tr = tbody.append('div') + .attr('class', 'tr'); + tr.append('div') + .attr('class', 'td') + .text('Subnet'); + tr.append('div') + .attr('class', 'td') + .append('select') + .attr('id', 'move_bastion_subnet_id'); + // Load Subnets + this.loadSubnetsSelect('move_bastion_subnet_id'); + $(jqId("move_bastion_subnet_id")).val(bastion.artefact.subnet_id); + // Submit Button + const submit = d3.select(d3Id('modal_dialog_footer')).append('div').append('button') + .attr('id', 'submit_query_btn') + .attr('type', 'button') + .text('Move') + .on('click', function () { + $(jqId('modal_dialog_wrapper')).addClass('hidden'); + if (bastion.artefact.subnet_id !== $(jqId("move_bastion_subnet_id")).val()) { + self.getSubnet(bastion.artefact.subnet_id).recalculate_dimensions = true; + self.getSubnet($(jqId("move_bastion_subnet_id")).val()).recalculate_dimensions = true; + bastion.artefact.subnet_id = $(jqId("move_bastion_subnet_id")).val(); + bastion.artefact.compartment_id = self.getSubnet(bastion.artefact.subnet_id).artefact.compartment_id; + } + self.update(this.okitjson); + }); + $(jqId('modal_dialog_wrapper')).removeClass('hidden'); +} +OkitJsonView.prototype.pasteBastion = function(drop_target) { + const clone = this.copied_artefact.artefact.clone(); + clone.display_name += 'Copy'; + if (this.paste_count) {clone.display_name += `-${this.paste_count}`;} + this.paste_count += 1; + clone.id = clone.okit_id; + if (drop_target.getArtifactReference() === Subnet.getArtifactReference()) { + clone.subnet_id = drop_target.id; + clone.compartment_id = drop_target.compartment_id; + } + this.okitjson.bastions.push(clone); + this.update(this.okitjson); +} +OkitJsonView.prototype.loadBastionsSelect = function(select_id, empty_option=false) { + $(jqId(select_id)).empty(); + const bastion_select = $(jqId(select_id)); + if (empty_option) { + bastion_select.append($('