Skip to content

Commit

Permalink
Enhance install UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierstoval committed Nov 18, 2024
1 parent 8302f4d commit ebf89fc
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 104 deletions.
18 changes: 9 additions & 9 deletions install/install.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,19 +334,19 @@ public function __construct($dbh)
if ($success) {
echo "<p>" . __('Initializing database tables and default data...') . "</p>";

$alert_name = 'glpi_install_messages_container';
ob_start();
echo \sprintf('<p>%s</p>', __('Progress:'));

echo '<div id="glpi_install_messages_container"></div>';

echo '<div id="glpi_install_success" class="container mt-4">';
$next_form();
$next = ob_get_clean();
echo '</div>';

$prev_form($host, $user, $password);

echo \sprintf('<div id="%s"></div>', $alert_name);
echo \sprintf(
'<script defer>startDatabaseInstall("%s", "%s");</script>',
$alert_name,
str_replace(["\n", '"'], ['', '\\"'], $next),
'<script defer>startDatabaseInstall();</script>',
);

$prev_form($host, $user, $password);
} else { // can't create config_db file
echo "<p>" . __s('Impossible to write the database setup file') . "</p>";
$prev_form($host, $user, $password);
Expand Down
176 changes: 92 additions & 84 deletions js/glpi_install.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,111 +29,119 @@
*
* ---------------------------------------------------------------------
*/

let request_running = false;

function startDatabaseInstall(message_element_id, success_html)
{
const message_element = document.getElementById(message_element_id);
if (!message_element) {
const alert = document.createElement('p');
alert.innerText = 'Could not load HtmlElement to append messages to.';
document.body.appendChild(alert);
throw new Error(alert.innerText);
(() => {
let request_running = false;

function updateProgress(progress_element, value, max) {
// Trick for visual aid to understand it's not yet finished.
// Values "100" are used when it's *really* finished
if (max !== 100 && value !== 100 && value && max === value) {
value = (max * 0.98).toFixed(0);
}

if (value) {
progress_element.value = value;
} else {
progress_element.removeAttribute('value');
}

if (max) {
progress_element.max = max;
} else {
progress_element.removeAttribute('max');
}
}

const single_message_element = document.createElement('p');
const msg_list_element = document.createElement('div');
message_element.appendChild(msg_list_element);
msg_list_element.appendChild(single_message_element);

function message(text) {
function message(msg_list_element, text) {
const alert = document.createElement('p');
alert.innerHTML = text;
msg_list_element.appendChild(alert);
}
function queries_message(amount) {
single_message_element.innerHTML = `Process: ${amount}`;
}

request_running = true;

setTimeout(() => {
checkProgress(queries_message);
}, 1500);


fetch("/install/database_setup/start_db_inserts", {
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
})
.then((res) => res.text())
.then((text) => {
if (text && text.trim().length) {
message(`Error:\n${text}`);
} else {
message(success_html);
queries_message('✅');
}
})
.finally(() => request_running = false);
}
function startDatabaseInstall()
{
const message_element_id = 'glpi_install_messages_container';
const success_element_id = 'glpi_install_success';

let previous_count = 0;
let previous_state_commutator = 1;
const messages_container = document.getElementById(message_element_id);
const success_element = document.getElementById(success_element_id);

function checkProgress(message_fn)
{
if (!request_running) {
return;
}
const progress_container_element = document.createElement('p');
const progress_element = document.createElement('progress');
progress_container_element.appendChild(progress_element);
const message_element = document.createElement('div');

success_element.querySelector('button').setAttribute('disabled', true);

messages_container.appendChild(message_element);
messages_container.appendChild(progress_container_element);

request_running = true;

setTimeout(() => {
setTimeout(() => {
checkProgress(message_element, progress_element);
}, 1500);

fetch("/install/database_setup/check_progress", {
fetch("/install/database_setup/start_db_inserts", {
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
})
.then((res) => {
if (res.status === 404) {
// Progress not found, let's continue when necessary.
return request_running ? checkProgress(message_fn) : null;
.then((res) => res.text())
.then((text) => {
if (text && text.trim().length) {
message(message_element, `Error:\n${text}`);
} else {
updateProgress(progress_element, 100, 100);
success_element.querySelector('button').removeAttribute('disabled');
}
})
.finally(() => {
request_running = false;
});
}

if (res.status >= 300) {
throw new Error('Invalid response from progress check.');
}
function checkProgress(message_element, progress_element)
{
if (!request_running) {
return;
}

setTimeout(() => {

return res.json();
fetch("/install/database_setup/check_progress", {
method: 'POST',
})
.then((json) => {
if (!request_running) {
return;
}
.then((res) => {
if (res.status === 404) {
// Progress not found, let's continue when necessary.
return request_running ? checkProgress(message_element, progress_element) : null;
}

if (json && json.current) {
message_fn("Data received:");
let msg = json.current.toString();
if (res.status >= 300) {
throw new Error('Invalid response from progress check.');
}

msg += (new Array(previous_state_commutator)).fill('.').join('');
previous_state_commutator ++;
if (previous_state_commutator >= 4) {
previous_state_commutator = 1;
return res.json();
})
.then((json) => {
if (!request_running) {
return;
}

previous_count = json.current;
if (json && json.current) {
updateProgress(progress_element, json.current, json.max);

message_fn(msg);
return checkProgress(message_element, progress_element);
} else if (json) {
message(message_element, `Error:\n${json}`);
}
})
.catch((err) => message(message_element, err.message || err.toString()));

return checkProgress(message_fn);
} else if (json) {
message_fn(`Error:\n${json}`);
}
})
.catch((err) => {
return message_fn(err.message || err.toString());
});
}, 500);
}

}, 500);
}
window.startDatabaseInstall = startDatabaseInstall;
})();
3 changes: 2 additions & 1 deletion src/Glpi/Controller/Install/InstallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ public function start_inserts(): Response

return new StreamedResponse(function () use ($progressChecker) {
try {
$progressCallback = static function () use ($progressChecker) {
$progressCallback = static function (?int $current = null, ?int $max = null) use ($progressChecker) {
$progress = $progressChecker->getCurrentProgress(self::STORED_PROGRESS_KEY);
$progress->current++;
$progress->max = (int) $max;
$progressChecker->save($progress);
};
Toolbox::createSchema($_SESSION["glpilanguage"], null, $progressCallback);
Expand Down
2 changes: 1 addition & 1 deletion src/Glpi/Progress/SessionProgress.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
final class SessionProgress implements \JsonSerializable
{
public readonly string $key;
public readonly int $max;
public readonly \DateTimeImmutable $startDate;
public int $current = 0;
public int $max;
public string|int|float|bool|null $data;

public function __construct(string $key, int $max)
Expand Down
23 changes: 14 additions & 9 deletions src/Toolbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -2089,23 +2089,28 @@ public static function createSchema($lang = 'en_GB', ?DBmysql $database = null,
/** @var \DBmysql $DB */
$DB = $database;

$queries = $DB->getQueriesFromFile(sprintf('%s/install/mysql/glpi-empty.sql', GLPI_ROOT));
$structure_queries = $DB->getQueriesFromFile(sprintf('%s/install/mysql/glpi-empty.sql', GLPI_ROOT));

foreach ($queries as $query) {
//dataset
Session::loadLanguage($lang, false); // Load default language locales to translate empty data
$tables = require_once(__DIR__ . '/../install/empty_data.php');
Session::loadLanguage('', false); // Load back session language

$number_of_queries = \count($structure_queries);
foreach ($tables as $data) {
$number_of_queries += \count($data);
}

foreach ($structure_queries as $query) {
if ($progressCallback) {
$progressCallback();
$progressCallback(null, $number_of_queries);
}
if (!$query) {
continue;
}
$DB->doQuery($query);
}

//dataset
Session::loadLanguage($lang, false); // Load default language locales to translate empty data
$tables = require_once(__DIR__ . '/../install/empty_data.php');
Session::loadLanguage('', false); // Load back session language

foreach ($tables as $table => $data) {
$reference = array_replace(
$data[0],
Expand All @@ -2120,7 +2125,7 @@ public static function createSchema($lang = 'en_GB', ?DBmysql $database = null,
$types = str_repeat('s', count($data[0]));
foreach ($data as $row) {
if ($progressCallback) {
$progressCallback();
$progressCallback(null, $number_of_queries);
}
$res = $stmt->bind_param($types, ...array_values($row));
if (false === $res) {
Expand Down

0 comments on commit ebf89fc

Please sign in to comment.