mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Website: Build pricing page from yaml file (#8549)
* Create pricing-features-table.yml * update built-static-content to add the pricing table configuration to builtStaticContent * Update pricing page to use builtStaticContent.pricingTable * Update view-pricing.js * update pricing table, lint fix Co-authored-by: Mike McNeil <mikermcneil@users.noreply.github.com>
This commit is contained in:
parent
a59e1cce80
commit
d92d9980ce
131
handbook/product/pricing-features-table.yml
Normal file
131
handbook/product/pricing-features-table.yml
Normal file
@ -0,0 +1,131 @@
|
||||
- categoryName: Support
|
||||
features:
|
||||
- name: Public issue tracker (GitHub)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Community Slack channel
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Unlimited email support (confidential)
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- name: Phone and video call support
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- categoryName: Inventory management
|
||||
features:
|
||||
- name: Secure REST API
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Command line tool (CLI)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Realtime device inventory dashboard
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Browse installed software packages
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Search devices by IP, serial, hostname, UUID
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Target and configure specific groups of devices
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- name: Aggregate insights for groups of devices
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- categoryName: Collaboration
|
||||
features:
|
||||
- name: Shareable device health reports
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Versionable queries and config (GitOps)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Human-to-device mapping
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Scope transparency
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Multiple teams
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- categoryName: Security and compliance
|
||||
features:
|
||||
- name: Single sign on (SSO, SAML)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Audit queries and user activities
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Grant API-only access
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Role-based access control
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Just-in-time provisioning
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- categoryName: Monitoring
|
||||
features:
|
||||
- name: Schedule and automate custom queries
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Detect vulnerable software
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Query performance monitoring
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Standard query and policy library
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Detect and surface issues with devices
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Policy and vulnerability automations (webhook, Zendesk, JIRA, ServiceNow*)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Vulnerability scores (EPSS and CVSS)
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- name: CISA known exploited vulnerabilities
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- name: End-user self-service
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- categoryName: Data outputs
|
||||
features:
|
||||
- name: Flexible log destinations (AWS Kinesis, Lambda, GCP, Kafka)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: File carving (AWS S3)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- categoryName: Deployment
|
||||
features:
|
||||
- name: Self-managed
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Deployment tools (Helm, Terraform)
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Configure osquery startup flags remotely
|
||||
tier: Free
|
||||
comingSoon: true
|
||||
- name: Autoupdate osquery agents
|
||||
tier: Free
|
||||
comingSoon: false
|
||||
- name: Self-managed autoupdate registry
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
- name: Manage osquery extensions remotely
|
||||
tier: Premium
|
||||
comingSoon: false
|
||||
|
||||
|
||||
|
13
website/api/controllers/view-pricing.js
vendored
13
website/api/controllers/view-pricing.js
vendored
@ -11,15 +11,24 @@ module.exports = {
|
||||
|
||||
success: {
|
||||
viewTemplatePath: 'pages/pricing'
|
||||
}
|
||||
},
|
||||
|
||||
badConfig: {
|
||||
responseType: 'badConfig'
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function () {
|
||||
|
||||
if(!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.pricingTable)) {
|
||||
throw {badConfig: 'builtStaticContent.pricingTable'};
|
||||
}
|
||||
let pricingTable = sails.config.builtStaticContent.pricingTable;
|
||||
|
||||
// Respond with view.
|
||||
return {};
|
||||
return { pricingTable };
|
||||
|
||||
}
|
||||
|
||||
|
8
website/assets/styles/pages/pricing.less
vendored
8
website/assets/styles/pages/pricing.less
vendored
@ -8,10 +8,7 @@
|
||||
.btn {
|
||||
color: #fff;
|
||||
}
|
||||
.faq-question {
|
||||
font-weight: @bold;
|
||||
}
|
||||
.faq-list {
|
||||
[purpose='faq-list'] {
|
||||
padding-left: 20px;
|
||||
|
||||
li {
|
||||
@ -20,6 +17,9 @@
|
||||
}
|
||||
|
||||
}
|
||||
[purpose='pricing-table-category']:not(:first-of-type) {
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
p {font-size: 16px;}
|
||||
|
36
website/scripts/build-static-content.js
vendored
36
website/scripts/build-static-content.js
vendored
@ -638,6 +638,42 @@ module.exports = {
|
||||
builtStaticContent.compiledPagePartialsAppPath = APP_PATH_TO_COMPILED_PAGE_PARTIALS;
|
||||
|
||||
},
|
||||
async()=>{
|
||||
// Validate the pricing table yaml and add it to builtStaticContent.pricingTable.
|
||||
let RELATIVE_PATH_TO_PRICING_TABLE_YML_IN_FLEET_REPO = 'handbook/product/pricing-features-table.yml';// TODO: Is there a better home for this file?
|
||||
let yaml = await sails.helpers.fs.read(path.join(topLvlRepoPath, RELATIVE_PATH_TO_PRICING_TABLE_YML_IN_FLEET_REPO)).intercept('doesNotExist', (err)=>new Error(`Could not find pricing table features YAML file at "${RELATIVE_PATH_TO_PRICING_TABLE_YML_IN_FLEET_REPO}". Was it accidentally moved? Raw error: `+err.message));
|
||||
let pricingTableCategories = YAML.parse(yaml, {prettyErrors: true});
|
||||
|
||||
for(let category of pricingTableCategories){
|
||||
if(!category.categoryName){ // Throw an error if a category is missing a categoryName.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml, a category in the pricing table configuration is missing a categoryName. To resolve, make sure every category in the pricing table YAML file has a categoryName');
|
||||
}
|
||||
if(!category.features){// Throw an error if a category is missing `features`.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml, the "'+category.categoryName+'" category in the yaml file is missing features. To resolve, add an array of features to this category.');
|
||||
}
|
||||
if(!_.isArray(category.features)){ // Throw an error if a category's `features`` is not an array.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml, The value of the "'+category.categoryName+'" category is invalid, to resolve, change the features for this category to be an array of objects.');
|
||||
}
|
||||
// Validate all features in a category.
|
||||
for(let feature of category.features){
|
||||
if(!feature.name) { // Throw an error if a feature is missing a `name`.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml. A feature in the "'+category.categoryName+'" category is missing a "name". To resolve, add a "name" to this feature '+feature);
|
||||
}
|
||||
if(!feature.tier) { // Throw an error if a feature is missing a `tier`.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml. The "'+feature.name+'" feature is missing a "tier". To resolve, add a "tier" (either "Free" or "Premium") to this feature.');
|
||||
} else if(!_.contains(['Free', 'Premium'], feature.tier)){ // Throw an error if a feature's `tier` is not either "Free" or "Premium".
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml. The "'+feature.name+'" feature has an invalid "tier". to resolve, change the value of this features "tier" (currently set to '+feature.tier+') to be either "Free" or "Premium".');
|
||||
}
|
||||
if(feature.comingSoon === undefined) { // Throw an error if a feature is missing a `comingSoon` value
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml. The "'+feature.name+'" feature is missing a "comingSoon" value (boolean). To resolve, add a comingSoon value to this feature.');
|
||||
} else if(typeof feature.comingSoon !== 'boolean'){ // Throw an error if the `comingSoon` value is not a boolean.
|
||||
throw new Error('Could not build pricing table config from pricing-features-table.yml. The "'+feature.name+'" feature has an invalid "comingSoon" value (currently set to '+feature.comingSoon+'). To resolve, change the value of "comingSoon" for this feature to be either "true" or "false".');
|
||||
}
|
||||
}
|
||||
}
|
||||
builtStaticContent.pricingTable = pricingTableCategories;
|
||||
},
|
||||
|
||||
]);
|
||||
|
||||
// ██████╗ ███████╗██████╗ ██╗ █████╗ ██████╗███████╗ ███████╗ █████╗ ██╗██╗ ███████╗██████╗ ██████╗
|
||||
|
1083
website/views/pages/pricing.ejs
vendored
1083
website/views/pages/pricing.ejs
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user