Path: blob/master/webpage/src/components/Configuration/index.tsx
1007 views
import React from 'react';1import Tabs from '@theme/Tabs';2import TabItem from '@theme/TabItem';3import CodeBlock from '@theme/CodeBlock';45interface ConfigOptionValue {6type?: string;7description?: string;8defaultValue?: string;9}1011interface ConfigOption extends ConfigOptionValue {12key: string[];13}1415function configKey(key: string | string[], value: ConfigOptionValue | any): ConfigOption {16if (typeof key === 'string') {17key = key.split('.');18}19if (typeof value === 'object') {20return {21key,22type: value.type || getType(value.defaultValue),23description: value.description,24defaultValue: value.defaultValue,25}26} else {27return {28key,29type: getType(value),30defaultValue: value,31}32}33}3435function configKeys(optValues: Record<string, ConfigOptionValue | any>): ConfigOption[] {36let options: ConfigOption[] = [];37Object.entries(optValues).forEach(([key, value]) => {38options.push(configKey(key, value));39});40return options;41}4243function filterKeys(options: ConfigOption[], filter: string): ConfigOption[] {44return options.filter(option => {45const key = option.key.join('.');46return key.startsWith(filter)47});48}4950function defaultValue(value: ConfigOptionValue): string {51switch (value.type) {52case 'boolean':53return `${value.defaultValue || false}`;54case 'int':55case 'float':56case 'number':57return `${value.defaultValue || 0}`;58case 'duration':59case 'string':60return `${value.defaultValue ? `"${value.defaultValue}"` : '<string>'}`;61case 'strings':62return '<comma-separated list of strings>';63case 'object':64return '<json encoded object>';65case 'array':66return '<json encoded array>';67default:68return value.type ? `<${value.type}>` : '';69}70}7172function getType(value: any): string {73if (Array.isArray(value)) {74return 'array';75}76return typeof value;77}7879export function EnvironmentVariables({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) {80if (typeof comments === 'undefined') {81comments = true;82}8384let code = '';85options.forEach(option => {86const description = option.description ? option.description : '';87const type = option.type ? ` (${option.type})` : '';88if (comments && description) {89code += `# ${description}${type}\n`;90}91code += `NEKO_${option.key.join('_').toUpperCase()}=${defaultValue(option)}\n`;92});9394return (95<CodeBlock language="shell" {...props}>96{code}97</CodeBlock>98);99}100101export function CommandLineArguments({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) {102if (typeof comments === 'undefined') {103comments = true;104}105106let code = '';107options.forEach(option => {108const description = option.description ? option.description : '';109const type = option.type ? ` (${option.type})` : '';110if (comments && description) {111code += `# ${description}${type}\n`;112}113code += `--${option.key.join('.')} ${defaultValue(option)}\n`;114});115116return (117<CodeBlock language="shell" {...props}>118{code}119</CodeBlock>120);121}122123export function YamlFileContent({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) {124if (typeof comments === 'undefined') {125comments = true;126}127128const final = Symbol('final');129130const buildYaml = (obj: Record<string, any>, prefix = '') => {131let code = '';132Object.entries(obj).forEach(([key, option]) => {133if (typeof option === 'object' && !Array.isArray(option) && !option[final]) {134code += prefix+`${key}:\n`;135code += buildYaml(option, prefix + ' ');136} else {137const description = option.description ? option.description : '';138const type = option.type ? ` (${option.type})` : '';139if (comments && description) {140code += `${prefix}# ${description}${type}\n`;141}142let value: string;143if (option.type === 'strings') {144value = option.defaultValue ? `[ "${option.defaultValue}" ]` : '[ <string> ]';145} else if (option.type === 'object') {146value = "{}"147} else if (option.type === 'array') {148value = "[]"149} else {150value = defaultValue(option);151}152code += `${prefix}${key}: ${value}\n`;153}154});155return code;156};157158const yamlCode = buildYaml(options.reduce((acc, option) => {159const keys = option.key;160let current = acc;161keys.forEach((key, index) => {162if (!current[key]) {163current[key] = index === keys.length - 1 ? option : {};164}165current = current[key];166});167current[final] = true;168return acc;169}, {}));170171return (172<CodeBlock language="yaml" {...props}>173{yamlCode}174</CodeBlock>175);176}177178type ConfigurationTabProps = {179options?: ConfigOption[] | Record<string, ConfigOptionValue | any>;180heading?: boolean;181comments?: boolean;182filter?: string | string[] | Record<string, ConfigOptionValue | any>;183};184185export function ConfigurationTab({ options, heading, comments, filter, ...props }: ConfigurationTabProps) {186var configOptions: ConfigOption[] = [];187if (Array.isArray(options)) {188configOptions = options;189} else {190configOptions = configKeys(options)191}192if (typeof comments === 'undefined') {193comments = true;194}195if (typeof heading === 'undefined') {196heading = false;197}198199if (Array.isArray(filter)) {200let filteredOptions: ConfigOption[] = [];201for (const f of filter) {202filteredOptions = [ ...filteredOptions, ...filterKeys(configOptions, f) ];203}204configOptions = filteredOptions;205} else if (typeof filter === 'string') {206configOptions = filterKeys(configOptions, filter);207} else if (typeof filter === 'object') {208let filteredOptions: ConfigOption[] = [];209for (const k in filter) {210let filtered = configOptions.find(option => {211return option.key.join('.') === k;212});213let replaced = configKey(k, filter[k]);214filteredOptions = [ ...filteredOptions, { ...filtered, ...replaced } ];215}216configOptions = filteredOptions;217}218219return (220<Tabs groupId="configuration" defaultValue="yaml" values={[221{ label: 'YAML Configuration File', value: 'yaml' },222{ label: 'Environment Variables', value: 'env' },223{ label: 'Command Line Arguments', value: 'args' },224]} {...props}>225<TabItem value="env" label="Environment Variables">226{heading && (227<p>You can set the following environment variables in your <code>docker-compose.yaml</code> file or in your shell environment.</p>228)}229{EnvironmentVariables({ options: configOptions, comments })}230</TabItem>231<TabItem value="args" label="Command Line Arguments">232{heading && (233<p>You can list the following command line arguments using <code>neko serve --help</code>.</p>234)}235{CommandLineArguments({ options: configOptions, comments })}236</TabItem>237<TabItem value="yaml" label="YAML Configuration File">238{heading && (239<p>You can create a <code>/etc/neko/neko.yaml</code> file with the following configuration options.</p>240)}241{YamlFileContent({ options: configOptions, comments })}242</TabItem>243</Tabs>244);245}246247248