Website Update /start signup flow. (#18027)

Closes: #17958

Changes:
- Updated the primary and secondary CTAs site-wide
- Updated the /start page to have a multi-stage form that users can fill
out to personalize their onboarding experience
- Updated the signup action to not set a `primaryBuyingSituation` on new
user records (This will now be set when users progress through the
/start form)
- Added two new attributes to the `User` model:
`currentGetStartedQuestionnarieStep` and
`getStartedQuestionnarieAnswers` that save user's progress in the /start
form.


Before this PR can be merged we will need to:
- [x] Update the Zapier webhook that runs when new users sign up to no
longer expect a `primaryBuyingSituation` value
- [ ] Update the User table in the website's database
- [ ] Migrate the existing user records
This commit is contained in:
Eric
2024-04-04 11:13:53 -05:00
committed by GitHub
parent 0db1c225f4
commit a0d1172f89
27 changed files with 1037 additions and 103 deletions
+1 -15
View File
@@ -63,18 +63,6 @@ the account verification message.)`,
defaultsTo: 'Buy a license',
},
primaryBuyingSituation: {
type: 'string',
description: 'What the user will be using Fleet for.',
required: true,
isIn: [
'eo-security',
'eo-it',
'mdm',
'vm'
],
}
},
@@ -104,7 +92,7 @@ the account verification message.)`,
},
fn: async function ({emailAddress, password, firstName, lastName, organization, signupReason, primaryBuyingSituation}) {
fn: async function ({emailAddress, password, firstName, lastName, organization, signupReason}) {
// Note: in Oct. 2023, the Fleet Sandbox related code was removed from this action. For more details, see https://github.com/fleetdm/fleet/pull/14638/files
var newEmailAddress = emailAddress.toLowerCase();
@@ -153,7 +141,6 @@ the account verification message.)`,
signupReason,
password: await sails.helpers.passwords.hashPassword(password),
stripeCustomerId,
primaryBuyingSituation,
tosAcceptedByIp: this.req.ip
}, sails.config.custom.verifyEmailAddresses? {
emailProofToken: await sails.helpers.strings.random('url-friendly'),
@@ -173,7 +160,6 @@ the account verification message.)`,
lastName,
organization,
signupReason,
primaryBuyingSituation,
webhookSecret: sails.config.custom.zapierSandboxWebhookSecret,
}
})
+1 -3
View File
@@ -26,10 +26,8 @@ module.exports = {
if (this.req.me) {
if(this.req.me.isSuperAdmin){
throw {redirect: '/admin/generate-license'};
} else if(this.req.me.hasBillingCard) {
throw {redirect: '/customers/new-license'};
} else {
throw {redirect: '/try-fleet/sandbox'};
throw {redirect: '/start'};
}
}
+71
View File
@@ -0,0 +1,71 @@
module.exports = {
friendlyName: 'Save questionnaire progress and continue',
description: 'Saves the user\'s current progress in the get started questionnaire',
inputs: {
currentStep: {
type: 'string',
description: 'The step of the get started questionnaire that is being saved.',
isIn: [
'start',
'what-are-you-using-fleet-for',
'have-you-ever-used-fleet',
'how-many-hosts',
'will-you-be-self-hosting',
'what-are-you-working-on-eo-security',
'is-it-any-good',
'what-did-you-think',
'deploy-fleet-in-your-environment',
'managed-cloud-for-growing-deployments',
'self-hosted-deploy',
]
},
formData: {
type: {},
description: 'The formdata that will be saved for this step of the get started questionnaire'
}
},
exits: {
},
fn: async function ({currentStep, formData}) {
// find this user's DB record.
let userRecord = await User.findOne({id: this.req.me.id});
if(!userRecord){
throw new Error(`Consistency violation: when trying to save a user's progress in the get started questionnaire, a User record with the ID ${this.req.me.id} could not be found.`);
}
let questionnaireProgress;
// If this user doesn't have a lastSubmittedGetStartedQuestionnaireStep or getStartedQuestionnaireAnswers, create an empty dictionary to store their answers.
if(!userRecord.lastSubmittedGetStartedQuestionnaireStep || _.isEmpty(userRecord.getStartedQuestionnaireAnswers)) {
questionnaireProgress = {};
} else {// other wise clone it from the user record.
questionnaireProgress = _.clone(userRecord.getStartedQuestionnaireAnswers);
}
// When the 'what-are-you-using-fleet-for' is completed, update this user's DB record and session to include their answer.
if(currentStep === 'what-are-you-using-fleet-for') {
let primaryBuyingSituation = formData.primaryBuyingSituation;
await User.updateOne({id: this.req.me.id}).set({primaryBuyingSituation});
// Set the primary buying situation in the user's session.
this.req.session.primaryBuyingSituation = primaryBuyingSituation;
}
// Set the user's answer to the current step.
questionnaireProgress[currentStep] = formData;
// Clone the questionnaireProgress to prevent any mutations from sending it through the updateOne Waterline method.
let getStartedProgress = _.clone(questionnaireProgress);
// Update the user's database model.
await User.updateOne({id: userRecord.id}).set({getStartedQuestionnaireAnswers: questionnaireProgress, lastSubmittedGetStartedQuestionnaireStep: currentStep});
// Return the JSON dictionary of form data submitted by this user.
return getStartedProgress;
}
};
+11 -2
View File
@@ -12,6 +12,11 @@ module.exports = {
description: 'A boolean that determines whether or not to display the talk to us form when the contact page loads.',
defaultsTo: false,
},
prefillFormDataFromUserRecord: {
type: 'boolean',
description: 'If true, the contact form will be prefilled in with information from this user\'s account.',
},
},
exits: {
@@ -23,15 +28,19 @@ module.exports = {
},
fn: async function ({sendMessage}) {
fn: async function ({sendMessage, prefillFormDataFromUserRecord}) {
let formToShow = 'talk-to-us';
if(sendMessage) {
formToShow = 'contact';
}
// If the prefillFormDataFromUserRecord flag was set to true, but this user is not logged in, set it to false.
if(prefillFormDataFromUserRecord && !this.req.me){
prefillFormDataFromUserRecord = false;
}
// Respond with view.
return {formToShow};
return {formToShow, prefillFormDataFromUserRecord};
}
+9 -3
View File
@@ -17,9 +17,15 @@ module.exports = {
fn: async function () {
// Respond with view.
return {};
if(this.req.me.lastSubmittedGetStartedQuestionnaireStep && !_.isEmpty(this.req.me.getStartedQuestionnaireAnswers)){
let currentStep = this.req.me.lastSubmittedGetStartedQuestionnaireStep;
let previouslyAnsweredQuestions = this.req.me.getStartedQuestionnaireAnswers;
// Respond with view.
return {currentStep, previouslyAnsweredQuestions};
} else {
// Respond with view.
return;
}
}
+11
View File
@@ -212,6 +212,17 @@ without necessarily having a billing card.`
'mdm',
'vm',
]
},
lastSubmittedGetStartedQuestionnaireStep: {
type: 'string',
description: 'The last step the user reached in the get started form.'
},
getStartedQuestionnaireAnswers: {
type: 'json',
description: 'This answers the user provided when they filled out the get started form.',
defaultsTo: {},
}
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+1 -1
View File
@@ -13,7 +13,7 @@
Cloud.setup({
/* eslint-disable */
methods: {"downloadSitemap":{"verb":"GET","url":"/sitemap.xml","args":[]},"downloadRssFeed":{"verb":"GET","url":"/rss/:categoryName","args":["categoryName"]},"receiveUsageAnalytics":{"verb":"POST","url":"/api/v1/webhooks/receive-usage-analytics","args":["anonymousIdentifier","fleetVersion","licenseTier","numHostsEnrolled","numUsers","numTeams","numPolicies","numLabels","softwareInventoryEnabled","vulnDetectionEnabled","systemUsersEnabled","hostsStatusWebHookEnabled","numWeeklyActiveUsers","numWeeklyPolicyViolationDaysActual","numWeeklyPolicyViolationDaysPossible","hostsEnrolledByOperatingSystem","hostsEnrolledByOrbitVersion","hostsEnrolledByOsqueryVersion","storedErrors","numHostsNotResponding","organization","mdmMacOsEnabled","mdmWindowsEnabled","liveQueryDisabled","hostExpiryEnabled"]},"receiveFromGithub":{"verb":"GET","url":"/api/v1/webhooks/github","args":["botSignature","action","sender","repository","changes","issue","comment","pull_request","label","release"]},"receiveFromStripe":{"verb":"POST","url":"/api/v1/webhooks/receive-from-stripe","args":["id","type","data","webhookSecret"]},"deliverContactFormMessage":{"verb":"POST","url":"/api/v1/deliver-contact-form-message","args":["emailAddress","firstName","lastName","message"]},"sendPasswordRecoveryEmail":{"verb":"POST","url":"/api/v1/entrance/send-password-recovery-email","args":["emailAddress"]},"signup":{"verb":"POST","url":"/api/v1/customers/signup","args":["emailAddress","password","organization","firstName","lastName","signupReason"]},"updateProfile":{"verb":"POST","url":"/api/v1/account/update-profile","args":["firstName","lastName","organization","emailAddress"]},"updatePassword":{"verb":"POST","url":"/api/v1/account/update-password","args":["oldPassword","newPassword"]},"updateBillingCard":{"verb":"POST","url":"/api/v1/account/update-billing-card","args":["stripeToken","billingCardLast4","billingCardBrand","billingCardExpMonth","billingCardExpYear"]},"login":{"verb":"POST","url":"/api/v1/customers/login","args":["emailAddress","password","rememberMe"]},"logout":{"verb":"GET","url":"/api/v1/account/logout","args":[]},"createQuote":{"verb":"POST","url":"/api/v1/customers/create-quote","args":["numberOfHosts"]},"saveBillingInfoAndSubscribe":{"verb":"POST","url":"/api/v1/customers/save-billing-info-and-subscribe","args":["quoteId","organization","firstName","lastName","paymentSource"]},"updatePasswordAndLogin":{"verb":"POST","url":"/api/v1/entrance/update-password-and-login","args":["password","token"]},"deliverDemoSignup":{"verb":"POST","url":"/api/v1/deliver-demo-signup","args":["emailAddress"]},"createOrUpdateOneNewsletterSubscription":{"verb":"POST","url":"/api/v1/create-or-update-one-newsletter-subscription","args":["emailAddress","subscribeTo"]},"unsubscribeFromAllNewsletters":{"verb":"GET","url":"/api/v1/unsubscribe-from-all-newsletters","args":["emailAddress"]},"buildLicenseKey":{"verb":"POST","url":"/api/v1/admin/build-license-key","args":["numberOfHosts","organization","expiresAt","partnerName"]},"createVantaAuthorizationRequest":{"verb":"POST","url":"/api/v1/create-vanta-authorization-request","args":["emailAddress","fleetInstanceUrl","fleetApiKey"]},"deliverMdmBetaSignup":{"verb":"POST","url":"/api/v1/deliver-mdm-beta-signup","args":["emailAddress","fullName","jobTitle","numberOfHosts"]},"deliverAppleCsr":{"verb":"POST","url":"/api/v1/deliver-apple-csr","args":["unsignedCsrData"]},"deliverPremiumUpgradeForm":{"verb":"POST","url":"/api/v1/deliver-premium-upgrade-form","args":["organization","monthsUsingFleetFree","emailAddress","numberOfHosts"]},"deliverLaunchPartySignup":{"verb":"POST","url":"/api/v1/deliver-launch-party-signup","args":["emailAddress","firstName","lastName","jobTitle","phoneNumber"]},"deliverMdmDemoEmail":{"verb":"POST","url":"/api/v1/deliver-mdm-demo-email","args":["emailAddress"]},"provisionSandboxInstanceAndDeliverEmail":{"verb":"POST","url":"/api/v1/admin/provision-sandbox-instance-and-deliver-email","args":["userId"]},"deliverTalkToUsFormSubmission":{"verb":"POST","url":"/api/v1/deliver-talk-to-us-form-submission","args":["emailAddress","firstName","lastName","organization","numberOfHosts","primaryBuyingSituation"]}}
methods: {"downloadSitemap":{"verb":"GET","url":"/sitemap.xml","args":[]},"downloadRssFeed":{"verb":"GET","url":"/rss/:categoryName","args":["categoryName"]},"receiveUsageAnalytics":{"verb":"POST","url":"/api/v1/webhooks/receive-usage-analytics","args":["anonymousIdentifier","fleetVersion","licenseTier","numHostsEnrolled","numUsers","numTeams","numPolicies","numLabels","softwareInventoryEnabled","vulnDetectionEnabled","systemUsersEnabled","hostsStatusWebHookEnabled","numWeeklyActiveUsers","numWeeklyPolicyViolationDaysActual","numWeeklyPolicyViolationDaysPossible","hostsEnrolledByOperatingSystem","hostsEnrolledByOrbitVersion","hostsEnrolledByOsqueryVersion","storedErrors","numHostsNotResponding","organization","mdmMacOsEnabled","mdmWindowsEnabled","liveQueryDisabled","hostExpiryEnabled"]},"receiveFromGithub":{"verb":"GET","url":"/api/v1/webhooks/github","args":["botSignature","action","sender","repository","changes","issue","comment","pull_request","label","release"]},"receiveFromStripe":{"verb":"POST","url":"/api/v1/webhooks/receive-from-stripe","args":["id","type","data","webhookSecret"]},"deliverContactFormMessage":{"verb":"POST","url":"/api/v1/deliver-contact-form-message","args":["emailAddress","firstName","lastName","message"]},"sendPasswordRecoveryEmail":{"verb":"POST","url":"/api/v1/entrance/send-password-recovery-email","args":["emailAddress"]},"signup":{"verb":"POST","url":"/api/v1/customers/signup","args":["emailAddress","password","organization","firstName","lastName","signupReason","primaryBuyingSituation"]},"updateProfile":{"verb":"POST","url":"/api/v1/account/update-profile","args":["firstName","lastName","organization","emailAddress"]},"updatePassword":{"verb":"POST","url":"/api/v1/account/update-password","args":["oldPassword","newPassword"]},"updateBillingCard":{"verb":"POST","url":"/api/v1/account/update-billing-card","args":["stripeToken","billingCardLast4","billingCardBrand","billingCardExpMonth","billingCardExpYear"]},"login":{"verb":"POST","url":"/api/v1/customers/login","args":["emailAddress","password","rememberMe"]},"logout":{"verb":"GET","url":"/api/v1/account/logout","args":[]},"createQuote":{"verb":"POST","url":"/api/v1/customers/create-quote","args":["numberOfHosts"]},"saveBillingInfoAndSubscribe":{"verb":"POST","url":"/api/v1/customers/save-billing-info-and-subscribe","args":["quoteId","organization","firstName","lastName","paymentSource"]},"updatePasswordAndLogin":{"verb":"POST","url":"/api/v1/entrance/update-password-and-login","args":["password","token"]},"deliverDemoSignup":{"verb":"POST","url":"/api/v1/deliver-demo-signup","args":["emailAddress"]},"createOrUpdateOneNewsletterSubscription":{"verb":"POST","url":"/api/v1/create-or-update-one-newsletter-subscription","args":["emailAddress","subscribeTo"]},"unsubscribeFromAllNewsletters":{"verb":"GET","url":"/api/v1/unsubscribe-from-all-newsletters","args":["emailAddress"]},"buildLicenseKey":{"verb":"POST","url":"/api/v1/admin/build-license-key","args":["numberOfHosts","organization","expiresAt","partnerName"]},"createVantaAuthorizationRequest":{"verb":"POST","url":"/api/v1/create-vanta-authorization-request","args":["emailAddress","fleetInstanceUrl","fleetApiKey"]},"deliverMdmBetaSignup":{"verb":"POST","url":"/api/v1/deliver-mdm-beta-signup","args":["emailAddress","fullName","jobTitle","numberOfHosts"]},"deliverAppleCsr":{"verb":"POST","url":"/api/v1/deliver-apple-csr","args":["unsignedCsrData"]},"deliverLaunchPartySignup":{"verb":"POST","url":"/api/v1/deliver-launch-party-signup","args":["emailAddress","firstName","lastName","jobTitle","phoneNumber"]},"deliverMdmDemoEmail":{"verb":"POST","url":"/api/v1/deliver-mdm-demo-email","args":["emailAddress"]},"provisionSandboxInstanceAndDeliverEmail":{"verb":"POST","url":"/api/v1/admin/provision-sandbox-instance-and-deliver-email","args":["userId"]},"deliverTalkToUsFormSubmission":{"verb":"POST","url":"/api/v1/deliver-talk-to-us-form-submission","args":["emailAddress","firstName","lastName","organization","numberOfHosts","primaryBuyingSituation"]},"saveQuestionnaireProgress":{"verb":"POST","url":"/api/v1/save-questionnaire-progress","args":["currentStep","formData"]}}
/* eslint-enable */
});
+18 -1
View File
@@ -32,6 +32,8 @@ parasails.registerPage('contact', {
message: {required: false},
},
formDataToPrefillForLoggedInUsers: {},
// Server error state for the form
cloudError: '',
@@ -46,6 +48,17 @@ parasails.registerPage('contact', {
if(this.formToShow === 'contact'){
this.formToDisplay = this.formToShow;
}
if(this.prefillFormDataFromUserRecord){
this.formDataToPrefillForLoggedInUsers.emailAddress = this.me.emailAddress;
this.formDataToPrefillForLoggedInUsers.firstName = this.me.firstName;
this.formDataToPrefillForLoggedInUsers.lastName = this.me.lastName;
this.formDataToPrefillForLoggedInUsers.organization = this.me.organization;
// Only prefil this information if the user has this value set.
if(this.me.primaryBuyingSituation) {
this.formDataToPrefillForLoggedInUsers.primaryBuyingSituation = this.me.primaryBuyingSituation;
}
this.formData = _.clone(this.formDataToPrefillForLoggedInUsers);
}
if(window.location.search){
window.history.replaceState({}, document.title, '/contact' );
}
@@ -78,7 +91,11 @@ parasails.registerPage('contact', {
},
clickSwitchForms: function(form) {
this.formData = {};
if(this.prefillFormDataFromUserRecord){
this.formData = _.clone(this.formDataToPrefillForLoggedInUsers);
} else {
this.formData = {};
}
this.formErrors = {};
this.cloudError = '';
this.formToDisplay = form;
-1
View File
@@ -17,7 +17,6 @@ parasails.registerPage('signup', {
organization: {required: true},
emailAddress: {required: true, isEmail: true},
password: {required: true, minLength: 8},
primaryBuyingSituation: {required: true},
},
// Syncing / loading state
syncing: false,
+171 -2
View File
@@ -3,7 +3,54 @@ parasails.registerPage('start', {
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: {
//…
currentStep: 'start',
syncing: false,
// Form data
formData: {
'start': {stepCompleted: true},
'what-are-you-using-fleet-for': {},
'have-you-ever-used-fleet': {},
'how-many-hosts': {},
'will-you-be-self-hosting': {},
'what-are-you-working-on-eo-security': {},
'is-it-any-good': {stepCompleted: true},
'what-did-you-think': {},
},
// For tracking client-side validation errors in our form.
// > Has property set to `true` for each invalid property in `formData`.
formErrors: { /* … */ },
formRules: {},
primaryBuyingSituationFormRules: {
primaryBuyingSituation: {required: true}
},
isUsingFleetFormRules: {
fleetUseStatus: {required: true}
},
numberOfHostsFormRules: {
numberOfHosts: {required: true}
},
hostingFleetFormRules: {
willSelfHost: {required: true}
},
endpointOpsSecurityWorkingOnFormRules: {
endpointOpsSecurityUseCase: {required: true}
},
endpointOpsSecurityIsItAnyGoodFormRules: {
isItAnyGood: {required: true}
},
endpointOpsSecurityWhatDidYouThinkFormRules: {
whatDidYouThink: {required: true}
},
previouslyAnsweredQuestions: {},
// Server error state for the forms
cloudError: '',
// Success state when form has been submitted
cloudSuccess: false,
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
@@ -11,6 +58,9 @@ parasails.registerPage('start', {
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
beforeMount: function() {
//…
if(this.currentStep !== 'start'){
this.prefillPreviousAnswers();
}
},
mounted: async function() {
//…
@@ -20,6 +70,125 @@ parasails.registerPage('start', {
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
//…
handleSubmittingForm: async function(argins) {
let formDataForThisStep = _.clone(argins);
let nextStep = this.getNextStep();
let getStartedProgress = await Cloud.saveQuestionnaireProgress.with({
currentStep: this.currentStep,
formData: formDataForThisStep,
});
this.previouslyAnsweredQuestions[this.currentStep] = getStartedProgress[this.currentStep];
this.syncing = false;
this.currentStep = nextStep;
},
clickGoToPreviousStep: async function() {
switch(this.currentStep) {
case 'have-you-ever-used-fleet':
this.currentStep = 'what-are-you-using-fleet-for';
break;
case 'how-many-hosts':
this.currentStep = 'have-you-ever-used-fleet';
break;
case 'will-you-be-self-hosting':
this.currentStep = 'how-many-hosts';
break;
case 'self-hosted-deploy':
this.currentStep = 'will-you-be-self-hosting';
break;
case 'managed-cloud-for-growing-deployments':
this.currentStep = 'will-you-be-self-hosting';
break;
case 'what-are-you-working-on-eo-security':
this.currentStep = 'have-you-ever-used-fleet';
break;
case 'is-it-any-good':
this.currentStep = 'what-are-you-working-on-eo-security';
break;
case 'lets-talk-to-your-team':
this.currentStep = 'how-many-hosts';
break;
case 'welcome-to-fleet':
this.currentStep = 'have-you-ever-used-fleet';
break;
case 'deploy-fleet-in-your-environment':
this.currentStep = 'what-did-you-think';
break;
case 'what-did-you-think':
this.currentStep = 'is-it-any-good';
break;
}
},
getNextStep: function() {
let nextStepInForm;
switch(this.currentStep) {
case 'start':
nextStepInForm = 'what-are-you-using-fleet-for';
break;
case 'what-are-you-using-fleet-for':
nextStepInForm = 'have-you-ever-used-fleet';
break;
case 'have-you-ever-used-fleet':
let fleetUseStatus = this.formData['have-you-ever-used-fleet'].fleetUseStatus;
let primaryBuyingSituation = this.formData['what-are-you-using-fleet-for'].primaryBuyingSituation;
if(fleetUseStatus === 'yes-recently-deployed' || fleetUseStatus === 'yes-deployed') {
nextStepInForm = 'how-many-hosts';
} else {
if(primaryBuyingSituation === 'eo-security'){
nextStepInForm = 'what-are-you-working-on-eo-security';
} else {
nextStepInForm = 'welcome-to-fleet';
}
}
break;
case 'how-many-hosts':
if(this.formData['how-many-hosts'].numberOfHosts === '1-100' ||
this.formData['how-many-hosts'].numberOfHosts === '100-700') {
nextStepInForm = 'will-you-be-self-hosting';
} else {
nextStepInForm = 'lets-talk-to-your-team';
}
break;
case 'will-you-be-self-hosting':
if(this.formData['will-you-be-self-hosting'].willSelfHost === 'true'){
nextStepInForm = 'self-hosted-deploy';
} else {
nextStepInForm = 'managed-cloud-for-growing-deployments';
}
break;
case 'what-are-you-working-on-eo-security':
nextStepInForm = 'is-it-any-good';
break;
case 'is-it-any-good':
nextStepInForm = 'what-did-you-think';
break;
case 'what-did-you-think':
if(this.formData['what-did-you-think'].whatDidYouThink === 'let-me-think-about-it'){
nextStepInForm = 'is-it-any-good';
} else {
nextStepInForm = 'deploy-fleet-in-your-environment';
}
break;
}
return nextStepInForm;
},
clickGoToCalendly: function() {
window.location = `https://calendly.com/fleetdm/talk-to-us?email=${encodeURIComponent(this.me.emailAddress)}&name=${encodeURIComponent(this.me.firstName+' '+this.me.lastName)}`;
},
clickGoToContactPage: function() {
window.location = `/contact?prefillFormDataFromUserRecord`;
},
clickClearOneFormError: function(field) {
if(this.formErrors[field]){
this.formErrors = _.omit(this.formErrors, field);
}
},
prefillPreviousAnswers: function() {
if(!_.isEmpty(this.previouslyAnsweredQuestions)){
for(let step in this.previouslyAnsweredQuestions){
this.formData[step] = this.previouslyAnsweredQuestions[step];
}
this.currentStep = this.getNextStep();
}
},
}
});
+183 -4
View File
@@ -8,18 +8,139 @@
font-weight: 800;
line-height: 150%;
}
h2 {
margin-bottom: 32px;
font-size: 24px;
font-weight: 800;
line-height: 120%;
}
[purpose='logo-container'] {
max-width: 524px;
margin-left: auto;
margin-right: auto;
}
[purpose='form-container'] {
width: 528px;
margin-left: auto;
margin-right: auto;
}
[purpose='page-container'] {
padding-top: 80px;
padding-top: 64px;
padding-left: 64px;
padding-right: 64px;
padding-bottom: 64px;
max-width: unset;
display: flex;
flex-direction: column;
justify-content: center;
}
[purpose='progress-bar-container'] {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 32px;
img {
height: 18px;
display: inline;
margin-left: 10px;
}
}
[purpose='form-progress-bar'] {
height: 6px;
width: 200px;
background: #E2E4EA;
border-radius: 3px;
[purpose='current-progress'] {
background-color: #3DB67B;
height: 6px;
border-radius: 3px;
}
}
.form-group.is-invalid {
color: @core-vibrant-red;
.form-control {
color: @core-vibrant-red;
}
.invalid-feedback {
display: block;
}
}
[purpose='form-option'] {
user-select: none;
cursor: pointer;
width: fit-content;
padding: 8px 12px 8px 8px;
margin-bottom: 16px;
display: flex;
flex-direction: row;
align-items: center;
border-radius: 7px;
border: 1px solid #E2E4EA;
font-size: 16px;
line-height: 24px;
color: #515774;
white-space: nowrap;
height: fit-content;
input {
cursor: pointer;
margin-right: 8px;
display: none;
}
[purpose='custom-radio'] {
margin-right: 8px;
display: flex;
min-width: 18px;
min-height: 18px;
border-radius: 50%;
border: 1px solid #E2E4EA;
justify-content: center;
align-items: center;
[purpose='custom-radio-selected'] {
min-width: 10px;
min-height: 10px;
border-radius: 50%;
background-color: @core-vibrant-blue;
transform: scale(0);
transition: 180ms transform ease-in-out;
}
}
input[type='radio']:checked + [purpose='custom-radio'] {
[purpose='custom-radio-selected'] {
transform: scale(1);
}
}
.form-control {
height: 40px;
}
&:hover {
border: 1px solid @core-vibrant-blue;
}
&.selected {
border: 1px solid @core-vibrant-blue;
}
}
[purpose='form-buttons'] {
margin-top: 32px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: start;
user-select: none;
}
[purpose='submit-button'] {
padding: 12px;
font-size: 14px;
font-weight: 700;
line-height: 150%;
margin-right: 24px;
}
[purpose='back-button'] {
cursor: pointer;
font-size: 14px;
font-weight: 700;
line-height: 150%;
margin-right: 24px;
}
[purpose='start-cards'] {
display: flex;
@@ -31,13 +152,14 @@
}
[purpose='card'] {
width: 252px;
height: 200px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-decoration: none;
padding: 43px 52px;
cursor: pointer;
padding: 24px;
background: #FFF;
color: @core-fleet-black-75;
border-radius: 12px;
@@ -57,7 +179,7 @@
font-size: 12px;
font-weight: 400;
line-height: 150%;
white-space: nowrap;
// white-space: nowrap;
margin-bottom: 0px;
}
&:first-of-type {
@@ -68,6 +190,51 @@
}
}
[purpose='quote'] {
display: flex;
min-height: 300px;
padding: 32px;
flex-direction: column;
justify-content: center;
align-items: flex-start;
align-self: stretch;
border-radius: 16px;
background: #FFF;
box-shadow: none;
background-color: #FFF;
height: fit-content;
max-width: 100%;
text-align: left;
border: 1px solid @core-vibrant-blue-15;
[purpose='logo'] {
img {
max-height: 32px;
}
min-height: 0;
margin-bottom: 24px;
}
[purpose='quote-text'] {
margin-bottom: 24px;
font-size: 14px;
line-height: 150%;
}
[purpose='quote-author-info'] {
[purpose='job-title'] {
font-size: 12px;
line-height: 18px;
}
[purpose='name'] {
color: @core-fleet-black;
}
[purpose='profile-picture'] {
margin-right: 16px;
img {
height: 48px;
width: 48px;
}
}
}
}
@media (max-width: 991px) {
[purpose='page-container'] {
padding-top: 60px;
@@ -91,11 +258,23 @@
}
[purpose='start-cards'] {
flex-direction: column;
[purpose='card'] {
width: 100%;
}
}
[purpose='card']:first-of-type {
margin-right: unset;
margin-bottom: 20px;
}
[purpose='form-container'] {
width: unset;
margin-left: 0;
margin-right: 0;
}
[purpose='form-option'] {
white-space: unset;
width: unset;
}
}
@media (max-width: 375px) {
h1 {
+2 -1
View File
@@ -280,8 +280,8 @@ module.exports.routes = {
'GET /start': {
action: 'view-start',
locals: {
hideHeaderLinks: true,
hideFooterLinks: true,
hideGetStartedButton: true,
pageTitleForMeta: 'Start | Fleet',
pageDescriptionForMeta: 'Get Started with Fleet. Spin up a local demo or get your premium license key.',
}
@@ -577,4 +577,5 @@ module.exports.routes = {
'POST /api/v1/deliver-mdm-demo-email': { action: 'deliver-mdm-demo-email' },
'POST /api/v1/admin/provision-sandbox-instance-and-deliver-email': { action: 'admin/provision-sandbox-instance-and-deliver-email' },
'POST /api/v1/deliver-talk-to-us-form-submission': { action: 'deliver-talk-to-us-form-submission' },
'POST /api/v1/save-questionnaire-progress': { action: 'save-questionnaire-progress' },
};
+6 -6
View File
@@ -219,8 +219,8 @@ module.exports = {
<h1>${_.capitalize(scope.stem.replace(/\-/gim, ' '))}</h1>
<p>Vitae architecto reiciendis in temporibus consequatur doloremque reprehenderit perferendis? Eaque quod voluptates earum corporis, quo labore reprehenderit libero sint.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -274,8 +274,8 @@ module.exports = {
</div>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
@@ -296,8 +296,8 @@ module.exports = {
<h4>Open-source device management</h4>
<h1>Lighter than air</h1>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+7 -2
View File
@@ -8,6 +8,7 @@
var hideHeaderLinks;// Hides the header navigation links.
var hideFooterLinks;// Hides footer links, reduces the height of the footer to 60px;
var showAdminLinks;// Shows links to admin pages to admin users.
var hideGetStartedButton;// Hides the 'Get started' button in the website's navigation header.
// Applies personalization for who people come from ads, so that the website makes more sense for them:
var primaryBuyingSituation;
@@ -217,7 +218,9 @@
<a purpose="mobile-dropdown-link" href="/admin/email-preview">HTML Email preview tool</a>
</div>
<%}%>
<a purpose="glass-header-btn" style="padding: 4px 16px; line-height: 24px; width: 100px" class="btn btn-sm btn-primary align-items-center d-flex mt-4" href="/contact">Talk to us</a>
<%if(!hideGetStartedButton){%>
<a purpose="glass-header-btn" style="padding: 4px 16px; line-height: 24px; width: 100px" class="btn btn-sm btn-primary align-items-center d-flex mt-4" href="/register">Start now</a>
<% }%>
</div>
</div>
<%/* Desktop Navigation bar */%>
@@ -264,7 +267,9 @@
<iframe src="//ghbtns.com/github-btn.html?user=fleetdm&amp;repo=fleet&amp;type=watch&amp;count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
</span>
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/contact">Talk to us</a>
<%if(!hideGetStartedButton){%>
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/register">Start now</a>
<% }%>
<% if(_.has(me, 'id')) {%>
<a purpose="log-out-button" href="/logout" class="justify-content-end text-decoration-none">Log out</a>
<% }%>
+4 -4
View File
@@ -18,8 +18,8 @@
<strong>“Zero” trust, fewer tickets</strong>
<p>You can use Fleets API to customize every aspect of conditional access even the stuff your CISO hasnt thought of yet.</p>
<div purpose="button-row" class="d-flex flex-md-row flex-column justify-content-start align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -206,8 +206,8 @@
<h4>Device management (MDM)</h4>
<h2>Manage everything in one place</h2>
<div purpose="button-row" style="margin-top: 32px;" class="d-flex flex-md-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+4 -4
View File
@@ -18,8 +18,8 @@
<strong>Osquery on easy mode</strong>
<p>You dont need to be an osquery expert to get the answers you need from your devices, Fleet does some of that for you.</p>
<div purpose="button-row" class="d-flex flex-md-row flex-column justify-content-start align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -194,8 +194,8 @@
<h4>Endpoint operations</h4>
<h3>A consistent interface</h3>
<div purpose="button-row" style="margin-top: 32px;" class="d-flex flex-md-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
-13
View File
@@ -43,19 +43,6 @@
</div>
</div>
</div>
<div class="form-group">
<label for="primaryBuyingSituation">What will you be using Fleet for? *</label>
<div class="selectbox">
<select class="form-control" id="primaryBuyingSituation" name="primaryBuyingSituation" :class="[formErrors.primaryBuyingSituation ? 'is-invalid' : '']" v-model="formData.primaryBuyingSituation" @input="typeClearOneFormError('primaryBuyingSituation')">
<option disabled hidden value="undefined">Choose an option</option>
<option value="eo-security">Endpoint operations for security engineers</option>
<option value="eo-it">Endpoint operations for IT admins</option>
<option value="mdm">Device management (MDM)</option>
<option value="vm">Vulnerability management</option>
</select>
</div>
<div class="d-block invalid-feedback" v-if="formErrors.primaryBuyingSituation">Please select an option.</div>
</div>
</div>
<cloud-error v-if="cloudError==='emailAlreadyInUse'">
<p>This email is already linked to a Fleet account.<br> Please <a href="/login">sign in</a> with your email and password.</p>
+4 -4
View File
@@ -10,8 +10,8 @@
<h1><%- partial('../partials/primary-tagline.partial.ejs') %></h1>
<p>Replace the sprawl with open-source code that works the way you want.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -277,8 +277,8 @@
<h4>For teams with lots of different endpoints</h4>
<h1><%- partial('../partials/primary-tagline.partial.ejs') %></h1>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+4 -4
View File
@@ -8,8 +8,8 @@
<h1>Higher education meets simplified security</h1>
<p>Automate security workflows in a single application by creating or installing policies to identify which devices comply with your security guidelines.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -85,8 +85,8 @@
<h4>Open-source device management</h4>
<h1>Think for yourself</h1>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+4 -4
View File
@@ -8,8 +8,8 @@
<h1>Fleet brings GitOps to MDM</h1>
<p>Bringh-your-own MDM. Enjoy enterprise-ready open-source MDM and leverage the best of DevOps and GitOps inside a full-featured Macbook MDM.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -59,8 +59,8 @@
<h4>Open-source device management</h4>
<h1>Lighter than air</h1>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+4 -4
View File
@@ -8,8 +8,8 @@
<h1>Simplify vulnerability management</h1>
<p>Fleet, an open-source security platform, empowers you to take control of vulnerability management for your organization. Designed with modern DevOps practices in mind, Fleet offers superior visibility, rapid response capabilities, and seamless integration with your existing workflows.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -100,8 +100,8 @@
<h4>Open-source device management</h4>
<h1>Lighter than air</h1>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
+4 -4
View File
@@ -8,8 +8,8 @@
<h1>Discover unused software licenses and optimize your IT budget</h1>
<p>Fleet, the leading open-source, flexible device management solution, offers unprecedented visibility into your IT infrastructure, making it the ideal tool to discover and manage unused software licenses. This capability is essential to unlocking more IT budget, enhancing security, and ultimately improving the employee experience.</p>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -64,8 +64,8 @@
</div>
<div purpose="button-row" style="margin-top: 60px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
+1 -1
View File
@@ -43,7 +43,7 @@
</div>
</div>
<div>
<a purpose="card-button" class="btn btn-block btn-lg btn-primary mx-auto mb-0" href="/customers/register">Get started</a>
<a purpose="card-button" class="btn btn-block btn-lg btn-primary mx-auto mb-0" href="/register">Get started</a>
</div>
</div>
</div>
+512 -16
View File
@@ -1,23 +1,519 @@
<div id="start" v-cloak>
<div class="d-flex container" purpose="page-container">
<div class="text-center mx-auto">
<h1>Welcome to Fleet</h1>
<p class="mb-0">Spin up a local demo or get your Fleet Premium license key.</p>
<div purpose="form-container">
<%// ┌─┐┌┬┐┌─┐┬─┐┌┬┐
// └─┐ │ ├─┤├┬┘ │
// └─┘ ┴ ┴ ┴┴└─ ┴ %>
<div v-if="currentStep === 'start'">
<div class=" mx-auto">
<h2>Lets get started</h2>
<p>To see whether Fleets right for your team, let's have a look at your hosts and what you're trying to do.</p>
<p>You can come back at any time and pick up where you left off.</p>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['start']" :form-rules="formRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div purpose="form-buttons">
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Start</ajax-button>
</div>
</ajax-form>
</div>
</div>
<div purpose="start-cards">
<a purpose="card" href="/try-fleet">
<img alt="Run a local demo of Fleet" src="/images/start-try-fleet-64x64@2x.png">
<h2>Try Fleet</h2>
<p>Run a local demo of Fleet</p>
</a>
<a purpose="card" href="/new-license">
<img alt="Purchase a Fleet Premium license" src="/images/start-purchase-license-64x64@2x.png">
<h2>Start</h2>
<p>Purchase a Fleet Premium license</p>
</a>
<%// ┬ ┬┬ ┬┌─┐┌┬┐ ┌─┐┬─┐┌─┐ ┬ ┬┌─┐┬ ┬ ┬ ┬┌─┐┬┌┐┌┌─┐ ┌─┐┬ ┌─┐┌─┐┌┬┐ ┌─┐┌─┐┬─┐
// │││├─┤├─┤ │ ├─┤├┬┘├┤ └┬┘│ ││ │ │ │└─┐│││││ ┬ ├┤ │ ├┤ ├┤ │ ├┤ │ │├┬┘
// └┴┘┴ ┴┴ ┴ ┴ ┴ ┴┴└─└─┘ ┴ └─┘└─┘ └─┘└─┘┴┘└┘└─┘ └ ┴─┘└─┘└─┘ ┴ └ └─┘┴└─%>
<div v-if="currentStep === 'what-are-you-using-fleet-for'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 20%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>What will you use Fleet for?</h2>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['what-are-you-using-fleet-for']" :form-rules="primaryBuyingSituationFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group" :class="[formErrors.primaryBuyingSituation ? 'is-invalid' : '']" >
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'eo-security' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-using-fleet-for'].primaryBuyingSituation" value="eo-security" @input="clickClearOneFormError('primaryBuyingSituation')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Endpoint ops for security engineers
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'eo-it' ? 'selected' : '']">
<input type="radio" :class="[formErrors.primaryBuyingSituation ? 'is-invalid' : '']" v-model.trim="formData['what-are-you-using-fleet-for'].primaryBuyingSituation" value="eo-it" @input="clickClearOneFormError('primaryBuyingSituation')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Endpoint ops for IT admins
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'mdm' ? 'selected' : '']">
<input type="radio" :class="[formErrors.primaryBuyingSituation ? 'is-invalid' : '']" v-model.trim="formData['what-are-you-using-fleet-for'].primaryBuyingSituation" value="mdm" @input="clickClearOneFormError('primaryBuyingSituation')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Device management (MDM)
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'vm' ? 'selected' : '']">
<input type="radio" :class="[formErrors.primaryBuyingSituation ? 'is-invalid' : '']" v-model.trim="formData['what-are-you-using-fleet-for'].primaryBuyingSituation" value="vm" @input="clickClearOneFormError('primaryBuyingSituation')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Vulnerability management
</label>
<div class="invalid-feedback" v-if="formErrors.primaryBuyingSituation">Please select an option</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="form-buttons">
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┬┌─┐┬ ┬┌─┐ ┬ ┬┌─┐┬ ┬ ┌─┐┬ ┬┌─┐┬─┐ ┬ ┬┌─┐┌─┐┌┬┐ ┌─┐┬ ┌─┐┌─┐┌┬┐
// ├─┤├─┤└┐┌┘├┤ └┬┘│ ││ │ ├┤ └┐┌┘├┤ ├┬┘ │ │└─┐├┤ ││ ├┤ │ ├┤ ├┤ │
// ┴ ┴┴ ┴ └┘ └─┘ ┴ └─┘└─┘ └─┘ └┘ └─┘┴└─ └─┘└─┘└─┘─┴┘ └ ┴─┘└─┘└─┘ ┴ %>
<div v-if="currentStep === 'have-you-ever-used-fleet'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 40%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>Have you ever used Fleet?</h2>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['have-you-ever-used-fleet']" :form-rules="isUsingFleetFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group" :class="[formErrors.fleetUseStatus ? 'is-invalid' : '']">
<label purpose="form-option" class="form-control" :class="[formData['have-you-ever-used-fleet'].fleetUseStatus === 'yes-deployed' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['have-you-ever-used-fleet'].fleetUseStatus" value="yes-deployed" @input="clickClearOneFormError('fleetUseStatus')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Yes, we actively use Fleet at work today
</label>
<label purpose="form-option" class="form-control" :class="[formData['have-you-ever-used-fleet'].fleetUseStatus === 'yes-recently-deployed' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['have-you-ever-used-fleet'].fleetUseStatus" value="yes-recently-deployed" @input="clickClearOneFormError('fleetUseStatus')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Yes, we deployed Fleet at work recently to try it out
</label>
<label purpose="form-option" class="form-control" :class="[formData['have-you-ever-used-fleet'].fleetUseStatus === 'yes-deployed-local' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['have-you-ever-used-fleet'].fleetUseStatus" value="yes-deployed-local" @input="clickClearOneFormError('fleetUseStatus')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Yes, but only in a local / homelab environment
</label>
<label purpose="form-option" class="form-control" :class="[formData['have-you-ever-used-fleet'].fleetUseStatus === 'yes-deployed-long-time' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['have-you-ever-used-fleet'].fleetUseStatus" value="yes-deployed-long-time" @input="clickClearOneFormError('fleetUseStatus')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Yes, but it's been a long time
</label>
<label purpose="form-option" class="form-control" :class="[formData['have-you-ever-used-fleet'].fleetUseStatus === 'no' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['have-you-ever-used-fleet'].fleetUseStatus" value="no" @input="clickClearOneFormError('fleetUseStatus')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
No, not yet
</label>
<div class="invalid-feedback" v-if="formErrors.fleetUseStatus">Please select an option</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┬┌─┐┬ ┬ ┌┬┐┌─┐┌┐┌┬ ┬ ┬ ┬┌─┐┌─┐┌┬┐┌─┐
// ├─┤│ ││││ │││├─┤│││└┬┘ ├─┤│ │└─┐ │ └─┐
// ┴ ┴└─┘└┴┘ ┴ ┴┴ ┴┘└┘ ┴ ┴ ┴└─┘└─┘ ┴ └─┘%>
<div v-if="currentStep === 'how-many-hosts'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 70%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>How many hosts do you have:</h2>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['how-many-hosts']" :form-rules="numberOfHostsFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group">
<div class="form-group" :class="[formErrors.numberOfHosts ? 'is-invalid' : '']">
<label purpose="form-option" class="form-control" :class="[formData['how-many-hosts'].numberOfHosts === '1-100' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['how-many-hosts'].numberOfHosts" value="1-100" @input="clickClearOneFormError('numberOfHosts')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
1 to 100
</label>
<label purpose="form-option" class="form-control" :class="[formData['how-many-hosts'].numberOfHosts === '100-700' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['how-many-hosts'].numberOfHosts" value="100-700" @input="clickClearOneFormError('numberOfHosts')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
100 to 700
</label>
<label purpose="form-option" class="form-control" :class="[formData['how-many-hosts'].numberOfHosts === '700-10000' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['how-many-hosts'].numberOfHosts" value="700-10000" @input="clickClearOneFormError('numberOfHosts')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
700 to 10,000
</label>
<label purpose="form-option" class="form-control" :class="[formData['how-many-hosts'].numberOfHosts === '10000+' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['how-many-hosts'].numberOfHosts" value="10000+" @input="clickClearOneFormError('numberOfHosts')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
More than 10,000
</label>
<div class="invalid-feedback" v-if="formErrors.numberOfHosts">Please select an option</div>
</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┬┬┬ ┬ ┬ ┬┌─┐┬ ┬ ┌┐ ┌─┐ ┌─┐┌─┐┬ ┌─┐ ┬ ┬┌─┐┌─┐┌┬┐┬┌┐┌┌─┐
// │││││ │ └┬┘│ ││ │ ├┴┐├┤ └─┐├┤ │ ├┤ ├─┤│ │└─┐ │ │││││ ┬
// └┴┘┴┴─┘┴─┘ ┴ └─┘└─┘ └─┘└─┘ └─┘└─┘┴─┘└ ┴ ┴└─┘└─┘ ┴ ┴┘└┘└─┘%>
<div v-if="currentStep === 'will-you-be-self-hosting'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 90%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>Will you be hosting Fleet yourself?</h2>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['will-you-be-self-hosting']" :form-rules="hostingFleetFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group" :class="[formErrors.willSelfHost ? 'is-invalid' : '']" >
<label purpose="form-option" class="form-control" :class="[formData['will-you-be-self-hosting'].willSelfHost === 'true' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['will-you-be-self-hosting'].willSelfHost" value="true" @input="clickClearOneFormError('willSelfHost')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Yes, self hosted
</label>
<label purpose="form-option" class="form-control" :class="[formData['will-you-be-self-hosting'].willSelfHost === 'false' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['will-you-be-self-hosting'].willSelfHost" value="false" @input="clickClearOneFormError('willSelfHost')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
I'd prefer not to
</label>
<div class="invalid-feedback" v-if="formErrors.willSelfHost">Please select an option</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┬┬ ┬┌─┐┌┬┐ ┌─┐┬─┐┌─┐ ┬ ┬┌─┐┬ ┬ ┬ ┬┌─┐┬─┐┬┌─┬┌┐┌┌─┐ ┌─┐┌┐┌
// │││├─┤├─┤ │ ├─┤├┬┘├┤ └┬┘│ ││ │ ││││ │├┬┘├┴┐│││││ ┬ │ ││││ ───
// └┴┘┴ ┴┴ ┴ ┴ ┴ ┴┴└─└─┘ ┴ └─┘└─┘ └┴┘└─┘┴└─┴ ┴┴┘└┘└─┘ └─┘┘└┘
// ┌─┐┌─┐ ┌─┐┌─┐┌─┐┬ ┬┬─┐┬┌┬┐┬ ┬
// ├┤ │ │───└─┐├┤ │ │ │├┬┘│ │ └┬┘
// └─┘└─┘ └─┘└─┘└─┘└─┘┴└─┴ ┴ ┴%>
<div v-if="currentStep === 'what-are-you-working-on-eo-security'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 60%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>What are you working on, mainly?</h2>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['what-are-you-working-on-eo-security']" :form-rules="endpointOpsSecurityWorkingOnFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group">
<div class="form-group" :class="[formErrors.endpointOpsSecurityUseCase ? 'is-invalid' : '']">
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'detection-and-response' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="detection-and-response" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Detection and response
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'production-infrastructure-security' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="production-infrastructure-security" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Production infrastructure / security
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'identity-and-access-management-endpoint-security' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="identity-and-access-management-endpoint-security" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Identity and access management (IAM) / endpoint security
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'cyber-threat-intelligence' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="cyber-threat-intelligence" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Cyber-threat intelligence (CTI)
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'risk-grc' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="risk-grc" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Risk (GRC)
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase === 'ot-ics-iot-security' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-are-you-working-on-eo-security'].endpointOpsSecurityUseCase" value="ot-ics-iot-security" @input="clickClearOneFormError('endpointOpsSecurityUseCase')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
OT / ICS / IoT security
</label>
<div class="invalid-feedback" v-if="formErrors.endpointOpsSecurityUseCase">Please select an option</div>
</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬┌─┐ ┬┌┬┐ ┌─┐┌┐┌┬ ┬ ┌─┐┌─┐┌─┐┌┬┐
// │└─┐ │ │ ├─┤│││└┬┘ │ ┬│ ││ │ ││
// ┴└─┘ ┴ ┴ ┴ ┴┘└┘ ┴ └─┘└─┘└─┘─┴┘%>
<div v-if="currentStep === 'is-it-any-good'">
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['is-it-any-good']" :form-rules="formRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 80%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<div class="mx-auto">
<h2>Is it any good?</h2>
<p class="mb-0">We dont have a public sample environment, but you can try Fleet out locally on your computer.</p>
</div>
<div purpose="start-cards">
<a purpose="card" href="/try-fleet">
<img alt="Run a local demo of Fleet" src="/images/start-try-fleet-64x64@2x.png">
<h2>Try Fleet yourself</h2>
<p>Try Fleet locally on your device</p>
</a>
<a purpose="card" href="/docs/get-started">
<img alt="Purchase a Fleet Premium license" src="/images/homepage-icon-documentation-64x64@2x.png">
<h2>Read the docs</h2>
<p>See what Fleet can do</p>
</a>
</div>
<p>You can come back here any time to continue with your deployment.</p>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┬┬ ┬┌─┐┌┬┐ ┌┬┐┬┌┬┐ ┬ ┬┌─┐┬ ┬ ┌┬┐┬ ┬┬┌┐┌┬┌─
// │││├─┤├─┤ │ │││ ││ └┬┘│ ││ │ │ ├─┤││││├┴┐
// └┴┘┴ ┴┴ ┴ ┴ ─┴┘┴─┴┘ ┴ └─┘└─┘ ┴ ┴ ┴┴┘└┘┴ ┴%>
<div v-if="currentStep === 'what-did-you-think'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 90%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<h2>What did you think?</h2>
<p>Now that youve seen what Fleet can do, what do you want to do next?</p>
<ajax-form :handle-submitting="handleSubmittingForm" class="contact" :form-errors.sync="formErrors" :form-data="formData['what-did-you-think']" :form-rules="endpointOpsSecurityWhatDidYouThinkFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div class="form-group" :class="[formErrors.whatDidYouThink ? 'is-invalid' : '']">
<div purpose="form-option" class="form-control" @click.stop.prevent="clickGoToContactPage()">
<input type="radio" v-model.trim="formData['what-did-you-think'].whatDidYouThink" value="Id like you to host Fleet for me">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Id like you to host Fleet for me
</div>
<label purpose="form-option" class="form-control" :class="[formData['what-did-you-think'].whatDidYouThink === 'deploy-fleet-in-environemnt' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-did-you-think'].whatDidYouThink" value="deploy-fleet-in-environemnt" @input="clickClearOneFormError('whatDidYouThink')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Id like to deploy Fleet in my environment
</label>
<label purpose="form-option" class="form-control" :class="[formData['what-did-you-think'].whatDidYouThink === 'let-me-think-about-it' ? 'selected' : '']">
<input type="radio" v-model.trim="formData['what-did-you-think'].whatDidYouThink" value="let-me-think-about-it" @input="clickClearOneFormError('whatDidYouThink')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
Let me think about it
</label>
<div class="invalid-feedback" v-if="formErrors.whatDidYouThink">Please select an option</div>
</div>
<cloud-error v-if="cloudError"></cloud-error>
<div purpose="quote" v-if="!formData['what-are-you-using-fleet-for'].primaryBuyingSituation">
<div purpose="logo" class="mb-4"><img height="32" alt="Deloitte logo" src="/images/social-proof-logo-deloitte-130x32@2x.png"></div>
<p purpose="quote-text">
Something I really appreciate about working with you guys is that it doesn't feel like I'm talking to a vendor. It actually feels like I'm talking to my team, and I really appreciate it.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Chandra Majumdar" src="/images/testimonial-author-chandra-majumdar-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Chandra Majumdar</p>
<p purpose="job-title" class="m-0">Partner - Cyber and Strategic Risk</p>
</div>
</div>
</div>
<div purpose="quote" v-else-if="formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'mdm'">
<div purpose="logo" class="mb-4"><img height="32" alt="Uber logo" src="/images/social-proof-logo-uber-71x32@2x.png"></div>
<p purpose="quote-text">
Exciting. This is a team that listens to feedback.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Erik Gomez" src="/images/testimonial-author-erik-gomez-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Erik Gomez</p>
<p purpose="job-title" class="m-0">Staff Client Platform Engineer</p>
</div>
</div>
</div>
<div purpose="quote" v-else-if="formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'vm'">
<p purpose="quote-text">
The visibility down into the assets covered by the agent is phenomenal. Fleet has become the central source for a lot of things.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Andre Shields" src="/images/testimonial-author-andre-shields-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Andre Shields</p>
<p purpose="job-title" class="m-0">Staff Cybersecurity Engineer, Vulnerability Management</p>
</div>
</div>
</div>
<div purpose="quote" v-else-if="formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'eo-it'">
<div purpose="logo" class="mb-4"><img height="32" alt="Deputy logo" src="/images/logo-deputy-118x28@2x.png"></div>
<p purpose="quote-text">
When we look at vendors, we look for ones that are very receptive to feedback, where youre just part of the family, I guess. Fleets really good at that.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Harrison Ravazzolo" src="/images/testimonial-author-harrison-ravazzolo-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Harrison Ravazzolo</p>
<p purpose="job-title" class="m-0">Lead platform and identity engineer</p>
</div>
</div>
</div>
<div purpose="quote" v-else-if="formData['what-are-you-using-fleet-for'].primaryBuyingSituation === 'eo-security'">
<div purpose="logo" class="mb-4"><img height="32" alt="Atlassian logo" src="/images/social-proof-logo-atlassian-192x32@2x.png"></div>
<p purpose="quote-text">
I love the steady and consistent delivery of features that help teams work how they want to work, not how your product dictates they work.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Dan Grzelak" src="/images/testimonial-author-daniel-grzelak-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Dan Grzelak</p>
<p purpose="job-title" class="m-0">Security Chief of Staff</p>
</div>
</div>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
<ajax-button type="submit" purpose="submit-button" class="btn btn-primary">Continue</ajax-button>
</div>
</ajax-form>
</div>
<%// ┬ ┌─┐┌┬┐┌─┐ ┌┬┐┌─┐┬ ┬┌─ ┌┬┐┌─┐ ┬ ┬┌─┐┬ ┬┬─┐ ┌┬┐┌─┐┌─┐┌┬┐
// │ ├┤ │ └─┐ │ ├─┤│ ├┴┐ │ │ │ └┬┘│ ││ │├┬┘ │ ├┤ ├─┤│││
// ┴─┘└─┘ ┴ └─┘ ┴ ┴ ┴┴─┘┴ ┴ ┴ └─┘ ┴ └─┘└─┘┴└─ ┴ └─┘┴ ┴┴ ┴%>
<div v-if="currentStep === 'lets-talk-to-your-team'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 100%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<div class=" mx-auto">
<h2>Lets talk to your team</h2>
<p>Great, lets jump on a call to talk more about your fleet.</p>
</div>
<div purpose="start-cards">
<a purpose="card" @click="clickGoToCalendly()">
<img alt="Premium support" src="/images/icon-premium-support-64x64@2x.png">
<h2>Work with us</h2>
<p>Get support and training or schedule a personalized demo for your team.</p>
</a>
<a purpose="card" @click="clickGoToCalendly()">
<img alt="Ask us anything" src="/images/icon-ask-anything-64x64@2x.png">
<h2>Got questions?</h2>
<p>Grab some time and ask us anything.</p>
</a>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
</div>
</div>
<%// ╔╦╗┌─┐┌─┐┬ ┌─┐┬ ┬ ┌─┐┬ ┌─┐┌─┐┌┬┐ ┬┌┐┌ ┬ ┬┌─┐┬ ┬┬─┐ ┌─┐┌┐┌┬ ┬┬┬─┐┌─┐┌┐┌┌┬┐┌─┐┌┐┌┌┬┐
// ║║├┤ ├─┘│ │ │└┬┘ ├┤ │ ├┤ ├┤ │ ││││ └┬┘│ ││ │├┬┘ ├┤ │││└┐┌┘│├┬┘│ │││││││├┤ │││ │
// ═╩╝└─┘┴ ┴─┘└─┘ ┴ └ ┴─┘└─┘└─┘ ┴ ┴┘└┘ ┴ └─┘└─┘┴└─ └─┘┘└┘ └┘ ┴┴└─└─┘┘└┘┴ ┴└─┘┘└┘ ┴%>
<div v-if="currentStep === 'deploy-fleet-in-your-environment'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 100%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<div class="mx-auto">
<h2>Deploy Fleet in your environment</h2>
<p>Learn how to deploy and roll out Fleet in your environment.</p>
</div>
<div purpose="start-cards">
<a purpose="card" href="/docs/deploy">
<img alt="Premium support" src="/images/icon-deploy-fleet-64x64@2x.png">
<h2>Deploy Fleet</h2>
<p>Learn how to deploy Fleet</p>
</a>
<a purpose="card" href="/support">
<img alt="Ask us anything" src="/images/icon-ask-anything-64x64@2x.png">
<h2>Got questions?</h2>
<p>Ask Fleets community of helpful, knowledgeable people.</p>
</a>
</div>
<div purpose="logo-container">
<logo-carousel></logo-carousel>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
</div>
</div>
<%// ┌─┐┌─┐┬ ┌─┐ ┬ ┬┌─┐┌─┐┌┬┐┌─┐┌┬┐ ┌┬┐┌─┐┌─┐┬ ┌─┐┬ ┬
// └─┐├┤ │ ├┤───├─┤│ │└─┐ │ ├┤ ││ ││├┤ ├─┘│ │ │└┬┘
// └─┘└─┘┴─┘└ ┴ ┴└─┘└─┘ ┴ └─┘─┴┘ ─┴┘└─┘┴ ┴─┘└─┘ ┴%>
<div v-if="currentStep === 'self-hosted-deploy'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 100%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<div class="mx-auto">
<h2>Deploy Fleet in your environment</h2>
<p>Learn how to deploy and rollout Fleet in your environment, get a Fleet Premium license, or both. You can come back in any time to upgrade.</p>
</div>
<div purpose="start-cards">
<a purpose="card" href="/docs/deploy">
<img alt="Premium support" src="/images/icon-deploy-fleet-64x64@2x.png">
<h2>Deploy Fleet</h2>
<p>Learn how to deploy Fleet</p>
</a>
<a purpose="card" href="/new-license">
<img alt="Purchase a Fleet Premium license" src="/images/start-purchase-license-64x64@2x.png">
<h2>Get a license</h2>
<p>Purchase a Fleet Premium license</p>
</a>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
</div>
</div>
<%// ┌┬┐┌─┐┌┐┌┌─┐┌─┐┌─┐┌┬┐ ┌─┐┬ ┌─┐┬ ┬┌┬┐ ┌─┐┌─┐┬─┐ ┌─┐┬─┐┌─┐┬ ┬┬┌┐┌┌─┐
// │││├─┤│││├─┤│ ┬├┤ ││ │ │ │ ││ │ ││ ├┤ │ │├┬┘ │ ┬├┬┘│ │││││││││ ┬
// ┴ ┴┴ ┴┘└┘┴ ┴└─┘└─┘─┴┘ └─┘┴─┘└─┘└─┘─┴┘ └ └─┘┴└─ └─┘┴└─└─┘└┴┘┴┘└┘└─┘
// ┌┬┐┌─┐┌─┐┬ ┌─┐┬ ┬┌┬┐┌─┐┌┐┌┌┬┐┌─┐
// ││├┤ ├─┘│ │ │└┬┘│││├┤ │││ │ └─┐
// ─┴┘└─┘┴ ┴─┘└─┘ ┴ ┴ ┴└─┘┘└┘ ┴ └─┘%>
<div v-if="currentStep === 'managed-cloud-for-growing-deployments'">
<div purpose="progress-bar-container">
<div purpose="form-progress-bar"><div purpose="current-progress" style="width: 100%"></div></div>
<img purpose="success-icon" alt="🏆" src="/images/icon-form-success-12x12@2x.png">
</div>
<div class="mx-auto">
<h2>Managed cloud for growing deployments</h2>
<p>Unfortunately, managed cloud hosting is not yet available for growing deployments of less than 700 hosts.</p>
</div>
<div purpose="start-cards" class="justify-content-start">
<a purpose="card" href="/docs/deploy">
<img alt="Premium support" src="/images/icon-deploy-fleet-64x64@2x.png">
<h2>Deploy Fleet</h2>
<p>Learn how to deploy Fleet</p>
</a>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
</div>
</div>
<%// ┬ ┬┌─┐┬ ┌─┐┌─┐┌┬┐┌─┐ ┌┬┐┌─┐ ┌─┐┬ ┌─┐┌─┐┌┬┐
// │││├┤ │ │ │ ││││├┤ │ │ │ ├┤ │ ├┤ ├┤ │
// └┴┘└─┘┴─┘└─┘└─┘┴ ┴└─┘ ┴ └─┘ └ ┴─┘└─┘└─┘ ┴%>
<div v-if="currentStep === 'welcome-to-fleet'">
<div class="text-center mx-auto">
<h1>Welcome to Fleet</h1>
<p class="mb-0">Spin up a local demo or get your Fleet Premium license key.</p>
</div>
<div purpose="start-cards">
<a purpose="card" href="/try-fleet">
<img alt="Run a local demo of Fleet" src="/images/start-try-fleet-64x64@2x.png">
<h2>Try Fleet</h2>
<p>Run a local demo of Fleet</p>
</a>
<a purpose="card" href="/new-license">
<img alt="Purchase a Fleet Premium license" src="/images/start-purchase-license-64x64@2x.png">
<h2>Get a license</h2>
<p>Purchase a Fleet Premium license</p>
</a>
</div>
<div purpose="logo-container">
<logo-carousel></logo-carousel>
</div>
<div purpose="form-buttons">
<a purpose="back-button" @click="clickGoToPreviousStep()">Back</a>
</div>
</div>
<div purpose="logo-container">
<logo-carousel></logo-carousel>
</div>
</div>
</div>
+4 -4
View File
@@ -18,8 +18,8 @@
<strong>Untangle your security stack</strong>
<p>Use open data and APIs to connect your vulnerability solution with osquery, the agent you might already have deployed.</p>
<div purpose="button-row" class="d-flex flex-md-row flex-column justify-content-start align-items-center">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>
@@ -142,8 +142,8 @@
<h4>Open-source vulnerability management</h4>
<h2>Build the vulnerability program you actually want</h2>
<div purpose="button-row" style="margin-top: 32px;" class="d-flex flex-md-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Talk to us</a>
<a purpose="animated-arrow-button-red" href="/register">Try it out</a>
<a purpose="cta-button" href="/register">Start now</a>
<a purpose="animated-arrow-button-red" href="/contact">Talk to us</a>
</div>
</div>
</div>