implemented agent deploy wizard

This commit is contained in:
alejandro.campos@artica.es 2023-04-19 19:21:38 +02:00
parent a0426757b5
commit 9553c42496
8 changed files with 1328 additions and 10 deletions

Binary file not shown.

View File

@ -0,0 +1,71 @@
<?php
/**
* Credentials management view.
*
* @category Credentials management
* @package Pandora FMS
* @subpackage Opensource
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
require_once $config['homedir'].'/include/class/AgentDeployWizard.class.php';
$ajaxPage = 'godmode/agentes/agent_deploy';
// Control call flow.
try {
// User access and validation is being processed on class constructor.
$adw = new AgentDeployWizard($ajaxPage);
} catch (Exception $e) {
if (is_ajax()) {
echo json_encode(['error' => '[AgentDeployWizard]'.$e->getMessage() ]);
exit;
} else {
echo '[AgentDeployWizard]'.$e->getMessage();
}
// Stop this execution, but continue 'globally'.
return;
}
// AJAX controller.
if (is_ajax()) {
$method = get_parameter('method');
if (method_exists($adw, $method) === true) {
if ($adw->ajaxMethod($method) === true) {
$adw->{$method}();
} else {
$adw->error('Unavailable method.');
}
} else {
$adw->error('Method not found. ['.$method.']');
}
// Stop any execution.
exit;
} else {
// Run.
$adw->run();
}

View File

@ -419,6 +419,9 @@ ui_toggle(
'filter-datatable-main box-flat white_table_graph fixed_filter_bar'
);
require_once 'godmode/agentes/agent_deploy.php';
// Data table.
$selected = true;
$selectNameUp = false;
@ -1025,23 +1028,35 @@ if ($agents !== false) {
if ((bool) check_acl($config['id_user'], 0, 'AW') === true) {
// Create agent button.
echo '<form method="post" action="index.php?sec=gagente&amp;sec2=godmode/agentes/configurar_agente">';
echo '<form id="create-agent" method="post" action="index.php?sec=gagente&amp;sec2=godmode/agentes/configurar_agente"></form>';
$buttons = html_print_button(
__('Create agent'),
'crt-2',
false,
'',
[
'icon' => 'next',
'onClick' => "document.getElementById('create-agent').submit();",
],
true
).html_print_button(
__('Deploy agent'),
'modal_deploy_agent',
false,
'',
[],
true
);
html_print_action_buttons(
html_print_submit_button(
__('Create agent'),
'crt-2',
false,
[ 'icon' => 'next' ],
true
),
$buttons,
[
'type' => 'data_table',
'class' => 'fixed_action_buttons',
'right_content' => $tablePagination,
]
);
echo '</form>';
}
?>

View File

@ -0,0 +1,809 @@
<?php
/**
* Agent deploy wizard
*
* @category Class
* @package Pandora FMS
* @subpackage Agent deploy wizard
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2022 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
global $config;
/**
* Provides functionality for agent deploy wizard.
*/
class AgentDeployWizard
{
/**
* Url of controller.
*
* @var string
*/
public $ajaxController;
/**
* References datatables object identifier.
*
* @var string
*/
public $tableId;
/**
* Allowed methods to be called using AJAX request.
*
* @var array
*/
public $AJAXMethods = [
'loadModal',
];
/**
* Checks if target method is available to be called using AJAX.
*
* @param string $method Target method.
*
* @return boolean True allowed, false not.
*/
public function ajaxMethod($method)
{
return in_array($method, $this->AJAXMethods);
}
/**
* Generates a JSON error.
*
* @param string $msg Error message.
*
* @return void
*/
public function error($msg)
{
echo json_encode(
['error' => $msg]
);
}
/**
* Minor function to dump json message as ajax response.
*
* @param string $type Type: result || error.
* @param string $msg Message.
* @param boolean $delete Deletion messages.
*
* @return void
*/
private function ajaxMsg($type, $msg, $delete=false)
{
if ($type === 'error') {
$msg_title = ($delete === true) ? 'Failed while removing' : 'Failed while saving';
} else {
$msg_title = ($delete === true) ? 'Successfully deleted' : 'Successfully saved into keystore';
}
echo json_encode(
[ $type => __($msg_title).':<br>'.$msg ]
);
exit;
}
/**
* Initializes object and validates user access.
*
* @param string $ajax_controller Path of ajaxController, is the 'page'
* variable sent in ajax calls.
*
* @return object
*/
public function __construct($ajax_controller)
{
global $config;
// Check access.
check_login();
if ((bool) check_acl($config['id_user'], 0, 'AR') === false) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access agent deploy wizard'
);
if (is_ajax()) {
echo json_encode(['error' => 'noaccess']);
} else {
include 'general/noaccess.php';
}
exit;
}
$this->ajaxController = $ajax_controller;
return $this;
}
/**
* Prints inputs for modal "Deploy agents".
*
* @return void
*/
public function loadModal()
{
ob_start();
echo '<div id="wizard-modal-content">';
echo $this->getModalContent();
echo '</div>';
echo ob_get_clean();
}
/**
* Run AgentDeployWizard.
*
* @return void
*/
public function run()
{
global $config;
if (check_acl($config['id_user'], 0, 'AR') === false) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access agent deploy.'
);
include 'general/noaccess.php';
return;
}
ui_require_css_file('agent_deploy_wizard');
// Auxiliar div for agent deploy modal.
echo '<div id="agent_deploy_modal" class="invisible"></div>';
echo $this->loadJS();
}
/**
* Generates content of modal.
*
* @param array $values Values or null.
*
* @return string Inputs.
*/
public function getModalContent()
{
global $config;
ob_start();
$inputs = [];
// Container div for stepper.
$stepper_container = html_print_div(
[
'id' => 'stepper_container',
'class' => 'stepper',
],
true
);
html_print_div(
[
'id' => 'modal_header',
'class' => 'margin-bottom-10',
'content' => $stepper_container,
]
);
// Deploy configuration.
$tableConfiguration = new stdClass();
$tableConfiguration->class = 'filter-table-adv w100p';
$tableConfiguration->data = [];
$tableConfiguration->style = [];
$tableConfiguration->cellclass = [];
$tableConfiguration->colspan = [];
$tableConfiguration->rowclass['os'] = 'margin-bottom-5';
$tableConfiguration->rowstyle['block2'] = 'display: flex; justify-content: space-between;';
$tableConfiguration->rowspan = [];
$windows_label_img = html_print_image(
'/images/windows@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$windows_label = html_print_div(
[
'style' => 'display: flex;align-items: center; margin-top: 5px;margin-bottom: 5px;',
'content' => $windows_label_img.'Windows',
],
true
);
$linux_label_img = html_print_image(
'/images/linux@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$linux_label = html_print_div(
[
'style' => 'display: flex;align-items: center; margin-top: 5px;margin-bottom: 5px;',
'content' => $linux_label_img.'Unix / Linux',
],
true
);
$mac_label_img = html_print_image(
'/images/apple@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$mac_label = html_print_div(
[
'style' => 'display: flex;align-items: center; margin-top: 5px;margin-bottom: 5px;',
'content' => $mac_label_img.'Mac OS',
],
true
);
// Operating System switch buttons.
$switchButtons = [];
$switchButtons[] = html_print_radio_button_extended(
'os',
0,
$windows_label,
0,
false,
'',
'',
true
);
$switchButtons[] = html_print_radio_button_extended(
'os',
1,
$linux_label,
0,
false,
'',
'',
true
);
$switchButtons[] = html_print_radio_button_extended(
'os',
2,
$mac_label,
0,
false,
'',
'',
true
);
$sub_tip = '<span class="input_sub_placeholder_normal">'.__('Please note that all OS must be 64-bit based architecture').'</span>';
$tableConfiguration->data['os'][] = html_print_label_input_block(
__('Choose your OS'),
html_print_div(
[
'id' => 'os_selector',
'class' => 'switch_radio_button',
'content' => implode('', $switchButtons),
],
true
).$sub_tip
);
/*$stepper_container = html_print_div(
[
'class' => 'switch_radio_button',
'content'
],
true
);*/
$server_add_help_tip = ui_print_help_tip(
__('Use your %s Data Server IP address here. It must be possible to establish a connection from the agent to port 41121/tcp of this address.', get_product_name()),
true
);
$tableConfiguration->data['block2'][0] = html_print_label_input_block(
__('Server address').$server_add_help_tip,
html_print_input_text(
'server_addr',
$_SERVER['SERVER_ADDR'],
'',
16,
100,
true,
false,
true,
'',
'w260px'
)
);
$tableConfiguration->data['block2'][1] = html_print_label_input_block(
__('Group'),
html_print_select_groups(
false,
'AR',
false,
'group',
$group,
'',
'',
0,
true,
false,
true,
'w260px',
false,
'',
'',
false,
'id_grupo',
false,
false,
false,
'260px',
false,
true,
)
);
echo '<div id="config_page">';
echo '<form id="form_generate_installer" method="post" action="index.php?sec=gagente&amp;sec2=godmode/agentes/agent_deploy">';
if ($config['language'] === 'es') {
$instructions_url = 'https://pandorafms.com/manual/es/documentation/02_installation/05_configuration_agents';
} else {
$instructions_url = 'https://pandorafms.com/manual/en/documentation/02_installation/05_configuration_agents';
}
$instructions_link = '<a class="green-link" style="font-size: 15px;" href="'.$instructions_url.'" target="_blank">'.__('view the following instructions').'</a>';
$more_info_link = html_print_div(
[
'id' => 'config_form_more_info',
'class' => 'warn-box',
'content' => __('If you need more information regarding agents').', '.$instructions_link,
],
true
);
$table_config = html_print_div(
[
'style' => 'flex: 1;',
'content' => html_print_table($tableConfiguration, true),
],
true
);
html_print_div(
[
'id' => 'config_form',
'class' => 'white_table_flex agent_details_col modal-content',
'content' => $table_config.$more_info_link,
]
);
html_print_div(
['id' => 'footer_separator']
);
html_print_div(
[
'id' => 'config_buttonset',
'class' => 'ui-dialog-buttonset',
'content' => html_print_submit_button(
__('Generate installer'),
'generate_installer',
false,
[],
true,
)
]
);
echo '</form>';
echo '</div>';
echo '<div id="installer_page">';
echo '<div id="installer_data" class="white_table_flex agent_details_col modal-content">';
// Start of Unix / Linux installer section.
$title = html_print_image(
'/images/linux@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$title .= '<span class="header_title">'.__('Linux agent').'</span>';
$content = html_print_div(
[
'class' => 'installer-title',
'content' => $title,
],
true
);
$content .= '<span>'.__('Run the following command in the shell of your Linux server to perform the installation of the generated agent:').'</span>';
$content .= html_print_code_picker('run_command_box_linux', '', 'installer-code-fragment', false, true);
$content .= '<span>'.__('Once installed, you must run the following command to start the software agent service:').'</span>';
$content .= html_print_code_picker('start_service_box_linux', '', 'installer-code-fragment', true, true);
if ($config['language'] === 'es') {
$linux_dependencies_url = 'https://pandorafms.com/manual/es/documentation/02_installation/01_installing#requisitos_para_el_agente';
} else {
$linux_dependencies_url = 'https://pandorafms.com/manual/en/documentation/02_installation/01_installing#agent_requirements';
}
$linux_dependencies_link = '<a class="green-link" href="'.$linux_dependencies_url.'" target="_blank">'.__('dependencies').'</a>';
$content .= '<span>'.__('For the correct operation of the Linux agent it is necessary that the server has installed the following ').$linux_dependencies_link.'</span>';
html_print_div(
[
'id' => 'linux_installer',
'class' => 'white_table_flex agent_details_col',
'style' => 'margin-bottom: 20px',
'content' => $content,
]
);
// Start of Windows installer section.
$title = html_print_image(
'/images/windows@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$title .= '<span class="header_title">'.__('Windows agent').'</span>';
$content = html_print_div(
[
'class' => 'installer-title',
'content' => $title,
],
true
);
$content .= '<span>'.__('Run the following command in cmd.exe as an administrator:').'</span>';
$content .= html_print_code_picker('run_command_box_windows', '', 'installer-code-fragment', false, true);
$content .= '<span>'.__('Once installed, you must run the following command to start the software agent service:').'</span>';
$content .= html_print_code_picker('start_service_box_windows', '', 'installer-code-fragment', true, true);
html_print_div(
[
'id' => 'win_installer',
'class' => 'white_table_flex agent_details_col',
'style' => 'margin-bottom: 20px',
'content' => $content,
]
);
// Start of MacOS installer section.
$title = html_print_image(
'/images/apple@os.svg',
true,
['class' => 'installer-title-icon main_menu_icon']
);
$title .= '<span class="header_title">'.__('Mac agent').'</span>';
$content = html_print_div(
[
'class' => 'installer-title',
'content' => $title,
],
true
);
$mac_warn_box = html_print_div(
[
'id' => 'warn_box_mac',
'class' => 'warn-box',
'content' => __('To complete the installation process, please perform a manual installation and configure the server address to XXX and specify the group as XXX. Thank you for your cooperation.'),
],
true
);
html_print_div(
[
'id' => 'mac_installer',
'class' => 'white_table_flex agent_details_col',
'style' => 'margin-bottom: 20px',
'content' => $content.$mac_warn_box,
]
);
// Footer.
html_print_div(
[
'id' => 'footer_separator',
]
);
echo '</div>';
html_print_div(
[
'id' => 'installer_buttonset',
'class' => 'flex-row',
'style' => '',
'content' => html_print_button(
__('Change configuration'),
'change_configuration',
false,
'',
['class' => 'secondary'],
true,
).html_print_button(
__('Done'),
'done',
false,
'',
['style' => 'min-width: 0;'],
true
)
]
);
echo '</div>';
return ob_get_clean();
}
/**
* Loads JS content.
*
* @return string JS content.
*/
public function loadJS()
{
ob_start();
ui_require_javascript_file('stepper', 'include/javascript/', true);
// Javascript content.
?>
<script type="text/javascript">
/**
* Cleanup current dom entries.
*/
function cleanupDOM() {
$('#div-identifier').empty();
$('#div-product').empty();
$('#div-username').empty();
$('#div-password').empty();
$('#div-extra_1').empty();
$('#div-extra_2').empty();
}
/**
* Process ajax responses and shows a dialog with results.
*/
function showMsg(data) {
var title = "<?php echo __('Success'); ?>";
var text = '';
var failed = 0;
try {
data = JSON.parse(data);
text = data['result'];
} catch (err) {
title = "<?php echo __('Failed'); ?>";
text = err.message;
failed = 1;
}
if (!failed && data['error'] != undefined) {
title = "<?php echo __('Failed'); ?>";
text = data['error'];
failed = 1;
}
if (data['report'] != undefined) {
data['report'].forEach(function (item){
text += '<br>'+item;
});
}
$('#msg').empty();
$('#msg').html(text);
$('#msg').dialog({
width: 450,
position: {
my: 'center',
at: 'center',
of: window,
collision: 'fit'
},
title: title,
buttons: [
{
class: "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next",
text: 'OK',
click: function(e) {
if (!failed) {
$(".ui-dialog-content").dialog("close");
$('.info').hide();
cleanupDOM();
dt_keystore.draw(false);
} else {
$(this).dialog('close');
}
}
}
]
});
}
function generate_installer() {
$('#config_page').hide();
$('#installer_page').show();
var os_val = $('input[name="os"]:checked').val();
var module_definition_val = $('input[name="module_definition"]:checked').val();
var server_addr_val = $('input[name="server_addr"]').val();
var group_val = $('[name="group"] option:selected').text();
console.log(group_val);
var win_installer_command = `curl -k "https://firefly.artica.es/pandorafms/latest/Windows/Pandora%20FMS%20Windows%20Agent%20v7.0NG.x86_64.exe" -o PandoraFMS_Windows_Agent_7.0NG.x86_64.exe ; ./PandoraFMS_Windows_Agent_7.0NG.x86_64.exe /S --ip ${server_addr_val} --group ${group_val} --remote_config 1`;
var linux_installer_command = `export PANDORA_SERVER_IP='${server_addr_val}' && \\ \nexport PANDORA_REMOTE_CONFIG=1 && \\ \nexport PANDORA_GROUP='${group_val}' && \\ \ncurl -Ls https://pfms.me/agent-deploy | bash`;
var mac_installer_text = `To complete the installation process, please perform a manual installation and configure the server IP to ${server_addr_val} and specify the group as ${group_val}. Thank you for your cooperation`;
var linux_service_start = "/etc/init.d/pandora_agent_daemon start";
var win_service_start = "NET START PandoraFMSAgent";
switch (os_val) {
case '0':
$('#run_command_box_windows').text(win_installer_command);
$('#start_service_box_windows').text(win_service_start);
$('#linux_installer').hide();
$('#mac_installer').hide();
$('#win_installer').show();
break;
case '1':
$('#run_command_box_linux').text(linux_installer_command);
$('#start_service_box_linux').text(linux_service_start);
$('#win_installer').hide();
$('#mac_installer').hide();
$('#linux_installer').show();
break;
case '2':
$('#warn_box_mac').text(mac_installer_text);
$('#win_installer').hide();
$('#linux_installer').hide();
$('#mac_installer').show();
break;
}
}
function display_deploy_configuration() {
$('#installer_page').hide();
$('#config_page').show();
}
/**
* Loads modal from AJAX.
*/
function show_agent_install_modal() {
var title = '<?php echo __('Deploy agent'); ?>';
var method = '';
load_modal({
target: $('#agent_deploy_modal'),
form: 'modal_form',
url: '<?php echo ui_get_full_url('ajax.php', false, false, false); ?>',
ajax_callback: showMsg,
cleanup: cleanupDOM,
modal: {
title: title,
},
extradata: [
{
name: 'identifier',
}
],
onload: function() {
display_deploy_configuration();
var stepper_step_names = [];
stepper_step_names.push('<?php echo __('Configuration'); ?>');
stepper_step_names.push('<?php echo __('Installer'); ?>');
var stepper_container = $('#stepper_container');
var stepper = new Stepper(stepper_container, stepper_step_names);
/*
{
1: 'Step One',
2: 'Step Two',
3: 'Step 3',
}
*/
stepper.render();
// Initial step: 1.
stepper.selectStep(1);
$("#form_generate_installer").on('submit', function(e) {
// We only want the form to be submitted for field validation.
e.preventDefault();
generate_installer();
stepper.selectStep(2);
});
$("#button-change_configuration").on('click', function() {
display_deploy_configuration();
stepper.selectStep(1);
});
$("#button-done").on('click', function() {
$(".ui-dialog-content").dialog("close");
$('.info').hide();
cleanupDOM();
dt_keystore.draw(false);
});
},
onshow: {
page: '<?php echo $this->ajaxController; ?>',
method: 'loadModal'
},
onsubmit: {
page: '<?php echo $this->ajaxController; ?>',
method: method
}
});
}
$(document).ready(function() {
var page = 0;
$("#button-modal_deploy_agent").on('click', function() {
show_agent_install_modal();
});
});
</script>
<?php
// EOF Javascript content.
return ob_get_clean();
}
}

View File

@ -6923,4 +6923,39 @@ function html_print_go_top()
$output .= '</div>';
return $output;
}
}
/**
* Render a code picker fragment with default Pandora styles.
*
* @param string $id,
* @param string $content Content.
* @param string $classes Classes for code picker.
* @param boolean $single_line If true, code picker will be displayed as a single line of code.
* @param boolean $return Return output if set to true.
*
* @return string
*/
function html_print_code_picker(
string $id,
string $content='',
string $classes='',
bool $single_line=false,
bool $return=false
) {
$single_line_class = '';
if ($single_line === true) {
$single_line_class = 'single-line ';
}
$output = '<div class="code-fragment '.$single_line_class.$classes.'">';
$output .= '<pre style="margin: 0;"><code class="code-font" id="'.$id.'" style="display: block; white-space: pre-wrap;">'.$content.'</code></pre>';
$output .= '</div>';
if ($return === true) {
return $output;
} else {
echo $output;
}
}

