Put live documentation on fleetdm.com (#1380)
* minor clarifications * further expand comments and stubs * absorb custom titles embedded in metadata, plus further comment expansion and a followup fix for something i left hanging in f8cbc14829d91e7577c63307fd9c4346dbc229bb * Skip non-markdown files and use real path maths * Prep for running in parallel (Remove `continue` so this isn't dependent on the `for` loop) * determine + track unique HTML output paths * Compile markdown + spit out real HTML (without involving any but the crunchy nougaty dependency from the very center of everything) * add md metadata parsing * add timestamp * Update build-static-content.js * attach misc metadata as "other" * how doc images might should work (this also aligns with how the select few images in the sailsjs.com docs work) * add file extension to generated HTML files * "options"=>"meta" * Make "htmlId" useful for alphabetically sorting pages within their bottom-level section See recent comments on https://github.com/fleetdm/fleet/issues/706 for more information. * list out the most important, specific build-time transformations * Omit ordering prefixes like "1-" from expected content page URLs * add a little zone for consolidating backwards compatible permalinks * interpret README.md files by mapping their URLs to match their containing folder * clarify plan for images * decrease probability of collisions * Make capitalization smarter using known acronyms, proper nouns, and a smarter numeric word trim * Resolve app path in case pwd is different in prod * Delete HTML output from previous runs, if any * condense the stuff about github emojis * got rid of "permalink" thing, since id gets automatically attached during markdown compilation anyway Also "permalink" isn't even a good name for what this is. See https://github.com/fleetdm/fleet/issues/706#issuecomment-884693931 * …and that eliminates the need for the cheerio dep! * Bring in bubbles+syntax highlighting into build script, and remove sails.helpers.compileMarkdownContent() -- this leaves link munging as a todo though * trivial (condense comments) * Remove unused code from toHtml() helper * Implemented target="_blank" and root-relative-ification * remove todo about emojis after testing and verifying it works just fine * trivial: add link to comment in case github emojis matter at some point * consolidate "what ifs" in comments * Leave this up to Sarah, for now. (Either bring it back here in the build script or do it all on the frontend) * Enable /docs and /handbook routes, and add example of a redirect for a legacy/deprecated URL * implement routing * Upgrade deps this takes advantages of the latest work from @eashaw, @rachaelshaw, and the rest of the Sails community * tweak var names and comments * make readme pages use their folder names to determine their default (fallback) titles as discussed in https://github.com/fleetdm/fleet/issues/706#issuecomment-884788002 * first (good enough for now) pass at link rewriting as discussed in https://github.com/fleetdm/fleet/issues/706#issuecomment-884742072 * Adapt docs pages to build from markdown output * Continue work on docs pages * Add landing page * Remove unused code; minor changes * Replace regex * fixes https://github.com/fleetdm/fleet/pull/1380#issuecomment-891429581 * Don't rely on "path" being a global var * Syle fleetdm doc pages * Continue work on docs pages * Fix linting error * Disable lesshint style warnings * parasails-has-no-page-script attribute Added a parasails-has-no-page-script attribute to the docs template, added a check for that attribute in parasails.js and removed the empty page script for 498 * bring in latest parasails dep * trivial * Update links to dedupe and not open in new tab unless actually external * Disable handbook for now til styles are ready * fix CTA links * trivial * make sitemap.xml get served in prod * hide search boxes for now, remove hard-coded version and make releases open in new tab * clean out unused files Co-authored-by: gillespi314 <73313222+gillespi314@users.noreply.github.com> Co-authored-by: eashaw <caglc@live.com>
This commit is contained in:
co-authored by
gillespi314
eashaw
parent
93ace41f2b
commit
8097251565
@@ -59,3 +59,5 @@ Let's say you have two teams in Fleet. One team is named "Workstations" and the
|
||||
To configure team agent options, head to **Settings > Teams > `Team-name-here` > Agent options**.
|
||||
|
||||

|
||||
|
||||
<meta name="title" value="Fleet UI">
|
||||
|
||||
+45
-8
@@ -7,23 +7,60 @@ module.exports = {
|
||||
description: 'Display "Basic documentation" page.',
|
||||
|
||||
|
||||
exits: {
|
||||
urlWildcardSuffix: 'pageUrlSuffix',
|
||||
|
||||
success: {
|
||||
viewTemplatePath: 'pages/docs/basic-documentation'
|
||||
|
||||
inputs: {
|
||||
pageUrlSuffix : {
|
||||
description: 'The relative path to the doc page from within this route. (i.e. the URL wildcard suffix)',
|
||||
example: 'using-fleet/supported-browsers',
|
||||
type: 'string',
|
||||
defaultsTo: ''
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function () {
|
||||
exits: {
|
||||
success: { viewTemplatePath: 'pages/docs/basic-documentation' },
|
||||
badConfig: { responseType: 'badConfig' },
|
||||
notFound: { responseType: 'notFound' },
|
||||
redirect: { responseType: 'redirect' },
|
||||
},
|
||||
|
||||
// Serve appropriate doc page content.
|
||||
|
||||
fn: async function ({pageUrlSuffix}) {
|
||||
|
||||
if (!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.markdownPages) || !sails.config.builtStaticContent.compiledPagePartialsAppPath) {
|
||||
throw {badConfig: 'builtStaticContent.markdownPages'};
|
||||
}
|
||||
|
||||
let SECTION_URL_PREFIX = '/docs';
|
||||
|
||||
// Serve appropriate page content.
|
||||
// > Inspired by https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/controllers/documentation/view-documentation.js
|
||||
// TODO
|
||||
let thisPage = _.find(sails.config.builtStaticContent.markdownPages, {
|
||||
url: _.trimRight(SECTION_URL_PREFIX + '/' + _.trim(pageUrlSuffix, '/'), '/')
|
||||
});
|
||||
// console.log('pageUrlSuffix:',pageUrlSuffix);
|
||||
// console.log('SECTION_URL_PREFIX + "/" + _.trim(pageUrlSuffix, "/"):',SECTION_URL_PREFIX + '/' + _.trim(pageUrlSuffix, '/'));
|
||||
// console.log('thisPage:',thisPage);
|
||||
if (!thisPage) {
|
||||
throw 'notFound';
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// TODO: add "redirect" exit and handle mismatched capitalization / extra slashes by redirecting to the correct URL. e.g. "http://localhost:2024/docs//usiNG-fleet///" Partial example of this: https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/controllers/documentation/view-documentation.js#L161-L166
|
||||
let revisedUrl = 'todo';
|
||||
throw {redirect: revisedUrl};
|
||||
}
|
||||
|
||||
// Respond with view.
|
||||
return {};
|
||||
return {
|
||||
path: require('path'),
|
||||
thisPage: thisPage,
|
||||
markdownPages: sails.config.builtStaticContent.markdownPages,
|
||||
compiledPagePartialsAppPath: sails.config.builtStaticContent.compiledPagePartialsAppPath
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
-6
@@ -16,7 +16,6 @@ module.exports = {
|
||||
exits: {
|
||||
success: { outputFriendlyName: 'Sitemap (XML)', outputType: 'string' },
|
||||
badConfig: { responseType: 'badConfig' },
|
||||
notFound: { responseType: 'notFound' }// « TODO: delete this and the code that calls it below when all pages are ready
|
||||
},
|
||||
|
||||
|
||||
@@ -27,11 +26,6 @@ module.exports = {
|
||||
// and for the real thing to be served in production, while explicitly preventing the "whoops,
|
||||
// i deployed staging and search engine crawlers got fixated on the wrong sitemap" dilemma.
|
||||
throw new Error('Since this is the staging environment, prevented sitemap.xml from being served to avoid search engine accidents.');
|
||||
}//•
|
||||
|
||||
if (sails.config.environment === 'production') {// TODO: Remove this once the pages are ready.
|
||||
// Don't serve a sitemap until the pages actually work.
|
||||
throw 'notFound';
|
||||
}
|
||||
|
||||
if (!_.isObject(sails.config.builtStaticContent)) {
|
||||
|
||||
+42
-8
@@ -7,23 +7,57 @@ module.exports = {
|
||||
description: 'Display "Basic handbook" page.',
|
||||
|
||||
|
||||
exits: {
|
||||
urlWildcardSuffix: 'pageUrlSuffix',
|
||||
|
||||
success: {
|
||||
viewTemplatePath: 'pages/handbook/basic-handbook'
|
||||
|
||||
inputs: {
|
||||
pageUrlSuffix : {
|
||||
description: 'The relative path to the doc page from within this route. (i.e. the URL wildcard suffix)',
|
||||
example: 'handbook/release-process',
|
||||
type: 'string',
|
||||
defaultsTo: ''
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function () {
|
||||
exits: {
|
||||
success: { viewTemplatePath: 'pages/handbook/basic-handbook' },
|
||||
badConfig: { responseType: 'badConfig' },
|
||||
notFound: { responseType: 'notFound' },
|
||||
redirect: { responseType: 'redirect' },
|
||||
},
|
||||
|
||||
// Serve appropriate handbook page content.
|
||||
|
||||
fn: async function ({pageUrlSuffix}) {
|
||||
|
||||
if (!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.markdownPages) || !sails.config.builtStaticContent.compiledPagePartialsAppPath) {
|
||||
throw {badConfig: 'builtStaticContent.markdownPages'};
|
||||
}
|
||||
|
||||
let SECTION_URL_PREFIX = '/handbook';
|
||||
|
||||
// Serve appropriate page content.
|
||||
// > Inspired by https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/controllers/documentation/view-documentation.js
|
||||
// TODO
|
||||
let thisPage = _.find(sails.config.builtStaticContent.markdownPages, {
|
||||
url: _.trimRight(SECTION_URL_PREFIX + '/' + _.trim(pageUrlSuffix, '/'), '/')
|
||||
});
|
||||
if (!thisPage) {
|
||||
throw 'notFound';
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// TODO: add "redirect" exit and handle mismatched capitalization / extra slashes by redirecting to the correct URL. e.g. "http://localhost:2024/docs//usiNG-fleet///" Partial example of this: https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/controllers/documentation/view-documentation.js#L161-L166
|
||||
let revisedUrl = 'todo';
|
||||
throw {redirect: revisedUrl};
|
||||
}
|
||||
|
||||
// Respond with view.
|
||||
return {};
|
||||
return {
|
||||
path: require('path'),
|
||||
thisPage: thisPage,
|
||||
markdownPages: sails.config.builtStaticContent.markdownPages,
|
||||
compiledPagePartialsAppPath: sails.config.builtStaticContent.compiledPagePartialsAppPath
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
|
||||
friendlyName: 'View docs template',
|
||||
|
||||
|
||||
description: 'Display "Docs template" page.',
|
||||
|
||||
|
||||
exits: {
|
||||
|
||||
success: {
|
||||
viewTemplatePath: 'pages/docs-template'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function () {
|
||||
|
||||
// Respond with view.
|
||||
return {
|
||||
outline: {
|
||||
sections: [
|
||||
{
|
||||
title: 'Get started',
|
||||
topics: [], // NOTE this array is empty bc this was not stubbed out
|
||||
},
|
||||
{
|
||||
title: 'Using Fleet',
|
||||
topics: [
|
||||
{
|
||||
title: 'Fleet UI',
|
||||
subtopics: ['Running queries', 'Scheduling queries'],
|
||||
relatedTopics: ['Osquery queries', 'Osquery packs'],
|
||||
},
|
||||
{
|
||||
title: 'fleetctl',
|
||||
subtopics: [], // NOTE this array is empty bc this was not stubbed out
|
||||
relatedTopics: [], // NOTE this array is empty bc this was not stubbed out
|
||||
},
|
||||
{
|
||||
title: 'REST API',
|
||||
subtopics: [], // NOTE this array is empty bc this was not stubbed out
|
||||
relatedTopics: [], // NOTE this array is empty bc this was not stubbed out
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Adding endpoints',
|
||||
topics: [],
|
||||
},
|
||||
{
|
||||
title: 'Deployment',
|
||||
topics: [],
|
||||
},
|
||||
{
|
||||
title: 'Contributing',
|
||||
topics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
currentPage: {
|
||||
section: 'Using Fleet',
|
||||
topic: 'Fleet UI',
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: 'subtopic',
|
||||
content: 'Running queries',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
content: 'The Fleet application allows you to query hosts that you have installed osquery on. To run a new query, navigate to "Queries" from the top nav, and then hit the "Create new query" button from the Queries page. From here, you can compose your query, view SQL table documentation via the sidebar, select arbitrary hosts (or groups of hosts), and execute your query. As results are returned, they will populate the interface in real time. You can use the integrated filtering tool to perform useful initial analytics and easily export the entire dataset for offline analysis.',
|
||||
},
|
||||
{
|
||||
type: 'image',
|
||||
content: '/images/fleetctl-900x580@2x.png',
|
||||
altText: 'An image of Fleet ctl'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
content: 'After you\'ve composed a query that returns the information you were looking for, you may choose to save the query. You can still continue to execute the query on whatever set of hosts you would like after you have saved the query.'
|
||||
},
|
||||
{
|
||||
type: 'note',
|
||||
content: 'To learn more about scheduling queries so that they run on an on-going basis, see the scheduling queries guide below.'
|
||||
},
|
||||
{
|
||||
type: 'subtopic',
|
||||
content: 'Scheduling queries',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
content: 'As discussed in the running queries documentation, you can use the Fleet application to create, execute, and save osquery queries. You can organize these queries into "Query Packs". To view all saved packs and perhaps create a new pack, select "Packs" from the top nav. Packs are usually organized by the general class of instrumentation that you\'re trying to perform.',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
content: 'To add queries to a pack, use the right-hand sidebar. You can take an existing scheduled query and add it to the pack. You must also define a few key details such as:',
|
||||
},
|
||||
{
|
||||
type: 'bullets',
|
||||
content: {
|
||||
intro: 'To add queries to a pack, use the right-hand sidebar. You can take an existing scheduled query and add it to the pack. You must also define a few key details such as:',
|
||||
bullets: [
|
||||
'interval: how often should the query be executed?',
|
||||
'logging: which osquery logging format would you like to use?',
|
||||
'platform: which operating system platforms should execute this query?',
|
||||
'minimum osquery version: if the table was introduced in a newer version of osquery, you may want to ensure that only sufficiently recent version of osquery execute the query.',
|
||||
'shard: from 0 to 100, what percent of hosts should execute this query?'
|
||||
],
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
|
||||
friendlyName: 'View documentation',
|
||||
|
||||
|
||||
description: 'Display "Documentation" page.',
|
||||
|
||||
|
||||
exits: {
|
||||
|
||||
success: {
|
||||
viewTemplatePath: 'pages/documentation'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function () {
|
||||
|
||||
// Respond with view.
|
||||
return {};
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
-206
@@ -1,206 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
|
||||
friendlyName: 'Compile markdown content',
|
||||
|
||||
|
||||
// TODO: Make this explanation better or refactor, because actually this does a lot more than just that, including cloning the source git repo
|
||||
description: 'Compile documentation templates from markdown.',
|
||||
// Also, FUTURE: dissect some of the code from here https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L16-L22
|
||||
// and use those building blocks directly instead of depending on doctemplater later and thus unnecessarily duplicating work. Also the other related code in sailsjs docs mentioned in https://github.com/fleetdm/fleet/issues/706
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Clone repo
|
||||
// let topLvlCachePath = path.resolve(sails.config.paths.tmp, `built-static-content/`);
|
||||
// await sails.helpers.fs.rmrf(topLvlCachePath);
|
||||
// let repoCachePath = path.join(topLvlCachePath, `cloned-repo-${Date.now()}-${Math.round(Math.random()*100)}`);
|
||||
// await sails.helpers.process.executeCommand(`git clone git://github.com/fleetdm/fleet.git ${repoCachePath}`);
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
inputs: {
|
||||
|
||||
repoPath: {
|
||||
description: 'The path of the subdirectory in the Git repo to compile from.',
|
||||
type: 'string',
|
||||
example: 'docs/',
|
||||
required: true
|
||||
},
|
||||
|
||||
repoBranch: {
|
||||
description: 'The name of the branch to compile from.',
|
||||
type: 'string',
|
||||
defaultsTo: 'master'
|
||||
},
|
||||
|
||||
repoUrl: {
|
||||
description: 'The git:// URL of the remote Git repo to compile from.',
|
||||
type: 'string',
|
||||
defaultsTo: 'git://github.com/fleetdm/fleet.git',
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
exits: {
|
||||
success: { outputDescription: 'A list of metadata about all generated HTML files.', outputType: [{}] }
|
||||
},
|
||||
|
||||
|
||||
fn: async function ({repoPath, repoBranch, repoUrl}) {
|
||||
|
||||
let path = require('path');
|
||||
let cheerio = require('cheerio');
|
||||
let DocTemplater = {};// require('doc-templater');
|
||||
if (true) {
|
||||
throw new Error('This helper has been retired. TODO: delete it.');
|
||||
}
|
||||
|
||||
sails.log.info('Compiling `%s` docs from the `%s` branch of `%s`...', repoPath, repoBranch, repoUrl);
|
||||
|
||||
// Relative path within this app where output will be written.
|
||||
let htmlOutputPath = path.join('views/partials/built-from-markdown/', _.kebabCase(repoPath));
|
||||
|
||||
// Relative path within this app where temporary menu data will be written.
|
||||
// (This is consumed later in this file.)
|
||||
let jsMenuOutputPath = path.join('.tmp/doc-templater/menus/', `${_.kebabCase(repoPath)}.tmp-menu.json`);// fka "the .jsmenu file"
|
||||
|
||||
// Delete existing output from previous runs, if any.
|
||||
await sails.helpers.fs.rmrf(path.resolve(sails.config.appPath, htmlOutputPath));
|
||||
await sails.helpers.fs.rmrf(path.resolve(sails.config.appPath, jsMenuOutputPath));
|
||||
|
||||
// Compile the markdown into HTML files and a JSON file (aka "jsmenu") representing
|
||||
// the manifest of all compiled HTML files and their hierarchy.
|
||||
await new Promise((resolve, reject)=>{
|
||||
DocTemplater().build([{
|
||||
remote: repoUrl,
|
||||
branch: repoBranch,
|
||||
remoteSubPath: repoPath,
|
||||
outputExtension: 'ejs',//« the file extension for resulting HTML files
|
||||
htmlDirPath: htmlOutputPath,
|
||||
jsMenuPath: jsMenuOutputPath,
|
||||
beforeConvert: (mdString, proceed)=>{// This function is applied to each template before the markdown is converted to markup
|
||||
// Based on the github-flavored markdown's language annotation, (e.g. ```js```) add a temporary marker to code blocks that can be parsed post-md-compilation by the `afterConvert()` lifecycle hook
|
||||
// Note: This is an HTML comment because it is easy to over-match and "accidentally" add it underneath each code block as well (being an HTML comment ensures it doesn't show up or break anything)
|
||||
let LANG_MARKER_PREFIX = '<!-- __LANG=%';
|
||||
let LANG_MARKER_SUFFIX = '%__ -->';
|
||||
let modifiedMd = mdString.replace(/(```)([a-zA-Z0-9\-]*)(\s*\n)/g, '$1\n' + LANG_MARKER_PREFIX + '$2' + LANG_MARKER_SUFFIX + '$3');
|
||||
|
||||
// FUTURE: implement a way of skipping non-markdown files, such as pngs (maybe here, but prbly just make it built-in)
|
||||
|
||||
return proceed(undefined, modifiedMd);
|
||||
},
|
||||
afterConvert: (html, proceed)=>{// This function is applied to each template after the markdown is converted to markup
|
||||
|
||||
let modifiedHtml = html;
|
||||
|
||||
// Replace github emoji with unicode emojis
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// TODO: actually sub unicode, instead of the following (there's probably an open source lib out there to do it)
|
||||
// modifiedHtml = html.replace(/\:white_check_mark\:/g, '<i class="sails-icon icon-plus"></i>');
|
||||
// modifiedHtml = modifiedHtml.replace(/\:white_large_square\:/g, '<i class="sails-icon icon-minus"></i>');
|
||||
// modifiedHtml = modifiedHtml.replace(/\:heavy_multiplication_x\:/g, '<i class="sails-icon icon-times"></i>');
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// TODO: As equivalent concepts are identified in the Fleet docs (e.g. in the API reference), maybe bring this back:
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// // Replace ((bubble))s with HTML
|
||||
// modifiedHtml = modifiedHtml.replace(/\(\(([^())]*)\)\)/g, '<bubble type="$1" class="colors"><span is="bubble-heart"></span></bubble>');
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// Flag <h2>, <h3>, <h4>, and <h5> tags with the `permalinkable` directive, so they can be clicked
|
||||
// e.g. ?q=transport-compatibility
|
||||
let $ = cheerio.load(modifiedHtml);
|
||||
$('h2, h3, h4, h5').each(function() {
|
||||
let content = $(this).text() || '';
|
||||
|
||||
// build the URL slug suffix
|
||||
let slug = content
|
||||
.replace(/[\?\!\.\-\_\:\;\'\"]/g, '') // punctuation => gone
|
||||
.replace(/\s/g, '-') // spaces => dashes
|
||||
.toLowerCase();
|
||||
|
||||
// set the "permalink" HTML attr to the slug
|
||||
$(this).attr('permalink', slug);
|
||||
|
||||
if ($(this) && typeof $(this).wrap === 'function') {// this was throwing ".wrap is undefined"
|
||||
$(this).wrap('<div class="permalink-header"></div>');
|
||||
}
|
||||
|
||||
});
|
||||
modifiedHtml = $.html();
|
||||
|
||||
// Modify links
|
||||
modifiedHtml = modifiedHtml.replace(/(href="https?:\/\/([^"]+)")/g, (hrefString)=>{
|
||||
// Check if this is an external link (like https://google.com) but that is ALSO not a link
|
||||
// to some page on the destination site where this will be hosted, like `(*.)?sailsjs.com`.
|
||||
// If external, add target="_blank" so the link will open in a new tab.
|
||||
let isExternal = ! hrefString.match(/^href=\"https?:\/\/([^\.]+\.)*fleetdm\.com/g);
|
||||
if (isExternal) {
|
||||
return hrefString.replace(/(href="https?:\/\/([^"]+)")/g, '$1 target="_blank"');
|
||||
} else {
|
||||
// Otherwise, change the link to be web root relative.
|
||||
// (e.g. 'href="http://sailsjs.com/documentation/concepts"'' becomes simply 'href="/documentation/concepts"'')
|
||||
// Note: See the Git version history of this file for examples of ways this can work across versioned subdomains.
|
||||
return hrefString.replace(/href="https?:\/\//, '').replace(/^fleetdm\.com/, 'href="');
|
||||
}
|
||||
});//∞
|
||||
|
||||
// Add the appropriate class to the `<code>` based on the temporary marker that was added in the `beforeConvert` function above
|
||||
// console.log('RAN AFTER HOOK, found: ',modifiedHtml.match(/(<code)([^>]*)(>\s*)(\<!--\s*__LANG=\%[^\%]*\%__\s*--\>)/g));
|
||||
modifiedHtml = modifiedHtml.replace(// Interpret `js` as `javascript`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%js\%__ --\>)\s*/gm,
|
||||
'$1 class="javascript"$2$3'
|
||||
);
|
||||
modifiedHtml = modifiedHtml.replace(// Interpret `sh` and `bash` as `bash`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%(bash|sh)\%__ --\>)\s*/gm,
|
||||
'$1 class="bash"$2$3'
|
||||
);
|
||||
modifiedHtml = modifiedHtml.replace(// When unspecified, default to `text`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%\%__ --\>)\s*/gm,
|
||||
'$1 class="nohighlight"$2$3'
|
||||
);
|
||||
modifiedHtml = modifiedHtml.replace(// Finally, nab the rest, leaving the code language as-is.
|
||||
// $1 $2 $3 $4 $5 $6
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%)([^%]+)(\%__ --\>)\s*/gm,
|
||||
'$1 class="$5"$2$3'
|
||||
);
|
||||
|
||||
return proceed(undefined, modifiedHtml);
|
||||
},
|
||||
}], (err)=>{
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});//_∏_
|
||||
});
|
||||
|
||||
// Now return the menu data, to provide a nicer way of programmatically working with it.
|
||||
// But first, we'll clean it up a bit.
|
||||
let filesGenerated = await sails.helpers.fs.readJson(jsMenuOutputPath);
|
||||
|
||||
// TODO: bring in the other cleanup in marshal-doc-page-metadata from sailsjs.com repo
|
||||
|
||||
// Since the format from the doc-templater package can be a little bit misleading,
|
||||
// we'll also munge the resulting data a little bit.
|
||||
for (let fileInfo of filesGenerated) {
|
||||
|
||||
fileInfo.path = fileInfo.fullPathAndFileName;// « for clarity (it's not technically the full path)
|
||||
delete fileInfo.fullPathAndFileName;
|
||||
|
||||
fileInfo.fallbackTitle = sails.helpers.strings.toSentenceCase(path.basename(fileInfo.templateTitle, '.ejs'));// « for clarity (the page isn't a template, necessarily, and this title is just a guess. Display title will, more likely than not, come from a <docmeta> tag -- see the bottom of the original, raw unformatted markdown of any page in the sailsjs docs for an example of how to use docmeta tags)
|
||||
delete fileInfo.templateTitle;
|
||||
|
||||
delete fileInfo.data.lastModified;// « for clarity (this isn't the timestamp you're expecting, so we delete it)
|
||||
}//∞
|
||||
|
||||
return filesGenerated;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
module.exports = {
|
||||
|
||||
|
||||
friendlyName: 'To HTML',
|
||||
|
||||
|
||||
description: 'Compile a Markdown string into an HTML string.',
|
||||
|
||||
|
||||
extendedDescription:
|
||||
'Expects GitHub-flavored Markdown syntax. Uses [`marked`](https://github.com/chjj/marked)@v0.3.5. '+
|
||||
'Inspired by https://github.com/mikermcneil/machinepack-markdown/tree/5d8cee127e8ce45c702ec9bbb2b4f9bc4b7fafac',
|
||||
|
||||
|
||||
moreInfoUrl: 'https://help.github.com/articles/basic-writing-and-formatting-syntax/',
|
||||
|
||||
|
||||
sideEffects: 'cacheable',
|
||||
|
||||
|
||||
inputs: {
|
||||
|
||||
mdString: {
|
||||
description: 'Markdown string to convert',
|
||||
example: '# hello world\n it\'s me, some markdown string \n\n ```js\n//but maybe i have code snippets too...\n```',
|
||||
required: true
|
||||
},
|
||||
|
||||
allowHtml: {
|
||||
friendlyName: 'Allow HTML?',
|
||||
description: 'Whether or not to allow HTML tags in the Markdown input. Defaults to `true`.',
|
||||
extendedDescription: 'If `false`, any input that contains HTML tags will trigger the `unsafeMarkdown` exit.',
|
||||
example: true,
|
||||
defaultsTo: true
|
||||
},
|
||||
|
||||
addIdsToHeadings: {
|
||||
friendlyName: 'Add IDs to headings?',
|
||||
description: 'Whether or not to add an ID attribute to rendered heading tags like <h1>',
|
||||
extendedDescription: 'This is not part of the Markdown specification (see http://daringfireball.net/projects/markdown/dingus), but it is the default behavior for the `marked` module. Defaults to `true`.',
|
||||
example: true,
|
||||
defaultsTo: true
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
exits: {
|
||||
|
||||
success: {
|
||||
outputFriendlyName: 'HTML',
|
||||
outputExample: '<h1 id="hello-world">hello world</h1>\n<p> it's me, some markdown string </p>\n<pre><code class="lang-js">//but maybe i have code snippets too...</code></pre>\n'
|
||||
},
|
||||
|
||||
unsafeMarkdown: {
|
||||
friendlyName: 'Unsafe Markdown detected',
|
||||
description: 'The provided input contained unsafe content (like HTML tags).'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: function(inputs, exits) {
|
||||
var marked = require('marked');
|
||||
|
||||
// For full list of options, see:
|
||||
// • https://github.com/chjj/marked
|
||||
var markedOpts = {
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
};
|
||||
|
||||
if (inputs.addIdsToHeadings === false) {
|
||||
var renderer = new marked.Renderer();
|
||||
renderer.heading = function (text, level) {
|
||||
return '<h'+level+'>'+text+'</h'+level+'>';
|
||||
};
|
||||
markedOpts.renderer = renderer;
|
||||
}
|
||||
|
||||
// Now actually compile the markdown to HTML.
|
||||
marked(inputs.mdString, markedOpts, function afterwards (err, htmlString) {
|
||||
if (err) { return exits.error(err); }
|
||||
|
||||
// If we're not allowing HTML, compile the input again with the `sanitize` option on.
|
||||
if (inputs.allowHtml === false) {
|
||||
markedOpts.sanitize = true;
|
||||
marked(inputs.mdString, markedOpts, function sanitized (err, sanitizedHtmlString) {
|
||||
if (err) { return exits.error(err); }
|
||||
|
||||
// Now compare the unsanitized and the sanitized output, and if they're not the same,
|
||||
// leave through the `unsafeMarkdown` exit since it means that HTML tags were detected.
|
||||
if (htmlString !== sanitizedHtmlString) {
|
||||
return exits.unsafeMarkdown();
|
||||
}
|
||||
return exits.success(htmlString);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return exits.success(htmlString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
+14
-3
@@ -21,11 +21,22 @@ module.exports = {
|
||||
|
||||
|
||||
fn: function ({ text }) {
|
||||
// TODO: make this smarter about: "Fleet REST API" => "Fleet rEST aPI")
|
||||
|
||||
let KNOWN_ACRONYMS = ['JSON', 'REST', 'CLI', 'API', 'FAQ', 'QA', 'UI', 'README']; // « helps make this smarter about things like: "Fleet rEST aPI" => "Fleet REST API")
|
||||
let KNOWN_PROPER_NOUNS = ['Fleet'];// « helps make this smarter about things like: "Deploying fleet" => "Deploying Fleet"
|
||||
|
||||
return text
|
||||
.split(/[\s-_]+/)
|
||||
.filter((word, idx) => !(idx === 0 && word.match(/[0-9]+/))) // « strip off any leading numbers so first word is actually capitalized
|
||||
.map((word, idx) => (idx === 0? word[0].toUpperCase() : word[0].toLowerCase())+word.slice(1))
|
||||
.filter((word, idx) => !(idx === 0 && word.match(/^[0-9]+$/))) // « disregard first word if it contains only numbers (this helps capitalization work as expected)
|
||||
.map((word, idx)=>{
|
||||
if (KNOWN_ACRONYMS.includes(word.toUpperCase())) {
|
||||
return word.toUpperCase();
|
||||
} else if (idx === 0 || KNOWN_PROPER_NOUNS.includes(word[0].toUpperCase() + word.slice(1).toLowerCase())) {
|
||||
return word[0].toUpperCase() + word.slice(1).toLowerCase();
|
||||
} else {
|
||||
return word.toLowerCase();
|
||||
}
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+17
-3
@@ -2,7 +2,7 @@
|
||||
* parasails.js
|
||||
* (lightweight structures for apps with more than one page)
|
||||
*
|
||||
* v0.9.2
|
||||
* v0.9.3
|
||||
*
|
||||
* Copyright 2014-present, Mike McNeil (@mikermcneil)
|
||||
* MIT License
|
||||
@@ -167,7 +167,7 @@
|
||||
// > This is particularly useful for catching loose top-level properties
|
||||
// > that were intended to be within `data` or `methods`, etc.)
|
||||
if (currentModuleEntityNoun === 'page script' || currentModuleEntityNoun === 'component') {
|
||||
// FUTURE: don't allow page-script only things on components
|
||||
// FUTURE: don't allow page script only things on components
|
||||
|
||||
var LEGAL_TOP_LVL_KEYS = [
|
||||
// Everyday page script stuff:
|
||||
@@ -723,8 +723,22 @@
|
||||
if (!pageName) { throw new Error('1st argument (page name) is required'); }
|
||||
if (!def) { throw new Error('2nd argument (page script definition) is required'); }
|
||||
|
||||
// Don't look for a matching DOM element (by "id") within anything that has `parasails-has-no-page-script`
|
||||
// FUTURE: Move this check a bit further below, probably without defining the variable, and just add another avast (aka early return)
|
||||
var isWithinIgnoredElements;
|
||||
if ($) {
|
||||
// Note that, luckily, this works even without waiting for the DOM to be ready according to jQuery. (i.e. $(()=>{ … }))
|
||||
isWithinIgnoredElements = (
|
||||
$('#'+pageName).parents().filter('[parasails-has-no-page-script]')
|
||||
).length >= 1;
|
||||
} else {
|
||||
// For simplicity, this check is skipped if jQuery is not available.
|
||||
// FUTURE: Implement with vanilla JS here
|
||||
isWithinIgnoredElements = false;
|
||||
}
|
||||
|
||||
// Only actually build+load this page script if it is relevant for the current contents of the DOM.
|
||||
if (!document.getElementById(pageName)) { return; }//eslint-disable-line no-undef
|
||||
if (!window.document.getElementById(pageName) || isWithinIgnoredElements) { return; }
|
||||
|
||||
// Spinlock
|
||||
if (didAlreadyLoadPageScript) { throw new Error('Cannot load page script (`'+pageName+') because a page script has already been loaded on this page.'); }
|
||||
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
parasails.registerPage('[id="498"]', {
|
||||
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
|
||||
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
|
||||
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
|
||||
data: {
|
||||
//…
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
|
||||
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
|
||||
beforeMount: function() {
|
||||
//…
|
||||
},
|
||||
mounted: async function(){
|
||||
//…
|
||||
},
|
||||
|
||||
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
|
||||
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
|
||||
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
|
||||
methods: {
|
||||
//…
|
||||
}
|
||||
});
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
parasails.registerPage('docs-template', {
|
||||
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
|
||||
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
|
||||
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
|
||||
data: {
|
||||
inputTextValue: '',
|
||||
inputTimers: {},
|
||||
searchString: '',
|
||||
showDocsNav: false,
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
|
||||
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
|
||||
beforeMount: function() {
|
||||
//…
|
||||
},
|
||||
mounted: async function() {
|
||||
//…
|
||||
},
|
||||
|
||||
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
|
||||
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
|
||||
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
|
||||
methods: {
|
||||
toggleDocsNav: function () {
|
||||
this.showDocsNav = !this.showDocsNav;
|
||||
},
|
||||
|
||||
delayInput: function (callback, ms, label) {
|
||||
let inputTimers = this.inputTimers;
|
||||
return function () {
|
||||
label = label || 'defaultTimer';
|
||||
_.has(inputTimers, label) ? clearTimeout(inputTimers[label]) : 0;
|
||||
inputTimers[label] = setTimeout(callback, ms);
|
||||
};
|
||||
},
|
||||
|
||||
setSearchString: function () {
|
||||
this.searchString = this.inputTextValue;
|
||||
},
|
||||
|
||||
getSubtopics: function () {
|
||||
return this.body.filter((item) => item.type === 'subtopic')
|
||||
.map((item) => item.content);
|
||||
},
|
||||
|
||||
getRelatedTopics: function () {
|
||||
try {
|
||||
const sectionIndex = this.outline.sections.findIndex((section) => section.title === this.currentPage.section);
|
||||
const topicIndex = this.outline.sections[sectionIndex].topics.findIndex((topic) => topic.title === this.currentPage.topic);
|
||||
return this.outline.sections[sectionIndex].topics[topicIndex].relatedTopics;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
+195
-4
@@ -3,23 +3,214 @@ parasails.registerPage('basic-documentation', {
|
||||
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
|
||||
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
|
||||
data: {
|
||||
//…
|
||||
|
||||
isDocsLandingPage: false,
|
||||
|
||||
inputTextValue: '',
|
||||
inputTimers: {},
|
||||
searchString: '',
|
||||
showDocsNav: false,
|
||||
|
||||
breadcrumbs: [],
|
||||
pages: [],
|
||||
pagesBySectionSlug: {},
|
||||
subtopics: [],
|
||||
relatedTopics: [],
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentLocation: function () {
|
||||
return window.location.href;
|
||||
}
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
|
||||
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
|
||||
beforeMount: function() {
|
||||
//…
|
||||
if (this.thisPage.url === '/docs') {
|
||||
this.isDocsLandingPage = true;
|
||||
}
|
||||
|
||||
this.breadcrumbs = _.trim(this.thisPage.url, /\//).split(/\//);
|
||||
|
||||
this.pages = _.sortBy(this.markdownPages, 'htmlId');
|
||||
|
||||
this.pagesBySectionSlug = (() => {
|
||||
const DOCS_SLUGS = ['using-fleet', 'deploying', 'contributing'];
|
||||
|
||||
let sectionSlugs = _.uniq(_.pluck(this.pages, 'url').map((url) => url.split(/\//).slice(-2)[0]));
|
||||
|
||||
let pagesBySectionSlug = {};
|
||||
|
||||
for (let sectionSlug of sectionSlugs) {
|
||||
pagesBySectionSlug[sectionSlug] = _
|
||||
.chain(this.pages)
|
||||
.filter((page) => {
|
||||
return sectionSlug === page.url.split(/\//).slice(-2)[0];
|
||||
})
|
||||
.sortBy((page) => {
|
||||
// custom sort function is needed because simple sort of alphanumeric htmlIds strings
|
||||
// does not appropriately handle double-digit strings
|
||||
try {
|
||||
// attempt to split htmlId and parse out its ordinal value (e.g., `docs--10-teams--xxxxxxxxxx`)
|
||||
let sortValue = page.htmlId.split(/--/)[1].split(/-/)[0];
|
||||
return parseInt(sortValue) || sortValue;
|
||||
} catch (error) {
|
||||
// something unexpected happened so just return the htmlId and continue sort
|
||||
console.log(error);
|
||||
return page.htmlId;
|
||||
}
|
||||
})
|
||||
.value();
|
||||
}
|
||||
|
||||
// We need to re-sort the top-level sections because their htmlIds do not reflect the correct order
|
||||
pagesBySectionSlug['docs'] = DOCS_SLUGS.map((slug) => {
|
||||
return pagesBySectionSlug['docs'].find((page) => slug === _.kebabCase(page.title));
|
||||
});
|
||||
|
||||
// We need to move any FAQs to the end of its array
|
||||
for (let slug of DOCS_SLUGS) {
|
||||
let pages = pagesBySectionSlug[slug];
|
||||
let index = pages.findIndex((page) => page.title === 'FAQ');
|
||||
if (index === -1 || index === pages.length - 1) {
|
||||
break;
|
||||
} else {
|
||||
let removedPage = _.pullAt(pages, index);
|
||||
pages.push(...removedPage);
|
||||
pagesBySectionSlug[slug] = pages;
|
||||
}
|
||||
}
|
||||
|
||||
return pagesBySectionSlug;
|
||||
})();
|
||||
},
|
||||
|
||||
mounted: async function() {
|
||||
//…
|
||||
|
||||
// // Alternative jQuery approach to grab `on this page` links from top of markdown files
|
||||
// let subtopics = $('#body-content').find('h1 + ul').children().map((_, el) => el.innerHTML);
|
||||
// subtopics = $.makeArray(subtopics);
|
||||
// console.log(subtopics);
|
||||
|
||||
this.subtopics = (() => {
|
||||
let subtopics = $('#body-content').find('h2').map((_, el) => el.innerHTML);
|
||||
subtopics = $.makeArray(subtopics).map((title) => {
|
||||
return {
|
||||
title,
|
||||
url: '#' + _.kebabCase(title),
|
||||
};
|
||||
});
|
||||
return subtopics;
|
||||
})();
|
||||
|
||||
// https://github.com/sailshq/sailsjs.com/blob/7a74d4901dcc1e63080b502492b03fc971d3d3b2/assets/js/functions/sails-website-actions.js#L177-L239
|
||||
(function highlightThatSyntax(){
|
||||
$('pre code').each((i, block) => {
|
||||
window.hljs.highlightBlock(block);
|
||||
});
|
||||
|
||||
// Make sure the <pre> tags whose code isn't being highlighted
|
||||
// has that nice muted look we like.
|
||||
$('.nohighlight').each(function() {
|
||||
var $codeBlock = $(this);
|
||||
$codeBlock.closest('pre').addClass('muted');
|
||||
});
|
||||
// Also make sure the 'usage' (and 'usage-*') code blocks have special styles.
|
||||
$('.usage,.usage-exec').each(function() {
|
||||
var $codeBlock = $(this);
|
||||
$codeBlock.closest('pre').addClass('usage-wrapper');
|
||||
});
|
||||
|
||||
// Now let's make the `function` keywords blue like in sublime.
|
||||
$('.hljs-keyword').each(function() {
|
||||
var $highlightedKeyword = $(this);
|
||||
if($highlightedKeyword.text() === 'function') {
|
||||
$highlightedKeyword.removeClass('hljs-keyword');
|
||||
$highlightedKeyword.addClass('hljs-function-keyword');
|
||||
}
|
||||
});
|
||||
|
||||
$('.hljs-built_in').each(function() {
|
||||
var $builtIn = $(this);
|
||||
var $parentCode = $builtIn.closest('code');
|
||||
var isJavascriptSyntax = $parentCode.hasClass('javascript');
|
||||
var isBashSyntax = $parentCode.hasClass('bash');
|
||||
// ...and make the `require()`s not yellow, also like in sublime.
|
||||
if(isJavascriptSyntax && $builtIn.text() === 'require') {
|
||||
$builtIn.removeClass('hljs-built_in');
|
||||
}
|
||||
// And don't highlight the word 'test' in the bash examples, e.g. for ('sails new test-project')
|
||||
if(isBashSyntax && $builtIn.text() === 'test') {
|
||||
$builtIn.removeClass('hljs-built_in');
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
},
|
||||
|
||||
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
|
||||
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
|
||||
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
|
||||
methods: {
|
||||
//…
|
||||
|
||||
clickCTA: function (slug) {
|
||||
window.location = slug;
|
||||
},
|
||||
|
||||
isCurrentSection: function (section) {
|
||||
if (_.trim(this.thisPage.url, (/\//)).split(/\//).includes(_.last(_.trimRight(section.url, (/\//)).split(/\//)))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
findPagesByUrl: function (url='') {
|
||||
let slug;
|
||||
// if no url is passed, use the base url as the slug (e.g., 'docs' or 'handbook')
|
||||
if (!url) {
|
||||
slug = _.trim(this.thisPage.url, /\//).split(/\//)[0];
|
||||
} else {
|
||||
slug = _.last(url.split(/\//));
|
||||
}
|
||||
|
||||
return this.pagesBySectionSlug[slug];
|
||||
},
|
||||
|
||||
getActiveSubtopicClass: function (currentLocation, url) {
|
||||
return _.last(currentLocation.split(/#/)) === _.last(url.split(/#/)) ? 'active' : '';
|
||||
},
|
||||
|
||||
getTitleFromUrl: function (url) {
|
||||
return _
|
||||
.chain(url.split(/\//))
|
||||
.last()
|
||||
.split(/-/)
|
||||
.map((str) => str === 'fleet' ? 'Fleet' : str)
|
||||
.join(' ')
|
||||
.capitalize()
|
||||
.value();
|
||||
},
|
||||
|
||||
toggleDocsNav: function () {
|
||||
this.showDocsNav = !this.showDocsNav;
|
||||
},
|
||||
|
||||
delayInput: function (callback, ms, label) {
|
||||
let inputTimers = this.inputTimers;
|
||||
return function () {
|
||||
label = label || 'defaultTimer';
|
||||
_.has(inputTimers, label) ? clearTimeout(inputTimers[label]) : 0;
|
||||
inputTimers[label] = setTimeout(callback, ms);
|
||||
};
|
||||
},
|
||||
|
||||
setSearchString: function () {
|
||||
this.searchString = this.inputTextValue;
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
parasails.registerPage('documentation', {
|
||||
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
|
||||
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
|
||||
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
|
||||
data: {
|
||||
inputTextValue: '',
|
||||
inputTimers: {},
|
||||
searchString: '',
|
||||
showDocsNav: false,
|
||||
tree: [
|
||||
{
|
||||
title: 'Using Fleet',
|
||||
children: [
|
||||
'Fleet UI',
|
||||
'fleetctl',
|
||||
'REST API',
|
||||
'Osquery logs',
|
||||
'Monitoring Fleet',
|
||||
'Security best practices',
|
||||
'Updating Fleet',
|
||||
'FAQ - Using Fleet'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Deploying',
|
||||
children: [
|
||||
'Installation',
|
||||
'Configuration',
|
||||
'Adding hosts',
|
||||
'Osquery logs',
|
||||
'Example deployment scenarios',
|
||||
'Self-managed agent updates',
|
||||
'FAQ - Deploying'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Contributing',
|
||||
children: [
|
||||
'Building Fleet',
|
||||
'Testing',
|
||||
'Migrations',
|
||||
'Committing changes',
|
||||
'Releasing Fleet',
|
||||
'FAQ - Contributing'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
|
||||
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
|
||||
beforeMount: function() {
|
||||
//…
|
||||
},
|
||||
mounted: async function() {
|
||||
//…
|
||||
},
|
||||
|
||||
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
|
||||
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
|
||||
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
|
||||
methods: {
|
||||
toggleDocsNav: function () {
|
||||
this.showDocsNav = !this.showDocsNav;
|
||||
},
|
||||
|
||||
clickCTA: function (slug) {
|
||||
window.location = slug;
|
||||
},
|
||||
|
||||
delayInput: function (callback, ms, label) {
|
||||
let inputTimers = this.inputTimers;
|
||||
return function () {
|
||||
label = label || 'defaultTimer';
|
||||
_.has(inputTimers, label) ? clearTimeout(inputTimers[label]) : 0;
|
||||
inputTimers[label] = setTimeout(callback, ms);
|
||||
};
|
||||
},
|
||||
|
||||
setSearchString: function () {
|
||||
this.searchString = this.inputTextValue;
|
||||
},
|
||||
|
||||
getSubtopics: function () {
|
||||
return this.body.filter((item) => item.type === 'subtopic')
|
||||
.map((item) => item.content);
|
||||
},
|
||||
|
||||
getRelatedTopics: function () {
|
||||
try {
|
||||
const sectionIndex = this.outline.sections.findIndex((section) => section.title === this.currentpage.section);
|
||||
const topicIndex = this.outline.sections[sectionIndex].topics.findIndex((topic) => topic.title === this.currentpage.topic);
|
||||
return this.outline.sections[sectionIndex].topics[topicIndex].relatedTopics;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
Vendored
-3
@@ -48,7 +48,4 @@
|
||||
@import 'pages/docs/basic-documentation.less';
|
||||
@import 'pages/handbook/basic-handbook.less';
|
||||
|
||||
@import 'pages/documentation.less';
|
||||
@import 'pages/docs-template.less';
|
||||
|
||||
@import 'pages/transparency.less';
|
||||
|
||||
-145
@@ -1,145 +0,0 @@
|
||||
#docs-template {
|
||||
|
||||
h3 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-family: 'Nunito';
|
||||
}
|
||||
|
||||
a {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 8px;
|
||||
li {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.topic {
|
||||
&.active {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
&::placeholder {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
color: #8b8fa2;
|
||||
border-color: #c5c7d1;
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
border-color: #c5c7d1;
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
&:focus {
|
||||
border: 1px solid #c5c7d1;
|
||||
}
|
||||
}
|
||||
|
||||
.subtopic {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
border-right: 1px solid @core-fleet-black-25;
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
&.btn-primary {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.left-nav {
|
||||
border-bottom: 1px solid @core-fleet-black-25;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #ff5c83;
|
||||
border-color: #ff5c83;
|
||||
&:hover {
|
||||
background-color: darken(#ff5c83, 10%);
|
||||
border-color: darken(#ff5c83, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: @core-vibrant-blue-10;
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-nav-button {
|
||||
color: @core-fleet-black;
|
||||
background-color: transparent;
|
||||
font-family: 'Nunito';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid @core-vibrant-blue-15;
|
||||
border-radius: 0px;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-docs-nav {
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 993px) {
|
||||
ul {
|
||||
.topic {
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
.subtopic {
|
||||
color: @core-fleet-black;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
border-left: 1px solid @core-vibrant-blue-25;
|
||||
.active {
|
||||
position: absolute;
|
||||
height: 32px;
|
||||
transform: translate(-2px, -4px);
|
||||
border-left: 3px solid @core-vibrant-blue;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
.input-group {
|
||||
min-width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+461
-8
@@ -1,13 +1,466 @@
|
||||
#basic-documentation {
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// For a starting point on how to approach styling this generated HTML, please see @RachelElysia's draft in:
|
||||
// https://github.com/fleetdm/fleet/commit/bfb758d9dc81c423538f75fc86244b06cc810c1a
|
||||
// https://github.com/fleetdm/fleet/commit/e4c77b981627bde0e6225c805c89143467a9bca1
|
||||
//
|
||||
// Note that handbook and documentation can probably share many of the same styles. (Consider a dedicated mixin.)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
//…
|
||||
h3 {
|
||||
font-size: 22px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-family: 'Nunito';
|
||||
}
|
||||
|
||||
a {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 8px;
|
||||
|
||||
li {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='docs-landing-page'] {
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
[purpose='search'] {
|
||||
|
||||
input {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
|
||||
&::placeholder {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
color: @core-fleet-black-50;
|
||||
border-color: @core-fleet-black-25;
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
border-color: @core-fleet-black-25;
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid @core-fleet-black-25;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='cta-cards'] {
|
||||
|
||||
.cta-card {
|
||||
cursor: pointer;
|
||||
border: 1px solid @ui-gray;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 2px 2px rgba(197, 199, 209, 0.2);
|
||||
|
||||
.cta-image {
|
||||
max-height: 60px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.cta-text {
|
||||
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
padding-left: 8px;
|
||||
transition: 0.2s ease-in-out;
|
||||
-o-transition: 0.2s ease-in-out;
|
||||
-ms-transition: 0.2s ease-in-out;
|
||||
-moz-transition: 0.2s ease-in-out;
|
||||
-webkit-transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
.arrow {
|
||||
|
||||
img {
|
||||
padding-left: 11px;
|
||||
transition: 0.2s ease-in-out;
|
||||
-o-transition: 0.2s ease-in-out;
|
||||
-ms-transition: 0.2s ease-in-out;
|
||||
-moz-transition: 0.2s ease-in-out;
|
||||
-webkit-transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='docs-tree'] {
|
||||
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
||||
.cta-card {
|
||||
max-width: 437px;
|
||||
min-height: 160px;
|
||||
|
||||
.cta-image {
|
||||
max-height: 72px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
[purpose='docs-template'] {
|
||||
|
||||
h3 {
|
||||
|
||||
code {
|
||||
color: @core-fleet-black;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='search'] {
|
||||
|
||||
input {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
border-radius: 6px;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
|
||||
&::placeholder {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.input-group-prepend {
|
||||
border-radius: 6px;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
color: #8b8fa2;
|
||||
border-color: #c5c7d1;
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
border-color: #c5c7d1;
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid #c5c7d1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='breadcrumbs'] {
|
||||
|
||||
p, a {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='mobile-docs-nav'] {
|
||||
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
|
||||
&.active {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='docs-nav-button'] {
|
||||
color: @core-fleet-black;
|
||||
background-color: transparent;
|
||||
font-family: 'Nunito';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='left-sidebar'] {
|
||||
font-size: 14px;
|
||||
border-right: 1px solid @core-fleet-black-25;
|
||||
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: #6A67FE;
|
||||
}
|
||||
|
||||
&.btn-primary {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #ff5c83;
|
||||
border-color: #ff5c83;
|
||||
|
||||
&:hover {
|
||||
background-color: darken(#ff5c83, 10%);
|
||||
border-color: darken(#ff5c83, 10%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.left-nav {
|
||||
border-bottom: 1px solid @core-fleet-black-25;
|
||||
}
|
||||
|
||||
.topic {
|
||||
|
||||
&.active {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='right-sidebar'] {
|
||||
|
||||
p, a {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
a {
|
||||
&:hover {
|
||||
color: #6A67FE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='content'] {
|
||||
|
||||
h1 {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
line-height: 28px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
h1 + ul {
|
||||
display: none; // Hides links at top of some markdown files
|
||||
}
|
||||
|
||||
h2 + h3 {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: @core-vibrant-blue-10;
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for smaller screens
|
||||
@media (max-width: 991px) {
|
||||
|
||||
[purpose='right-sidebar'] {
|
||||
width: 100%;
|
||||
|
||||
[purpose='subtopics'] {
|
||||
color: @core-fleet-black;
|
||||
|
||||
a {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='content'] {
|
||||
width: 100%;
|
||||
|
||||
h1:first-of-type {
|
||||
display: none; // hides on mobile
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for larger screens
|
||||
@media (min-width: 992px) {
|
||||
|
||||
ul {
|
||||
.topic {
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='search'] {
|
||||
|
||||
.input-group {
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='page-title'] {
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='right-sidebar'] {
|
||||
min-width: 190px;
|
||||
max-width: 210px;
|
||||
|
||||
[purpose='subtopics'] {
|
||||
color: @core-fleet-black;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
border-left: 1px solid @core-vibrant-blue-25;
|
||||
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// .active {
|
||||
// color: @core-vibrant-blue;
|
||||
// position: absolute;
|
||||
// height: 32px;
|
||||
// transform: translate(-2px, -4px);
|
||||
// border-left: 3px solid @core-vibrant-blue;
|
||||
// border-radius: 2px;
|
||||
// a {
|
||||
// color: @core-vibrant-blue;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[purpose='content'] {
|
||||
min-width: 0px; // in order for <pre> elements to shrink properly, the parent flex element needs to override min-width auto
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@import 'code-blocks.less'; // styles for code blocks and hljs
|
||||
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// lesshint-disable spaceAroundComma, trailingWhitespace
|
||||
|
||||
pre {
|
||||
background: #282C40;
|
||||
padding: 24px;
|
||||
border: 1px solid @core-fleet-black-25;
|
||||
border-radius: 4px;
|
||||
margin: 16px 0px 32px;
|
||||
|
||||
|
||||
&.muted {
|
||||
color: @core-fleet-black-50;
|
||||
background: @ui-off-white;
|
||||
margin: 16px 0px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.hljs {
|
||||
background: #282C40;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/
|
||||
|
||||
*/
|
||||
|
||||
.hljs,
|
||||
.hljs-tag,
|
||||
.hljs-built_in,
|
||||
.hljs-subst {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
.hljs-strong,
|
||||
.hljs-emphasis {
|
||||
color: #a8a8a2;
|
||||
}
|
||||
|
||||
.hljs-bullet,
|
||||
.hljs-quote,
|
||||
.hljs-number,
|
||||
.hljs-regexp,
|
||||
.hljs-literal,
|
||||
.hljs-link {
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
.hljs-code,
|
||||
.hljs-title,
|
||||
.hljs-section,
|
||||
.hljs-selector-class {
|
||||
color: #a6e22e;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-name {
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.hljs-attribute,
|
||||
.hljs-function-keyword {
|
||||
color: #66d9ef;
|
||||
}
|
||||
|
||||
.hljs-attr,
|
||||
.hljs-class .hljs-title {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
.hljs-params {
|
||||
color: #fd9720;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-type,
|
||||
.hljs-builtin-name,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-addition,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable {
|
||||
color: #e6db74;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-deletion,
|
||||
.hljs-meta {
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
#documentation {
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @core-vibrant-blue;
|
||||
}
|
||||
|
||||
input {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
&::placeholder {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
color: @core-fleet-black-50;
|
||||
border-color: @core-fleet-black-25;
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
border-color: @core-fleet-black-25;
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
&:focus {
|
||||
border: 1px solid @core-fleet-black-25;
|
||||
}
|
||||
}
|
||||
|
||||
.cta-card {
|
||||
cursor: pointer;
|
||||
border: 1px solid @ui-gray;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 2px 2px rgba(197, 199, 209, 0.2);
|
||||
.cta-image {
|
||||
max-height: 60px;
|
||||
width: auto;
|
||||
}
|
||||
.cta-text {
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
}
|
||||
img {
|
||||
padding-left: 8px;
|
||||
transition: 0.2s ease-in-out;
|
||||
-o-transition: 0.2s ease-in-out;
|
||||
-ms-transition: 0.2s ease-in-out;
|
||||
-moz-transition: 0.2s ease-in-out;
|
||||
-webkit-transition: 0.2s ease-in-out;
|
||||
}
|
||||
&:hover {
|
||||
.arrow {
|
||||
img {
|
||||
padding-left: 11px;
|
||||
transition: 0.2s ease-in-out;
|
||||
-o-transition: 0.2s ease-in-out;
|
||||
-ms-transition: 0.2s ease-in-out;
|
||||
-moz-transition: 0.2s ease-in-out;
|
||||
-webkit-transition: 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.tree {
|
||||
a {
|
||||
color: @core-fleet-black;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.cta-card {
|
||||
max-width: 437px;
|
||||
min-height: 160px;
|
||||
.cta-image {
|
||||
max-height: 72px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Vendored
+1
-4
@@ -17,10 +17,7 @@ module.exports = {
|
||||
// Add any dev-only routes for local development of not-yet-released pages.
|
||||
// e.g. http://localhost:2024/sandbox/example-query
|
||||
routes: {
|
||||
'GET /sandbox/docs/*': { skipAssets: false, action: 'docs/view-basic-documentation' },// « to see it, check out http://localhost:2024/sandbox/documentation/adsg
|
||||
'GET /sandbox/handbook/*': { skipAssets: false, action: 'handbook/view-basic-handbook' },// « to see it, check out http://localhost:2024/sandbox/handbook/adsg
|
||||
'GET /sandbox/documentation': { action: 'view-documentation' },
|
||||
'GET /sandbox/docs-template': { action: 'view-docs-template' },
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
Vendored
-2
@@ -29,8 +29,6 @@ module.exports.policies = {
|
||||
'docs/*': true,
|
||||
'handbook/*': true,
|
||||
'download-sitemap': true,
|
||||
'view-docs-template': true,
|
||||
'view-documentation': true,
|
||||
'view-transparency': true,
|
||||
|
||||
};
|
||||
|
||||
Vendored
+17
-4
@@ -18,24 +18,37 @@ module.exports.routes = {
|
||||
'GET /get-started': { action: 'view-pricing' },
|
||||
|
||||
'GET /install': 'https://github.com/fleetdm/fleet/blob/main/README.md', // « FUTURE: When ready, bring back { action: 'view-get-started' }
|
||||
'/docs': 'https://github.com/fleetdm/fleet/tree/main/docs',
|
||||
'/hall-of-fame': 'https://github.com/fleetdm/fleet/pulse',
|
||||
'/company/about': '/handbook', // FUTURE: brief "about" page explaining the origins of the company
|
||||
'/handbook': 'https://github.com/fleetdm/fleet/tree/main/handbook',
|
||||
|
||||
'GET /queries': { action: 'view-query-library' },
|
||||
'GET /queries/:slug': { action: 'view-query-detail' },
|
||||
|
||||
'/contribute': 'https://github.com/fleetdm/fleet/tree/main/docs/3-Contributing',
|
||||
'GET /docs/?*': { skipAssets: false, action: 'docs/view-basic-documentation' },// handles /docs and /docs/foo/bar
|
||||
// 'GET /handbook/?*': { skipAssets: false, action: 'handbook/view-basic-handbook' },// handles /handbook and /handbook/foo/bar
|
||||
'GET /handbook': 'https://github.com/fleetdm/fleet/tree/main/handbook',// TODO: Bring back the above when styles are ready
|
||||
|
||||
'/contribute': '/docs/contribute',
|
||||
'/company/stewardship': 'https://github.com/fleetdm/fleet', // FUTURE: page about how we approach open source and our commitments to the community
|
||||
'/legal/terms': 'https://docs.google.com/document/d/1OM6YDVIs7bP8wg6iA3VG13X086r64tWDqBSRudG4a0Y/edit',
|
||||
'/security': 'https://github.com/fleetdm/fleet/security/policy',
|
||||
|
||||
'GET /transparency': { action: 'view-transparency' },
|
||||
|
||||
'GET /apply': 'https://fleet-device-management.breezy.hr',
|
||||
'GET /apply': 'https://fleet-device-management.breezy.hr',
|
||||
|
||||
|
||||
// ╦ ╔═╗╔═╗╔═╗╔═╗╦ ╦ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗
|
||||
// ║ ║╣ ║ ╦╠═╣║ ╚╦╝ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗
|
||||
// ╩═╝╚═╝╚═╝╩ ╩╚═╝ ╩ ╩╚═╚═╝═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝
|
||||
// ┌─ ┌─┐┌─┐┬─┐ ┌┐ ┌─┐┌─┐┬┌─┬ ┬┌─┐┬─┐┌┬┐┌─┐ ┌─┐┌─┐┌┬┐┌─┐┌─┐┌┬┐ ─┐
|
||||
// │ ├┤ │ │├┬┘ ├┴┐├─┤│ ├┴┐│││├─┤├┬┘ ││└─┐ │ │ ││││├─┘├─┤ │ │
|
||||
// └─ └ └─┘┴└─ └─┘┴ ┴└─┘┴ ┴└┴┘┴ ┴┴└──┴┘└─┘ └─┘└─┘┴ ┴┴ ┴ ┴ ┴o ─┘
|
||||
// Use these redirects for deprecated/legacy links, so that they go to an appropriate new place instead of just being broken when docs/etc move or get renamed.
|
||||
// > Note that these redirects take precedence over less specific wildcard routes like '/docs/*' and '/handbook/*'
|
||||
|
||||
'GET /docs/using-fleet/some-deprecated-link-like-this': '/docs/using-fleet/supported-browsers',// « this is just an example to show how
|
||||
|
||||
// ╔╦╗╦╔═╗╔═╗ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗ ┬ ╔╦╗╔═╗╦ ╦╔╗╔╦ ╔═╗╔═╗╔╦╗╔═╗
|
||||
// ║║║║╚═╗║ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗ ┌┼─ ║║║ ║║║║║║║║ ║ ║╠═╣ ║║╚═╗
|
||||
// ╩ ╩╩╚═╝╚═╝ ╩╚═╚═╝═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝ └┘ ═╩╝╚═╝╚╩╝╝╚╝╩═╝╚═╝╩ ╩═╩╝╚═╝
|
||||
|
||||
Vendored
+6
-6
@@ -9,19 +9,19 @@
|
||||
"@sailshq/lodash": "^3.10.3",
|
||||
"@sailshq/socket.io-redis": "^5.2.0",
|
||||
"machinepack-github": "^5.0.0",
|
||||
"sails": "^1.4.3",
|
||||
"sails-hook-apianalytics": "^2.0.3",
|
||||
"sails-hook-organics": "^2.0.0",
|
||||
"sails-hook-orm": "^2.1.1",
|
||||
"sails-hook-sockets": "^2.0.0",
|
||||
"sails": "^1.4.4",
|
||||
"sails-hook-apianalytics": "^2.0.5",
|
||||
"sails-hook-organics": "^2.2.0",
|
||||
"sails-hook-orm": "^3.0.2",
|
||||
"sails-hook-sockets": "^2.0.1",
|
||||
"sails-postgresql": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cheerio": "0.18.0",
|
||||
"eslint": "5.16.0",
|
||||
"grunt": "1.0.4",
|
||||
"htmlhint": "0.11.0",
|
||||
"lesshint": "6.3.6",
|
||||
"marked": "0.3.5",
|
||||
"sails-hook-grunt": "^4.0.0",
|
||||
"yaml": "1.10.2"
|
||||
},
|
||||
|
||||
+186
-54
@@ -24,7 +24,7 @@ module.exports = {
|
||||
let builtStaticContent = {};
|
||||
|
||||
await sails.helpers.flow.simultaneously([
|
||||
async()=>{// Parse query library from YAML and bake them into the Sails app's configuration.
|
||||
async()=>{// Parse query library from YAML and prepare to bake them into the Sails app's configuration.
|
||||
let RELATIVE_PATH_TO_QUERY_LIBRARY_YML_IN_FLEET_REPO = 'docs/1-Using-Fleet/standard-query-library/standard-query-library.yml';
|
||||
let yaml = await sails.helpers.fs.read(path.join(topLvlRepoPath, RELATIVE_PATH_TO_QUERY_LIBRARY_YML_IN_FLEET_REPO));
|
||||
|
||||
@@ -72,7 +72,10 @@ module.exports = {
|
||||
// Talk to GitHub and get additional information about each contributor.
|
||||
let githubDataByUsername = {};
|
||||
await sails.helpers.flow.simultaneouslyForEach(githubUsernames, async(username)=>{
|
||||
githubDataByUsername[username] = await sails.helpers.http.get('https://api.github.com/users/' + encodeURIComponent(username), {}, { 'User-Agent': 'Fleet-Standard-Query-Library', Accept: 'application/vnd.github.v3+json' });
|
||||
githubDataByUsername[username] = await sails.helpers.http.get.with({
|
||||
url: 'https://api.github.com/users/' + encodeURIComponent(username),
|
||||
headers: { 'User-Agent': 'Fleet-Standard-Query-Library', Accept: 'application/vnd.github.v3+json' }
|
||||
});
|
||||
});//∞
|
||||
|
||||
// Now expand queries with relevant profile data for the contributors.
|
||||
@@ -90,23 +93,24 @@ module.exports = {
|
||||
query.contributors = contributorProfiles;
|
||||
}
|
||||
|
||||
// Attach to Sails app configuration.
|
||||
// Attach to what will become configuration for the Sails app.
|
||||
builtStaticContent.queries = queries;
|
||||
builtStaticContent.queryLibraryYmlRepoPath = RELATIVE_PATH_TO_QUERY_LIBRARY_YML_IN_FLEET_REPO;
|
||||
},
|
||||
async()=>{// Parse markdown pages, compile & generate HTML files, and bake documentation's directory tree into the Sails app's configuration.
|
||||
async()=>{// Parse markdown pages, compile & generate HTML files, and prepare to bake directory trees into the Sails app's configuration.
|
||||
let APP_PATH_TO_COMPILED_PAGE_PARTIALS = 'views/partials/built-from-markdown';
|
||||
|
||||
// Note:
|
||||
// • path maths inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L107-L132
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// // Original way that works: (versus new stuff below)
|
||||
// builtStaticContent.markdownPages = await sails.helpers.compileMarkdownContent('docs/'); // TODO remove this and helper once everything works again
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Delete existing HTML output from previous runs, if any.
|
||||
await sails.helpers.fs.rmrf(path.resolve(sails.config.appPath, APP_PATH_TO_COMPILED_PAGE_PARTIALS));
|
||||
|
||||
builtStaticContent.markdownPages = [];// « dir tree representation that will be injected into Sails app's configuration
|
||||
|
||||
let SECTION_REPO_PATHS = ['docs/', 'handbook/'];
|
||||
for (let sectionRepoPath of SECTION_REPO_PATHS) {
|
||||
let SECTION_INFOS_BY_SECTION_REPO_PATHS = {
|
||||
'docs/': { urlPrefix: '/docs', },
|
||||
// 'handbook/': { urlPrefix: '/handbook', }, // TODO: Bring this back when styles are complete (removed from build in the meantime so that sitemap.xml is not incorrect)
|
||||
};
|
||||
let rootRelativeUrlPathsSeen = [];
|
||||
for (let sectionRepoPath of Object.keys(SECTION_INFOS_BY_SECTION_REPO_PATHS)) {// FUTURE: run this in parallel
|
||||
let thinTree = await sails.helpers.fs.ls.with({
|
||||
dir: path.join(topLvlRepoPath, sectionRepoPath),
|
||||
depth: 100,
|
||||
@@ -114,15 +118,39 @@ module.exports = {
|
||||
includeSymlinks: false,
|
||||
});
|
||||
|
||||
let rootRelativeUrlPathsSeen = [];
|
||||
for (let pageSourcePath of thinTree) {
|
||||
for (let pageSourcePath of thinTree) {// FUTURE: run this in parallel
|
||||
|
||||
// Perform path maths (determine this using sectionRepoPath, etc)
|
||||
// Crunch some paths (used for determining the URL, etc below.)
|
||||
// > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L308-L313
|
||||
// > And https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L107-L132
|
||||
let rootRelativeUrlPath = `/todo-${_.trimRight(sectionRepoPath,'/')}-${pageSourcePath.slice(-30).replace(/[^a-z0-9\-]/ig,'')}-${Math.floor(Math.random()*10000000)}`;
|
||||
sails.log.verbose(`Building page ${rootRelativeUrlPath} from ${pageSourcePath} (${sectionRepoPath})`);
|
||||
// ^^TODO: replace that with the actual desired root relative URL path
|
||||
let pageRelSourcePath = path.relative(path.join(topLvlRepoPath, sectionRepoPath), path.resolve(pageSourcePath));
|
||||
let pageUnextensionedLowercasedRelPath = (
|
||||
pageRelSourcePath
|
||||
.replace(/(^|\/)([^/]+)\.[^/]*$/, '$1$2')
|
||||
.split(/\//).map((fileOrFolderName) => fileOrFolderName.toLowerCase()).join('/')
|
||||
);
|
||||
let RX_README_FILENAME = /\/?readme\.?m?d?$/i;// « for matching `readme` or `readme.md` (case-insensitive) at the end of a file path
|
||||
|
||||
// Determine this page's default (fallback) display title.
|
||||
// (README pages use their folder name as their fallback title.)
|
||||
let fallbackPageTitle;
|
||||
if (pageSourcePath.match(RX_README_FILENAME)) {
|
||||
// console.log(pageRelSourcePath.split(/\//).slice(-2)[0], path.basename(pageRelSourcePath), pageRelSourcePath);
|
||||
fallbackPageTitle = sails.helpers.strings.toSentenceCase(pageRelSourcePath.split(/\//).slice(-2)[0]);
|
||||
} else {
|
||||
fallbackPageTitle = sails.helpers.strings.toSentenceCase(path.basename(pageSourcePath, path.extname(pageSourcePath)));
|
||||
}
|
||||
|
||||
// Determine URL for this page
|
||||
let rootRelativeUrlPath = (
|
||||
(
|
||||
SECTION_INFOS_BY_SECTION_REPO_PATHS[sectionRepoPath].urlPrefix +
|
||||
'/' + (
|
||||
pageUnextensionedLowercasedRelPath
|
||||
.split(/\//).map((fileOrFolderName) => encodeURIComponent(fileOrFolderName.replace(/^[0-9]+[\-]+/,''))).join('/')// « Get URL-friendly by encoding characters and stripping off ordering prefixes (like the "1-" in "1-Using-Fleet") for all folder and file names in the path.
|
||||
)
|
||||
).replace(RX_README_FILENAME, '')// « Interpret README files as special and map it to the URL representing its containing folder.
|
||||
);
|
||||
|
||||
// Assert uniqueness of URL paths.
|
||||
if (rootRelativeUrlPathsSeen.includes(rootRelativeUrlPath)) {
|
||||
@@ -130,51 +158,155 @@ module.exports = {
|
||||
}//•
|
||||
rootRelativeUrlPathsSeen.push(rootRelativeUrlPath);
|
||||
|
||||
// Get last modified timestamp using git
|
||||
// > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L265-L273
|
||||
let lastModifiedAt = Date.now();// TODO
|
||||
if (path.extname(pageSourcePath) !== '.md') {// If this file doesn't end in `.md`: skip it (we won't create a page for it)
|
||||
// > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L275-L276
|
||||
sails.log.verbose(`Skipping ${pageSourcePath}`);
|
||||
} else {// Otherwise, this is markdown, so: Compile to HTML, parse docpage metadata, and build+track it as a page
|
||||
sails.log.verbose(`Building page ${rootRelativeUrlPath} (from ${pageSourcePath})`);
|
||||
|
||||
let fallbackTitle = sails.helpers.strings.toSentenceCase(path.basename(pageSourcePath, '.ejs'));// « for clarity (the page isn't a template, necessarily, and this title is just a guess. Display title will, more likely than not, come from a <docmeta> tag -- see the bottom of the original, raw unformatted markdown of any page in the sailsjs docs for an example of how to use docmeta tags)
|
||||
// Compile markdown to HTML.
|
||||
// > This includes build-time enablement of:
|
||||
// > • syntax highlighting
|
||||
// > • data type bubbles
|
||||
// > • transforming relative markdown links to their fleetdm.com equivalents
|
||||
// >
|
||||
// > For more info about how these additional features work, see: https://github.com/fleetdm/fleet/issues/706#issuecomment-884622252
|
||||
// >
|
||||
// > • What about images referenced in markdown files? :: They need to be referenced using an absolute URL src-- e.g.  See also https://github.com/fleetdm/fleet/issues/706#issuecomment-884641081 for reasoning.
|
||||
// > • What about GitHub-style emojis like `:white_check_mark:`? :: Use actual unicode emojis instead. Need to revisit this? Visit https://github.com/fleetdm/fleet/pull/1380/commits/19a6e5ffc70bf41569293db44100e976f3e2bda7 for more info.
|
||||
let mdString = await sails.helpers.fs.read(pageSourcePath);
|
||||
mdString = mdString.replace(/(```)([a-zA-Z0-9\-]*)(\s*\n)/g, '$1\n' + '<!-- __LANG=%' + '$2' + '%__ -->' + '$3'); // « Based on the github-flavored markdown's language annotation, (e.g. ```js```) add a temporary marker to code blocks that can be parsed post-md-compilation when this is HTML. Note: This is an HTML comment because it is easy to over-match and "accidentally" add it underneath each code block as well (being an HTML comment ensures it doesn't show up or break anything). For more information, see https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L198-L202
|
||||
let htmlString = await sails.helpers.strings.toHtml(mdString);
|
||||
htmlString = (// « Add the appropriate class to the `<code>` based on the temporary "LANG" markers that were just added above
|
||||
htmlString
|
||||
.replace(// Interpret `js` as `javascript`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%js\%__ --\>)\s*/gm,
|
||||
'$1 class="javascript"$2$3'
|
||||
)
|
||||
.replace(// Interpret `sh` and `bash` as `bash`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%(bash|sh)\%__ --\>)\s*/gm,
|
||||
'$1 class="bash"$2$3'
|
||||
)
|
||||
.replace(// When unspecified, default to `text`
|
||||
// $1 $2 $3 $4
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%\%__ --\>)\s*/gm,
|
||||
'$1 class="nohighlight"$2$3'
|
||||
)
|
||||
.replace(// Finally, nab the rest, leaving the code language as-is.
|
||||
// $1 $2 $3 $4 $5 $6
|
||||
/(<code)([^>]*)(>\s*)(\<!-- __LANG=\%)([^%]+)(\%__ --\>)\s*/gm,
|
||||
'$1 class="$5"$2$3'
|
||||
)
|
||||
);
|
||||
htmlString = htmlString.replace(/\(\(([^())]*)\)\)/g, '<bubble type="$1" class="colors"><span is="bubble-heart"></span></bubble>');// « Replace ((bubble))s with HTML. For more background, see https://github.com/fleetdm/fleet/issues/706#issuecomment-884622252
|
||||
htmlString = htmlString.replace(/(href="(\.\/[^"]+|\.\.\/[^"]+)")/g, (hrefString)=>{// « Modify path-relative links like `./…` and `../…` to make them absolute. (See https://github.com/fleetdm/fleet/issues/706#issuecomment-884641081 for more background)
|
||||
let oldRelPath = hrefString.match(/href="(\.\/[^"]+|\.\.\/[^"]+)"/)[1];
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Note: This approach won't work as far as linking between handbook and docs
|
||||
// FUTURE: improve it so that it does. This may involve pulling out URL determination as a separate, first step, then looking up the appropriate URL.
|
||||
// Currently this is a kinda duplicative hack, that just determines the appropriate URL in a similar way to all the code above...
|
||||
// -mikermcneil 2021-07-27
|
||||
// ```
|
||||
let referencedPageSourcePath = path.resolve(path.join(topLvlRepoPath, sectionRepoPath, pageRelSourcePath), '../', oldRelPath);
|
||||
let referencedPageNewUrl = 'https://fleetdm.com/' + (
|
||||
(path.relative(topLvlRepoPath, referencedPageSourcePath).replace(/(^|\/)([^/]+)\.[^/]*$/, '$1$2').split(/\//).map((fileOrFolderName) => fileOrFolderName.toLowerCase()).join('/'))
|
||||
.split(/\//).map((fileOrFolderName) => encodeURIComponent(fileOrFolderName.replace(/^[0-9]+[\-]+/,''))).join('/')
|
||||
).replace(RX_README_FILENAME, '');
|
||||
// console.log(pageRelSourcePath, '»» '+hrefString+' »»»» href="'+referencedPageNewUrl+'"');
|
||||
// ```
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
return `href="${referencedPageNewUrl}"`;
|
||||
});
|
||||
htmlString = htmlString.replace(/(href="https?:\/\/([^"]+)")/g, (hrefString)=>{// « Modify links that are potentially external
|
||||
// Check if this is an external link (like https://google.com) but that is ALSO not a link
|
||||
// to some page on the destination site where this will be hosted, like `(*.)?fleetdm.com`.
|
||||
// If external, add target="_blank" so the link will open in a new tab.
|
||||
let isExternal = ! hrefString.match(/^href=\"https?:\/\/([^\.]+\.)*fleetdm\.com/g);// « FUTURE: make this smarter with sails.config.baseUrl + _.escapeRegExp()
|
||||
if (isExternal) {
|
||||
return hrefString.replace(/(href="https?:\/\/([^"]+)")/g, '$1 target="_blank"');
|
||||
} else {
|
||||
// Otherwise, change the link to be web root relative.
|
||||
// (e.g. 'href="http://sailsjs.com/documentation/concepts"'' becomes simply 'href="/documentation/concepts"'')
|
||||
// > Note: See the Git version history of "compile-markdown-content.js" in the sailsjs.com website repo for examples of ways this can work across versioned subdomains.
|
||||
return hrefString.replace(/href="https?:\/\//, '').replace(/^fleetdm\.com/, 'href="');
|
||||
}
|
||||
|
||||
// If markdown: Compile to HTML and parse docpage metadata
|
||||
// > Parsing docmeta tags (consider renaming them to just <meta>- or by now there's probably a more standard way of embedding semantics in markdown files; prefer to use that): https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L180-L183
|
||||
// > Compiling: https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L198-L202
|
||||
// TODO
|
||||
});//∞
|
||||
|
||||
// Skip this page, if appropriate
|
||||
// > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L275-L276
|
||||
// TODO
|
||||
// Extract metadata from markdown.
|
||||
// > • Parsing meta tags (consider renaming them to just <meta>- or by now there's probably a more standard way of embedding semantics in markdown files; prefer to use that): https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L180-L183
|
||||
// > See also https://github.com/mikermcneil/machinepack-markdown/blob/5d8cee127e8ce45c702ec9bbb2b4f9bc4b7fafac/machines/parse-docmeta-tags.js#L42-L47
|
||||
// >
|
||||
// > e.g. referring to stuff like:
|
||||
// > ```
|
||||
// > <meta name="foo" value="bar">
|
||||
// > <meta name="title" value="Sth with punctuATION and weird CAPS ... but never this long, please">
|
||||
// > ```
|
||||
let embeddedMetadata = {};
|
||||
for (let tag of (mdString.match(/<meta[^>]*>/igm)||[])) {
|
||||
let name = tag.match(/name="([^">]+)"/i)[1];
|
||||
let value = tag.match(/value="([^">]+)"/i)[1];
|
||||
embeddedMetadata[name] = value;
|
||||
}//∞
|
||||
if (Object.keys(embeddedMetadata).length >= 1) {
|
||||
sails.log.silly(`Parsed ${Object.keys(embeddedMetadata).length} <meta> tags:`, embeddedMetadata);
|
||||
}//fi
|
||||
|
||||
// Generate HTML file
|
||||
let htmlOutputPath = '';//TODO
|
||||
if (dry) {
|
||||
sails.log('Dry run: Would have generated file:', htmlOutputPath);
|
||||
} else {
|
||||
// TODO
|
||||
// Get last modified timestamp using git, and represent it as a JS timestamp.
|
||||
// > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L265-L273
|
||||
let lastModifiedAt = (new Date((await sails.helpers.process.executeCommand.with({
|
||||
command: `git log -1 --format="%ai" '${path.relative(topLvlRepoPath, pageSourcePath)}'`,
|
||||
dir: topLvlRepoPath,
|
||||
})).stdout)).getTime();
|
||||
|
||||
// Determine display title (human-readable title) to use for this page.
|
||||
let pageTitle;
|
||||
if (embeddedMetadata.title) {// Attempt to use custom title, if one was provided.
|
||||
if (embeddedMetadata.title.length > 40) {
|
||||
throw new Error(`Failed compiling markdown content: Invalid custom title (<meta name="title" value="${embeddedMetadata.title}">) embedded in "${path.join(topLvlRepoPath, sectionRepoPath)}". To resolve, try changing the title to a different, valid value, then rebuild.`);
|
||||
}//•
|
||||
pageTitle = embeddedMetadata.title;
|
||||
} else {// Otherwise use the automatically-determined fallback title.
|
||||
pageTitle = fallbackPageTitle;
|
||||
}
|
||||
|
||||
// Determine unique HTML id
|
||||
// > • This will become the filename of the resulting HTML.
|
||||
// > • And it will be attached to menu data for use in sorting pages within their bottom-level sections.
|
||||
let htmlId = (
|
||||
sectionRepoPath.slice(0,10)+
|
||||
'--'+
|
||||
_.last(pageUnextensionedLowercasedRelPath.split(/\//)).slice(0,20)+
|
||||
'--'+
|
||||
sails.helpers.strings.random.with({len:10})// if two files in different folders happen to have the same filename, there is a 1/16^10 chance of a collision (this is small enough- worst case, the build fails at the uniqueness check and we rerun it.)
|
||||
).replace(/[^a-z0-9\-]/ig,'');
|
||||
|
||||
// Generate HTML file
|
||||
let htmlOutputPath = path.resolve(sails.config.appPath, path.join(APP_PATH_TO_COMPILED_PAGE_PARTIALS, htmlId+'.ejs'));
|
||||
if (dry) {
|
||||
sails.log('Dry run: Would have generated file:', htmlOutputPath);
|
||||
} else {
|
||||
await sails.helpers.fs.write(htmlOutputPath, htmlString);
|
||||
}
|
||||
|
||||
// Append to what will become configuration for the Sails app.
|
||||
builtStaticContent.markdownPages.push({
|
||||
url: rootRelativeUrlPath,
|
||||
title: pageTitle,
|
||||
lastModifiedAt: lastModifiedAt,
|
||||
htmlId: htmlId,
|
||||
meta: _.omit(embeddedMetadata, 'title')
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Figure out what to do about embedded images (they'll get cached by CDN so probably ok to point at github, but markdown img srcs will break if relative. Also GitHub could just change image URLs whenever.)
|
||||
|
||||
// Append to Sails app configuration.
|
||||
builtStaticContent.markdownPages.push({
|
||||
url: rootRelativeUrlPath,
|
||||
title: '' || fallbackTitle,// TODO use metadata title if available
|
||||
lastModifiedAt: lastModifiedAt
|
||||
});
|
||||
}//∞ </each source file>
|
||||
}//∞ </each section repo path>
|
||||
|
||||
// Decorate markdownPages tree with easier-to-use properties related to metadata embedded in the markdown and parent/child relationships.
|
||||
// Note: Maybe skip the parent/child relationships.
|
||||
// > Inspired by https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/helpers/marshal-doc-page-metadata.js
|
||||
// > And https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/build-jsmenu.js
|
||||
// TODO
|
||||
// Attach partials dir path in what will become configuration for the Sails app.
|
||||
// (This is for easier access later, without defining this constant in more than one place.)
|
||||
builtStaticContent.compiledPagePartialsAppPath = APP_PATH_TO_COMPILED_PAGE_PARTIALS;
|
||||
|
||||
// Sort siblings in the markdownPages tree so it's ready to use in menus.
|
||||
// > Note: consider doing this on the frontend-- though there's a reason it was here. See:
|
||||
// > • https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/helpers/compare-doc-page-metadatas.js
|
||||
// > • https://github.com/sailshq/sailsjs.com/blob/b53c6e6a90c9afdf89e5cae00b9c9dd3f391b0e7/api/helpers/marshal-doc-page-metadata.js#L191-L208
|
||||
// TODO
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
Vendored
+10
-12
@@ -87,8 +87,8 @@
|
||||
<div class="d-flex flex-column mb-4">
|
||||
<span style="font-weight: 700;" class="py-2 px-3">Get started</span>
|
||||
<a class="mobile-menu-item py-2 px-3" target="_blank" href="/install" data-text="Try Fleet">Try Fleet</a>
|
||||
<a class="mobile-menu-item py-2 px-3" target="_blank" href="/documentation" data-text="Documentation">Documentation</a>
|
||||
<a class="mobile-menu-item py-2 px-3" target="_blank" href="/contribute" data-text="Contribute">Contribute</a>
|
||||
<a class="mobile-menu-item py-2 px-3" href="/docs" data-text="Documentation">Documentation</a>
|
||||
<a class="mobile-menu-item py-2 px-3" href="/contribute" data-text="Contribute">Contribute</a>
|
||||
<a class="mobile-menu-item py-2 px-3" target="_blank" href="/hall-of-fame" data-text="Hall of fame">Hall of fame</a>
|
||||
</div>
|
||||
<a href="/queries" class="menu-link d-flex align-items-center px-3 py-2 mb-4 text-decoration-none" style=" text-decoration: none; font-weight: 700;">Queries</a>
|
||||
@@ -111,8 +111,8 @@
|
||||
</button>
|
||||
<div style="border-radius: 8px;" class="dropdown-menu dropdown-container p-2" aria-labelledby="dropdownMenuButton">
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" target="_blank" href="/install" data-text="Try Fleet">Try Fleet</a>
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" target="_blank" href="/documentation" data-text="Documentation">Documentation</a>
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" target="_blank" href="/contribute" data-text="Contribute">Contribute</a>
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" href="/docs" data-text="Documentation">Documentation</a>
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" href="/contribute" data-text="Contribute">Contribute</a>
|
||||
<a style="border-radius: 4px;" class="dropdown-item py-2 px-3" target="_blank" href="/hall-of-fame" data-text="Hall of fame">Hall of fame</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -140,12 +140,12 @@
|
||||
<div style="max-width: 1248px;" class="container-fluid d-flex flex-column flex-lg-row justify-content-center justify-content-lg-between px-3 px-md-4 pt-4 pb-0 mt-md-5 mb-lg-5">
|
||||
<div class="d-flex flex-grow-1 flex-column align-items-center">
|
||||
<div class="container-fluid d-block d-md-flex flex-md-row text-center justify-content-between justify-content-lg-end px-5 px-lg-0 pt-lg-3 pb-4 pb-md-0">
|
||||
<a href="https://github.com/fleetdm/fleet/blob/main/README.md" class="d-block pr-lg-4 pb-4">Try Fleet</a>
|
||||
<a href="https://github.com/fleetdm/fleet/tree/main/docs" class="d-block pr-lg-4 pb-4">Documentation</a>
|
||||
<a href="/install" class="d-block pr-lg-4 pb-4">Try Fleet</a>
|
||||
<a href="/docs" class="d-block pr-lg-4 pb-4">Documentation</a>
|
||||
<a href="/pricing" class="d-block pr-lg-4 pb-4">Pricing</a>
|
||||
<a href="https://github.com/fleetdm/fleet/tree/main/docs/3-Contributing" class="d-block pr-lg-4 pb-4">Contribute</a>
|
||||
<a href="https://medium.com/fleetdm" class="d-block pr-lg-4 pb-4">Blog</a>
|
||||
<a href="https://github.com/fleetdm/fleet/pulse" class="d-block pb-4">Hall of fame</a>
|
||||
<a href="/docs/contributing" class="d-block pr-lg-4 pb-4">Contribute</a>
|
||||
<a href="/blog" class="d-block pr-lg-4 pb-4">Blog</a>
|
||||
<a href="/hall-of-fame" class="d-block pb-4">Hall of fame</a>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid d-flex flex-column flex-md-row font-weight-bold justify-content-center justify-content-lg-end px-0 pt-3 pt-md-0">
|
||||
@@ -213,6 +213,7 @@
|
||||
<script src="/dependencies/vue-router.js"></script>
|
||||
<script src="/dependencies/bootstrap-4/bootstrap-4.bundle.js"></script>
|
||||
<script src="/dependencies/cloud.js"></script>
|
||||
<script src="/dependencies/highlight.min.js"></script>
|
||||
<script src="/dependencies/moment.js"></script>
|
||||
<script src="/dependencies/parasails.js"></script>
|
||||
<script src="/js/cloud.setup.js"></script>
|
||||
@@ -223,15 +224,12 @@
|
||||
<script src="/js/components/modal.component.js"></script>
|
||||
<script src="/js/components/stripe-card-element.component.js"></script>
|
||||
<script src="/js/utilities/open-stripe-checkout.js"></script>
|
||||
<script src="/js/pages/498.page.js"></script>
|
||||
<script src="/js/pages/account/account-overview.page.js"></script>
|
||||
<script src="/js/pages/account/edit-password.page.js"></script>
|
||||
<script src="/js/pages/account/edit-profile.page.js"></script>
|
||||
<script src="/js/pages/contact.page.js"></script>
|
||||
<script src="/js/pages/dashboard/welcome.page.js"></script>
|
||||
<script src="/js/pages/docs-template.page.js"></script>
|
||||
<script src="/js/pages/docs/basic-documentation.page.js"></script>
|
||||
<script src="/js/pages/documentation.page.js"></script>
|
||||
<script src="/js/pages/entrance/confirmed-email.page.js"></script>
|
||||
<script src="/js/pages/entrance/forgot-password.page.js"></script>
|
||||
<script src="/js/pages/entrance/login.page.js"></script>
|
||||
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
<div id="docs-template" v-cloak>
|
||||
<div style="max-width: 1200px;" class="container-fluid px-3 px-sm-4 mb-5">
|
||||
|
||||
<div purpose="breadcrumbs-and-search" class="conainer-fluid d-flex flex-column flex-lg-row justify-content-lg-between p-0 pt-4 pb-lg-2 m-0 breadcrumbs-search">
|
||||
|
||||
<div purpose="breadcrumbs" class="d-none d-lg-flex p-0 m-0 align-items-center breadcrumbs">
|
||||
<a href="/docs" class="pr-3">Documentation</a>
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png"/>
|
||||
<a :href="'/docs/' + _.kebabCase(currentPage.section)" class="px-3">{{currentPage.section}}</a>
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png"/>
|
||||
<p class="px-3 m-0">{{currentPage.topic}}</p>
|
||||
</div>
|
||||
|
||||
<div purpose="search" class="d-flex p-0 mb-2 mb-lg-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend border-right-0">
|
||||
<span class="input-group-text bg-transparent border-right-0 pl-3 pr-2"><img style="height: 16px; width: auto;" class="search" alt="search"
|
||||
src="/images/icon-search-16x16@2x.png"></span>
|
||||
</div>
|
||||
<input class="form-control border-left-0 px-0" placeholder="Search the docs..." aria-label="Search the docs"
|
||||
v-model="inputTextValue" @keydown.self="delayInput(setSearchString, 400, 'defaultTimer')()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div purpose="mobile-docs-nav" class="d-flex-block d-lg-none">
|
||||
<div class="d-flex flex-column d-lg-none p-0 m-0 justify-content-start align-items-center">
|
||||
<button type="button" purpose="docs-nav-button" class="btn btn-block d-flex align-items-center docs-nav-button" @click="toggleDocsNav">
|
||||
<span class="pr-2 m-0">Docs</span>
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png"/>
|
||||
<span class="font-weight-bold px-2 m-0">{{currentPage.section}}</span>
|
||||
<img style="width: 6px; height: 9px;" class="ml-auto" alt="right chevron" src="/images/chevron-right-6x9@2x.png" v-if="!showDocsNav"/>
|
||||
<img style="width: 9px; height: 6px;" class="ml-auto" alt="down chevron" src="/images/chevron-down-9x6@2x.png" v-else/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex px-0 mobile-docs-nav" v-if="showDocsNav">
|
||||
<div class="container-fluid px-0 py-4">
|
||||
<ul class="px-0">
|
||||
<li class="px-0 mb-2" v-for="section in outline.sections">
|
||||
<a :href="'/docs/' + _.kebabCase(section.title)" class="font-weight-bold">{{section.title}}</a>
|
||||
<ul class="px-0 pt-3" v-if="section.topics && section.topics.length">
|
||||
<li class="px-0 mb-2" v-for="topic in section.topics">
|
||||
<a :href="'/docs/' + _.kebabCase(section.title) + '/' + _.kebabCase(topic.title)" :class="topic.title === currentPage.topic ? 'topic active' : 'topic'">{{topic.title}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h1 class="d-flex d-lg-none py-4 m-0">{{currentPage.topic}}</h1>
|
||||
|
||||
<div class="container-fluid d-flex flex-column flex-lg-row justify-content-start justify-content-lg-between p-0 pt-lg-4 pb-lg-4 m-0">
|
||||
|
||||
<div purpose="left-sidebar" class="container-fluid d-none d-lg-flex flex-column text-left pl-0 pr-4 left-sidebar">
|
||||
<ul class="p-0 pb-2 m-0 left-nav">
|
||||
<li v-for="section in outline.sections" :key="section.title">
|
||||
<a :href="'/docs/' + _.kebabCase(section.title)" class="font-weight-bold pb-3">{{section.title}}</a>
|
||||
<div class="pt-2" v-if="section.title === currentPage.section">
|
||||
<ul class="p-0 mb-2">
|
||||
<li v-for="topic in section.topics" :key="topic.title">
|
||||
<a :href="'/docs/' + _.kebabCase(section.title) + '/' + _.kebabCase(topic.title)" :class="topic.title === currentPage.topic ? 'topic active' : 'topic'">{{topic.title}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="font-weight-bold py-3" href="https://github.com/fleetdm/fleet/releases">Releases</a>
|
||||
<a href="/support" class="btn btn-block btn-sm btn-primary">Support</a>
|
||||
</div>
|
||||
|
||||
<div purpose="right-sidebar" class="container-fluid order-first order-lg-last p-0 pb-2 pb-lg-0 pr-lg-0 right-sidebar">
|
||||
|
||||
<h6 class="font-weight-bold pb-2 m-0 mb-2">On this page:</h6>
|
||||
<div class="subtopics">
|
||||
<ul class="p-0">
|
||||
<li class="subtopic" v-for="(subtopic, index) in getSubtopics()">
|
||||
<div class="d-none d-lg-block active" v-if="index === 0"></div>
|
||||
<p class="pl-lg-2 m-0">{{subtopic}}</p>
|
||||
</li>
|
||||
<li class="d-lg-none subtopic">Help and feedback</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h6 class="d-none d-lg-block font-weight-bold py-2">Related topics</h6>
|
||||
<ul class="d-none d-lg-block p-0">
|
||||
<li v-for="relatedTopic in getRelatedTopics()">{{relatedTopic}}</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div purpose="content" class="d-flex flex-column p-0 pl-lg-5 pr-lg-4 content">
|
||||
|
||||
<h1 class="d-none d-lg-flex pb-3 mb-3">{{currentPage.topic}}</h1>
|
||||
|
||||
<div class="d-flex" v-for="item in body" :key="item.type + _.uniqueId()">
|
||||
<h3 class="d-flex pb-4 m-0" v-if="item.type === 'subtopic'">{{item.content}}</h3>
|
||||
<p class="d-flex pb-4 mb-3" v-if="item.type === 'text'">{{item.content}}</p>
|
||||
<img style="width: 100%; height: 100%;" class="d-flex pb-4 mx-auto mb-3" alt="screenshot" :alt="item.altText || 'A screenshot of ' + currentPage.topic" :src="item.content" v-if="item.type === 'image'" />
|
||||
<div class="w-100 pb-4 mb-3" v-if="item.type === 'note'">
|
||||
<div class="p-4 note">
|
||||
<p class="font-weight-bold">Note:</p>
|
||||
<p>{{item.content}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-4 m-0" v-if="item.type === 'bullets'">
|
||||
<p class="pb-4 m-0" v-if="item.content.intro">{{item.content.intro}}</p>
|
||||
<ul>
|
||||
<li v-for="bullet in item.content.bullets">{{bullet}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-none d-lg-block">
|
||||
<h3 class="pb-4 m-0">Is there something missing?</h3>
|
||||
<p>
|
||||
If you notice something we've missed or could be improved on, please follow <a href="https://github.com/fleetdm/fleet">this link</a> and submit a pull request to the Fleet repo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
|
||||
+207
-4
@@ -1,11 +1,214 @@
|
||||
<div id="basic-documentation" v-cloak>
|
||||
|
||||
<h1>TODO: Implement this page.</h1>
|
||||
<p>(See also <em>assets/styles/pages/docs/basic-documentation.less</em>, <em>assets/js/pages/docs/basic-documentation.page.js</em>, and <em>api/controllers/docs/view-basic-documentation.js</em>.)</p>
|
||||
<div purpose="docs-landing-page" v-if="isDocsLandingPage">
|
||||
<div style="max-width: 948px;" class="container-fluid p-0 px-3 px-sm-4 py-5 mb-5 mx-auto">
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="pt-5">Fleet documentation</h1>
|
||||
<p class="mb-2">Welcome to the documentation for Fleet, an open-source osquery management server.</p>
|
||||
<!-- <p class="mb-0"><strong>v4.0.1 </strong><a href="https://github.com/fleetdm/fleet/releases">changelog</a></p> -->
|
||||
<!-- TODO automatically display latest release version or come up with some other way to present this that doesn't rely on knowing the version number -->
|
||||
</div>
|
||||
|
||||
<!-- TODO: bring back search -->
|
||||
<!-- <div purpose="search" class="d-flex p-0 pt-4 mt-3">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend border-right-0">
|
||||
<span class="input-group-text bg-transparent border-right-0 pl-3 pr-2">
|
||||
<img style="height: 16px; width: auto;" class="search" alt="search" src="/images/icon-search-16x16@2x.png"></span>
|
||||
</div>
|
||||
<input class="form-control border-left-0 px-0" placeholder="Search the docs..." aria-label="Search the docs"
|
||||
v-model="inputTextValue" @keydown.self="delayInput(setSearchString, 400, 'defaultTimer')()" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div purpose="cta-cards">
|
||||
<div class="container-fluid d-flex flex-column flex-sm-row justify-content-sm-between p-0 pt-4 mt-3">
|
||||
<div class="container-fluid d-flex flex-column flex-md-row justify-content-center align-items-center py-3 m-0 mr-sm-1 cta-card" @click="clickCTA('/install')">
|
||||
<img class="cta-image" alt="Install Fleet" src="/images/install-fleet-140x72@2x.png"/>
|
||||
<div class="text-center text-md-left cta-text">
|
||||
<p class="font-weight-bold p-0 pl-md-4 pt-2 pt-md-0 m-0">Install osquery and Fleet</p>
|
||||
<a class="p-0 pl-md-4 pt-2 pt-md-0 arrow" href="/get-started">
|
||||
Get started
|
||||
<img class="d-inline mb-1" style="height: 16px; width: auto;" alt="right arrow" src="/images/arrow-right-16x16@2x.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid d-flex flex-column flex-md-row justify-content-center align-items-center py-3 m-0 ml-sm-1 mt-3 mt-sm-0 cta-card" @click="clickCTA('support')">
|
||||
<img class="cta-image" alt="Fleet support" src="/images/fleet-support-140x72@2x.png"/>
|
||||
<div class="text-center text-md-left cta-text">
|
||||
<p class="font-weight-bold p-0 pl-md-4 pt-2 pt-md-0 m-0">Can't find what you need?</p>
|
||||
<a class="p-0 pl-md-4 pt-2 pt-md-0 arrow" href="/support">
|
||||
Support
|
||||
<img class="d-inline mb-1" style="height: 16px; width: auto;" alt="right arrow" src="/images/arrow-right-16x16@2x.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div purpose="docs-tree">
|
||||
<div class="container-fluid d-flex flex-column flex-sm-row justify-content-sm-between p-0 px-4">
|
||||
<div v-for="page in findPagesByUrl()">
|
||||
<div style="max-width: 300px;" class="container-fluid justify-content-start align-items-center p-0 px-2 pt-4 m-0 mt-3">
|
||||
<h3 class="mb-4">{{page.title}}</h3>
|
||||
<ul style="list-style: none;" class="p-0 m-0">
|
||||
<li class="mb-2" v-for="subpage in findPagesByUrl(page.url)">
|
||||
<a :href="subpage.url">{{subpage.title}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This paragraph, and the content above it, are just here for reference. The HTML generated from markdown is below.</p>
|
||||
<div v-else>
|
||||
<div purpose="docs-template" style="max-width: 1200px;" class="container-fluid px-3 px-sm-4 mb-5">
|
||||
|
||||
<%- partial('../../partials/built-from-markdown/docs/1-Using-Fleet/1-Fleet-UI.ejs') %>
|
||||
<div purpose="breadcrumbs-and-search" class="conainer-fluid d-flex flex-column flex-lg-row justify-content-lg-between p-0 pt-4 pb-lg-2 m-0 breadcrumbs-search">
|
||||
|
||||
<div purpose="breadcrumbs" class="d-none d-lg-flex p-0 m-0 align-items-center breadcrumbs">
|
||||
<a :href="'/' + breadcrumbs[0]" class="pr-3" v-if="breadcrumbs.length > 1">
|
||||
{{breadcrumbs[0] === 'docs' ? 'Documentation' : breadcrumbs[0]}}
|
||||
</a>
|
||||
<div class="d-flex p-0 m-0 align-items-center" v-if="breadcrumbs.length === 3">
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png" />
|
||||
<a :href="'/' + breadcrumbs[0] + '/' + breadcrumbs[1]" class="px-3">
|
||||
{{getTitleFromUrl(breadcrumbs[1])}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex p-0 m-0 align-items-center" v-if="breadcrumbs.length > 1">
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png"/>
|
||||
<p class="px-3 m-0">
|
||||
{{thisPage.title}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div purpose="search" class="d-flex p-0 mb-2 mb-lg-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend border-right-0">
|
||||
<span class="input-group-text bg-transparent border-right-0 pl-3 pr-2"><img style="height: 16px; width: auto;" class="search" alt="search"
|
||||
src="/images/icon-search-16x16@2x.png"></span>
|
||||
</div>
|
||||
<input class="form-control border-left-0 px-0" placeholder="Search the docs..." aria-label="Search the docs"
|
||||
v-model="inputTextValue" @keydown.self="delayInput(setSearchString, 400, 'defaultTimer')()" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div purpose="mobile-docs-nav" class="d-flex-block d-lg-none">
|
||||
<div class="d-flex flex-column d-lg-none p-0 m-0 justify-content-start align-items-center">
|
||||
<button purpose="docs-nav-button" class="btn btn-block d-flex align-items-center docs-nav-button" type="button" @click="toggleDocsNav">
|
||||
<span class="pr-2 m-0">Docs</span>
|
||||
<img style="width: 6px; height: 9px;" alt="right chevron" src="/images/chevron-right-6x9@2x.png"/>
|
||||
<span class="font-weight-bold px-2 m-0">{{thisPage.title}}</span>
|
||||
<img style="width: 6px; height: 9px;" class="ml-auto" alt="right chevron" src="/images/chevron-right-6x9@2x.png" v-if="!showDocsNav"/>
|
||||
<img style="width: 9px; height: 6px;" class="ml-auto" alt="down chevron" src="/images/chevron-down-9x6@2x.png" v-else/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="border-bottom" v-if="!showDocsNav"></div>
|
||||
<div class="d-flex px-0 border-bottom mobile-docs-nav" v-if="showDocsNav">
|
||||
<div class="container-fluid px-0 pt-4">
|
||||
<ul class="px-0 mb-0">
|
||||
<li class="px-0 mb-2" v-for="page in findPagesByUrl()" :key="page.title">
|
||||
<a :href="page.url" class="font-weight-bold">
|
||||
{{page.title}}
|
||||
</a>
|
||||
<ul class="px-0 pt-3 mb-0" v-if="!_.isEmpty(findPagesByUrl(page.url))">
|
||||
<li class="px-0 mb-2" v-for="subpage in findPagesByUrl(page.url)">
|
||||
<a :href="subpage.url" :class="subpage.title === thisPage.title ? 'topic active' : 'topic'">
|
||||
{{subpage.title}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h1 purpose="page-title" class="d-flex d-lg-none py-4 m-0">{{thisPage.title}}</h1>
|
||||
|
||||
<div class="container-fluid d-flex flex-column flex-lg-row p-0 pt-lg-4 pb-lg-4 m-0">
|
||||
|
||||
<div purpose="left-sidebar" style="min-width: 190px; max-width: 210px;" class="d-none d-lg-flex flex-column text-left pl-0 pr-4 left-sidebar">
|
||||
<ul class="p-0 pb-2 m-0 left-nav">
|
||||
<li v-for="page in findPagesByUrl()" :key="page.title">
|
||||
<a :href="page.url" class="font-weight-bold pb-3">{{page.title}}</a>
|
||||
<div class="pt-2" v-if="isCurrentSection(page)">
|
||||
<ul class="p-0 mb-2">
|
||||
<li v-for="subpage in findPagesByUrl(page.url)" :key="subpage.title">
|
||||
<a :href="subpage.url" :class="subpage.title === thisPage.title ? 'topic active' : 'topic'">
|
||||
{{subpage.title}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="font-weight-bold py-3" target="_blank" href="https://github.com/fleetdm/fleet/releases">Releases</a>
|
||||
<a href="/support" class="btn btn-block btn-sm btn-primary">Support</a>
|
||||
</div>
|
||||
|
||||
<div purpose="right-sidebar" class="order-first order-lg-last p-0 pb-2 pb-lg-0 pr-lg-0 right-sidebar" v-if="!thisPage.title.includes('FAQ')">
|
||||
|
||||
<p class="font-weight-bold pb-2 m-0 mb-2" v-if="!_.isEmpty(subtopics)">On this page:</p>
|
||||
<div purpose="subtopics">
|
||||
<ul class="p-0 m-0">
|
||||
<!-- <li v-for="(subtopic, index) in subtopics" :class="pl-lg-2 pb-3 pb-1g-2 subtopic" :key="index">
|
||||
<a :class="getActiveSubtopicClass(currentLocation, subtopic.url)" :href="subtopic.url">{{subtopic.title}}</a>
|
||||
</li> -->
|
||||
<li v-for="(subtopic, index) in subtopics" class="pl-lg-3 pb-3 pb-lg-2 subtopic" :key="index">
|
||||
<a :href="subtopic.url">{{subtopic.title}}</a>
|
||||
</li>
|
||||
<li class="d-lg-none pl-lg-3 subtopic">
|
||||
<a href="/support">Help and feedback</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- <div v-if="!_.isEmpty(relatedTopics)">
|
||||
<h6 class="d-none d-lg-block font-weight-bold py-2">Related topics</h6>
|
||||
<ul class="d-none d-lg-block p-0">
|
||||
<li v-for="(relatedTopic, index) in relatedTopics" :key="index">{{relatedTopic}}</li>
|
||||
</ul>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
|
||||
<div purpose="content" id="body-content" class="d-flex flex-column p-0 px-lg-5 content" parasails-has-no-page-script>
|
||||
<%- partial(
|
||||
path.relative(
|
||||
path.dirname(__filename),
|
||||
path.resolve(
|
||||
sails.config.appPath,
|
||||
path.join(
|
||||
sails.config.builtStaticContent.compiledPagePartialsAppPath,
|
||||
thisPage.htmlId
|
||||
)
|
||||
)
|
||||
)
|
||||
) %>
|
||||
|
||||
<div class="d-none d-lg-block">
|
||||
<h3 class="pb-4 m-0">Is there something missing?</h3>
|
||||
<p>
|
||||
If you notice something we've missed or could be improved on, please follow <a href="https://github.com/fleetdm/fleet">this link</a> and submit a pull request to the Fleet repo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
|
||||
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
<div id="documentation" v-cloak>
|
||||
<div style="max-width: 948px;" class="container-fluid p-0 px-3 px-sm-4 py-5 mb-5 mx-auto">
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="pt-5">Fleet documentation</h1>
|
||||
<p class="mb-2">Welcome to the documentation for the Fleet osquery fleet manager.</p>
|
||||
<p class="mb-0"><strong>v4.0.1 </strong><a href="https://github.com/fleetdm/fleet/releases">changelog</a></p>
|
||||
<!-- TODO script to pull latest release version -->
|
||||
</div>
|
||||
|
||||
<div purpose="search" class="d-flex p-0 pt-4 mt-3">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend border-right-0">
|
||||
<span class="input-group-text bg-transparent border-right-0 pl-3 pr-2">
|
||||
<img style="height: 16px; width: auto;" class="search" alt="search" src="/images/icon-search-16x16@2x.png"></span>
|
||||
</div>
|
||||
<input class="form-control border-left-0 px-0" placeholder="Search the docs..." aria-label="Search the docs"
|
||||
v-model="inputTextValue" @keydown.self="delayInput(setSearchString, 400, 'defaultTimer')()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cta-cards">
|
||||
<div class="container-fluid d-flex flex-column flex-sm-row justify-content-sm-between p-0 pt-4 mt-3">
|
||||
<div class="container-fluid d-flex flex-column flex-md-row justify-content-center align-items-center py-3 m-0 mr-sm-1 cta-card" @click="clickCTA('get-started')">
|
||||
<img class="cta-image" alt="Install Fleet" src="/images/install-fleet-140x72@2x.png"/>
|
||||
<div class="text-center text-md-left cta-text">
|
||||
<p class="font-weight-bold p-0 pl-md-4 pt-2 pt-md-0 m-0">Install osquery and Fleet</p>
|
||||
<a class="p-0 pl-md-4 pt-2 pt-md-0 arrow" href="/get-started">
|
||||
Get started
|
||||
<img class="d-inline mb-1" style="height: 16px; width: auto;" alt="right arrow" src="/images/arrow-right-16x16@2x.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid d-flex flex-column flex-md-row justify-content-center align-items-center py-3 m-0 ml-sm-1 mt-3 mt-sm-0 cta-card" @click="clickCTA('support')">
|
||||
<img class="cta-image" alt="Fleet support" src="/images/fleet-support-140x72@2x.png"/>
|
||||
<div class="text-center text-md-left cta-text">
|
||||
<p class="font-weight-bold p-0 pl-md-4 pt-2 pt-md-0 m-0">Can't find what you need?</p>
|
||||
<a class="p-0 pl-md-4 pt-2 pt-md-0 arrow" href="/support">
|
||||
Support
|
||||
<img class="d-inline mb-1" style="height: 16px; width: auto;" alt="right arrow" src="/images/arrow-right-16x16@2x.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tree">
|
||||
<div class="container-fluid d-flex flex-column flex-sm-row justify-content-sm-between p-0">
|
||||
<div v-for="item in tree">
|
||||
<div style="max-width: 300px;" class="container-fluid justify-content-start align-items-center p-0 px-2 pt-4 m-0 mt-3">
|
||||
<h3 class="mb-4">{{item.title}}</h3>
|
||||
<ul style="list-style: none;" class="p-0 m-0">
|
||||
<li class="mb-2" v-for="child in item.children">
|
||||
<a :href="'/docs/' + _.kebabCase(item.title) + '/' + _.kebabCase(child)">{{child}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
<p>This paragraph, and the content above it, are just here for reference. The HTML generated from markdown is below.</p>
|
||||
|
||||
<%- partial('../../partials/built-from-markdown/handbook/README.ejs') %>
|
||||
<%- partial(path.relative(path.dirname(__filename), path.resolve(sails.config.appPath, path.join(sails.config.builtStaticContent.compiledPagePartialsAppPath, thisPage.htmlId)))) %>
|
||||
|
||||
</div>
|
||||
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
|
||||
|
||||
Reference in New Issue
Block a user