View File

@ -0,0 +1,69 @@
function Stepper(container, steps) {
if (container instanceof jQuery) {
this.container = container[0];
} else {
this.container = container;
}
this.steps = [];
for (var i = 1; i <= steps.length; i++) {
var stepContainer = document.createElement("div");
stepContainer.className = "step-container";
var step = document.createElement("span");
step.className = "step";
step.textContent = i;
var text = document.createElement("div");
text.className = "step-text";
text.textContent = steps[i - 1];
stepContainer.appendChild(step);
stepContainer.appendChild(text);
this.steps.push(stepContainer);
}
}
Stepper.prototype.render = function() {
var separator = document.createElement("div");
separator.className = "step-separator";
var stepsContainer = document.createElement("div");
stepsContainer.className = "steps";
for (var i = 0; i < this.steps.length; i++) {
if (i > 0) {
stepsContainer.appendChild(separator.cloneNode());
}
stepsContainer.appendChild(this.steps[i]);
}
this.container.innerHTML = "";
this.container.appendChild(stepsContainer);
};
Stepper.prototype.selectStep = function(step) {
for (var i = 0; i < this.steps.length; i++) {
if (i < step - 1) {
this.steps[i].querySelector(".step").classList.add("visited");
this.steps[i].querySelector(".step-text").classList.remove("active");
var separators = this.container.querySelectorAll(".step-separator");
if (separators[i]) {
separators[i].classList.add("visited");
}
} else if (i === step - 1) {
this.steps[i].querySelector(".step").classList.add("active");
this.steps[i].querySelector(".step-text").classList.add("active");
this.steps[i].querySelector(".step").classList.remove("visited");
} else {
this.steps[i]
.querySelector(".step")
.classList.remove("visited", "active");
this.steps[i].querySelector(".step-text").classList.remove("active");
var separators = this.container.querySelectorAll(".step-separator");
if (separators[i - 1]) {
separators[i - 1].classList.remove("visited");
}
}
}
};

View File

@ -0,0 +1,85 @@
#agent_deploy_modal {
margin-bottom: 5px;
}
#footer_separator {
position: absolute;
bottom: 57px;
border-top: 1px solid #c1ccdc;
width: 100%;
left: 0px;
}
#stepper_container {
display: flex;
justify-content: center;
align-items: center;
}
#modal_header {
background-color: #f6f7fb;
border-radius: 10px;
width: 100%;
height: 76px;
/* padding: 10px; */
display: flex;
justify-content: center;
align-items: center;
}
#config_form_more_info {
margin-bottom: 5px !important;
}
#stepper_container {
width: 35%;
}
#table1-os-0 {
width: 100%;
}
#os_selector {
width: 100%;
height: 50px;
color: #333;
}
#os_selector > label {
width: 100%;
height: 30px;
}
.modal-content {
display: flex;
margin-bottom: 20px;
min-height: 400px;
flex-direction: column;
padding-left: 5px;
padding-right: 5px;
}
.installer-code-fragment {
margin-bottom: 15px;
margin-top: 5px;
}
.installer-title {
display: flex;
align-items: center;
margin-bottom: 10px;
margin-top: 10px;
}
.installer-title-icon {
margin-right: 9px;
}
.green-link {
color: #1d7873 !important;
text-decoration: none !important;
}
.green-link:hover {
color: #0d312f !important;
}

View File

@ -151,6 +151,14 @@
src: local("Nunito-Regular"), url(../../fonts/nunito.woff) format("woff");
}
@font-face {
font-family: "firacode-regular";
src: url("../fonts/FiraCode-Regular.woff") format("woff");
src: local("FiraCode-Regular"),
url(../../fonts/FiraCode-Regular.woff) format("woff");
font-weight: normal;
}
* {
font-size: 9pt;
line-height: 16pt;
@ -479,6 +487,11 @@ select:-internal-list-box {
max-width: 250px;
}
.w260px {
width: 260px;
max-width: 260px;
}
.w280px {
width: 280px;
max-width: 280px;
@ -1212,6 +1225,14 @@ p.center {
margin: 0 auto;
}
.margin-top-5 {
margin-top: 5px;
}
.margin-bottom-5 {
margin-bottom: 5px;
}
.margin-top-10 {
margin-top: 10px;
}
@ -11518,6 +11539,11 @@ p.trademark-copyright {
color: #8a96a6;
}
.input_sub_placeholder_normal {
font-size: 13px;
color: #8a96a6;
}
.input_sub_placeholder_warning {
color: #ffb900;
font-style: italic;
@ -11899,3 +11925,211 @@ td[id^="table_info_box"] a {
.break-word {
word-wrap: break-word;
}
.warn-box {
background: #fffbdf;
color: #454545;
font-size: 15px;
border-radius: 5px;
padding: 15px;
padding-left: 30px;
position: relative;
margin: 25px 0px;
}
.warn-box::before {
content: "|";
color: #dd9900;
position: absolute;
left: 4px;
top: 50%;
transform: translateY(-50%);
height: 77%;
background: #dd9900;
border-radius: 12px;
width: 4px;
}
.err-box {
background: #fbdada;
color: #454545;
font-size: 15px;
border-radius: 5px;
padding: 15px;
padding-left: 30px;
position: relative;
margin: 25px 0px;
}
.err-box::before {
content: "|";
color: red;
position: absolute;
left: 4px;
top: 50%;
transform: translateY(-50%);
height: 77%;
background: red;
border-radius: 12px;
width: 4px;
}
.signature {
color: #8a96a6;
font-size: 13px;
font-weight: 300;
margin-right: auto;
margin-left: 10px;
}
.link {
color: #82b92e;
text-decoration: none;
}
.signature a {
color: #82b92e;
text-decoration: none;
}
.steps {
display: flex;
align-items: center;
width: 100%;
}
.step {
font-size: 15px;
border: 2px solid #c0ccdc;
color: #999;
border-radius: 30px;
width: 30px;
height: 30px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
}
.step.active {
background-color: #0d312f !important;
color: #ffffff !important;
border-color: #0d312f !important;
}
.step.visited {
background-color: #1d7873 !important;
color: #ffffff !important;
border-color: #1d7873 !important;
}
.steps {
display: flex;
justify-content: space-between;
align-items: center;
}
.step-separator {
flex: 1;
height: calc(50% - 12px);
border: none;
border-top: 2px solid transparent;
border-image: repeating-linear-gradient(
to right,
#c0ccdc 0,
#c0ccdc 4px,
transparent 4px,
transparent 8px
)
1 0;
position: relative;
transform: translateY(-14px);
}
.step-separator.visited {
border-top: 2px solid #1d7873 !important;
border-image: none;
}
.step-separator:last-child {
display: none;
}
.step-container {
display: flex;
flex-direction: column;
align-items: center;
width: 30px;
}
.step-text {
font-size: 12px;
color: #333;
text-align: center;
margin-top: 5px;
}
.step-text.active {
font-weight: bold;
}
.code-fragment {
background-color: #1f2435;
color: #eaeaea;
overflow-y: scroll;
height: 100px;
padding: 10px;
font-family: "firacode-regular";
font-size: 14px;
padding-left: 25px;
padding-right: 25px;
border-radius: 6px;
}
.code-fragment.single-line {
height: 20px !important;
overflow-y: hidden !important;
}
.code-font {
font-family: "firacode-regular" !important;
}
/* Webkit-based browsers */
.code-fragment::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.code-fragment::-webkit-scrollbar-track {
background-color: transparent;
}
.code-fragment::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.25);
border-radius: 4px;
width: 6px;
height: 50px;
}
.code-fragment::-webkit-scrollbar-thumb:hover {
background-color: rgba(255, 255, 255, 0.25);
}
/* Firefox */
.code-fragment::-moz-scrollbar {
width: 6px;
height: 6px;
}
.code-fragment::-moz-scrollbar-track {
background-color: transparent;
}
.code-fragment::-moz-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.25);
border-radius: 4px;
width: 6px;
height: 50px;
}
.code-fragment::-moz-scrollbar-thumb:hover {
background-color: rgba(255, 255, 255, 0.25);
}