8.6 -> 8.7
diff --git a/lam/docs/manual-sources/images/configGeneral11.png b/lam/docs/manual-sources/images/configGeneral11.png
new file mode 100644
index 000000000..afa9732d6
Binary files /dev/null and b/lam/docs/manual-sources/images/configGeneral11.png differ
diff --git a/lam/help/help.inc b/lam/help/help.inc
index 95424d871..e1f80e89f 100644
--- a/lam/help/help.inc
+++ b/lam/help/help.inc
@@ -346,6 +346,9 @@ $helpArray = [
"293" => ["Headline" => _('Database type'),
"Text" => _('Please select the type of database to use for all configuration data. Please install PHP MySQL PDO extension for MySQL support.')
],
+ "294" => ["Headline" => _('Cron command'),
+ "Text" => _('Run this for global cleanup tasks. See manual for details.')
+ ],
// 300 - 399
// profile/PDF editor, file upload
"301" => ["Headline" => _("RDN identifier"),
diff --git a/lam/lib/baseModule.inc b/lam/lib/baseModule.inc
index e4c2b215d..2836d2bed 100644
--- a/lam/lib/baseModule.inc
+++ b/lam/lib/baseModule.inc
@@ -825,6 +825,46 @@ abstract class baseModule {
return $messages;
}
+ /**
+ * Returns a list of config options for LAM's main configuration.
+ *
+ * @param array $currentSettings current settings
+ * @return htmlElement[] config options
+ */
+ public function getGlobalConfigOptions(array $currentSettings): array {
+ return [];
+ }
+
+ /**
+ * Checks the global config options.
+ *
+ * @param string[] $messages info messages can be added here
+ * @param string[] $errors error messages can be added here
+ * @param array $options config options
+ */
+ public function checkGlobalConfigOptions(array &$options, array &$messages, array &$errors): void {
+ // to be implemented by modules if needed
+ }
+
+ /**
+ * Specifies if the module supports global cron job actions.
+ *
+ * @return bool supports cron
+ */
+ public function supportsGlobalCronJob(): bool {
+ return false;
+ }
+
+ /**
+ * Runs any global cron actions.
+ *
+ * @param bool $isDryRun dry-run active
+ * @throws LAMException error during execution
+ */
+ public function runGlobalCronActions(bool $isDryRun): void {
+ // needs to be implemented by submodule if needed
+ }
+
/**
* Returns a hashtable with all entries that may be printed out in the PDF.
*
diff --git a/lam/lib/config.inc b/lam/lib/config.inc
index 1363bceb8..aedde54f6 100644
--- a/lam/lib/config.inc
+++ b/lam/lib/config.inc
@@ -3145,6 +3145,9 @@ class LAMCfgMain {
/** database password */
public $configDatabasePassword = '';
+ /** database password */
+ private $moduleSettings = '';
+
/** list of data fields to save in config file */
private $settings = ["password", "default", "sessionTimeout", "hideLoginErrorDetails",
"logLevel", "logDestination", "allowedHosts", "passwordMinLength",
@@ -3158,7 +3161,7 @@ class LAMCfgMain {
'mailAttribute', 'mailBackupAttribute',
'configDatabaseType',
'configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser',
- 'configDatabasePassword'
+ 'configDatabasePassword', 'moduleSettings'
];
/** persistence settings are always stored on local file system */
@@ -3187,6 +3190,7 @@ class LAMCfgMain {
$this->logDestination = "SYSLOG";
$this->allowedHosts = "";
$this->allowedHostsSelfService = '';
+ $this->moduleSettings = '';
try {
$this->reload();
} catch (LAMException $e) {
@@ -3548,6 +3552,9 @@ class LAMCfgMain {
if (!in_array("configDatabasePassword", $saved)) {
array_push($file_array, "configDatabasePassword: " . $this->configDatabasePassword . "\n");
}
+ if (!in_array("moduleSettings", $saved)) {
+ array_push($file_array, "moduleSettings: " . $this->moduleSettings . "\n");
+ }
$file = @fopen($this->conffile, "w");
if ($file) {
@@ -3916,4 +3923,25 @@ class LAMCfgMain {
return self::MAIL_BACKUP_ATTRIBUTE_DEFAULT;
}
+ /**
+ * Returns a list of module settings.
+ *
+ * @return array module settings
+ */
+ public function getModuleSettings(): array {
+ if (empty($this->moduleSettings)) {
+ return [];
+ }
+ return json_decode(base64_decode($this->moduleSettings), true);
+ }
+
+ /**
+ * Sets the module settings.
+ *
+ * @param array $settings module settings
+ */
+ public function setModuleSettings(array $settings): void {
+ $this->moduleSettings = base64_encode(json_encode($settings));
+ }
+
}
diff --git a/lam/lib/cronGlobal.inc b/lam/lib/cronGlobal.inc
new file mode 100644
index 000000000..64af95bd6
--- /dev/null
+++ b/lam/lib/cronGlobal.inc
@@ -0,0 +1,69 @@
+supportsGlobalCronJob()) {
+ continue;
+ }
+ try {
+ if ($isDryRun) {
+ echo "Started actions for " . $module->get_alias() . "\n";
+ }
+ logNewMessage(LOG_NOTICE, 'Started actions for ' . $module->get_alias());
+ $module->runGlobalCronActions($isDryRun);
+ if ($isDryRun) {
+ echo "Finished actions for " . $module->get_alias() . "\n";
+ }
+ logNewMessage(LOG_NOTICE, 'Finished actions for ' . $module->get_alias());
+ }
+ catch (Exception $e) {
+ $errorsOccurred = true;
+ echo "Error in " . $module->get_alias() . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString() . "\n";
+ }
+}
+if ($errorsOccurred) {
+ echo "Problems occurred during cron execution\n";
+ die(1);
+}
diff --git a/lam/lib/cronGlobal.sh b/lam/lib/cronGlobal.sh
new file mode 100755
index 000000000..0e311015b
--- /dev/null
+++ b/lam/lib/cronGlobal.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+dir=`dirname $0`
+
+if [ -x /usr/bin/php ]; then
+ # delimiter must be added to support arguments starting with "--"
+ /usr/bin/php -f $dir/cronGlobal.inc delimiter $*
+ exit $?
+fi
+
+echo "No PHP executable found"
+
+exit 1
\ No newline at end of file
diff --git a/lam/lib/html.inc b/lam/lib/html.inc
index ecda94e25..9cbc2baed 100644
--- a/lam/lib/html.inc
+++ b/lam/lib/html.inc
@@ -407,6 +407,107 @@ class htmlTable extends htmlElement {
}
+/**
+ * Table component for client-side controlled data tables.
+ */
+class htmlDataTable extends htmlElement {
+
+ public const DATA_AJAX_URL = 'ajaxurl';
+ public const DATA_TOKEN_NAME = 'tokenname';
+ public const DATA_TOKEN_VALUE = 'tokenvalue';
+ public const DATA_ACTION = 'action';
+ public const DATA_OK_TEXT = 'oktext';
+
+ private string $id;
+ private int $height;
+ private array $columns;
+
+ /**
+ * Constructor
+ *
+ * @param string $id table ID
+ * @param htmlDataTableColumn[] $columns columns
+ * @param int $height table height
+ */
+ public function __construct(string $id, array $columns, int $height = 300) {
+ $this->id = htmlspecialchars($id);
+ $this->height = $height;
+ $this->columns = $columns;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ function generateHTML($module, $input, $values, $restricted, $scope) {
+ echo '';
+ echo '';
+ echo 'getDataAttributesAsString() . '>
';
+ $columnOptions = [];
+ foreach ($this->columns as $column) {
+ $headerFilter = $column->filterable ? ', headerFilter: "input"' : '';
+ $columnOptions[] = '{
+ title: "' . $column->label . '",
+ field: "' . $column->name . '",
+ formatter: "textarea"
+ ' . $headerFilter . '
+ }';
+ }
+ $columnsCode = implode(', ', $columnOptions);
+ echo '';
+ return [];
+ }
+
+}
+
+/**
+ * Column for data table.
+ */
+class htmlDataTableColumn {
+
+ public string $label;
+ public string $name;
+ public bool $filterable;
+
+ /**
+ * @param string $label
+ * @param string $name
+ * @param bool $filterable
+ */
+ public function __construct(string $label, string $name, bool $filterable = true) {
+ $this->label = htmlspecialchars($label);
+ $this->name = htmlspecialchars($name);
+ $this->filterable = $filterable;
+ }
+
+}
+
/**
* A standard input field.
*
diff --git a/lam/lib/modules.inc b/lam/lib/modules.inc
index b61b79391..598580d76 100644
--- a/lam/lib/modules.inc
+++ b/lam/lib/modules.inc
@@ -319,6 +319,25 @@ function getAvailableModules($scope, $mustSupportAdminInterface = false) {
return $return;
}
+/**
+ * Returns an array with all modules.
+ *
+ * @return baseModule[] list of modules
+ */
+function getAllModules(): array {
+ $dirname = substr(__FILE__, 0, strlen(__FILE__) - 12) . "/modules";
+ $dir = dir($dirname);
+ $return = [];
+ // get module names.
+ while ($entry = $dir->read()) {
+ if ((substr($entry, strlen($entry) - 4, 4) == '.inc') && is_file($dirname . '/'.$entry)) {
+ $entry = substr($entry, 0, strpos($entry, '.'));
+ $return[] = new $entry(null);
+ }
+ }
+ return $return;
+}
+
/**
* Returns the elements for the profile page.
*
diff --git a/lam/lib/persistence.inc b/lam/lib/persistence.inc
index d24cc37f3..721ea182e 100644
--- a/lam/lib/persistence.inc
+++ b/lam/lib/persistence.inc
@@ -18,7 +18,7 @@ use function LAM\PDF\getPDFStructures;
/*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
- Copyright (C) 2020 - 2022 Roland Gruber
+ Copyright (C) 2020 - 2024 Roland Gruber
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
@@ -400,6 +400,9 @@ class ConfigDataImporter {
if (isset($value['openRequests'])) {
$mainStep->addSubStep(new ImporterStep(_('Open requests'), 'requestAccess_openRequests', $value['openRequests']));
}
+ if (isset($value['historicRequests'])) {
+ $mainStep->addSubStep(new ImporterStep(_('Request history'), 'requestAccess_historicRequests', $value['historicRequests']));
+ }
$steps[] = $mainStep;
}
break;
@@ -767,6 +770,9 @@ class ConfigDataImporter {
case 'openRequests':
$database->importOpenRequests($data);
break;
+ case 'historicRequests':
+ $database->importRequestHistory($data);
+ break;
}
}
}
diff --git a/lam/style/500_layout.css b/lam/style/500_layout.css
index 6b677b61f..19d7f57a3 100644
--- a/lam/style/500_layout.css
+++ b/lam/style/500_layout.css
@@ -1115,3 +1115,47 @@ div.jodit-container {
margin: var(--lam-small-space);
margin-bottom: var(--lam-regular-space);
}
+
+div.lam-data-table {
+ border-color: var(--lam-table-border-color);
+ background-color: unset;
+}
+
+div.lam-data-table select {
+ width: unset;
+}
+
+div.lam-data-table input {
+ margin: unset;
+}
+
+div.lam-data-table div.tabulator-footer {
+ background-color: var(--lam-background-color-default);
+ border-color: var(--lam-table-border-color);
+}
+
+div.lam-data-table div.tabulator-row-odd {
+ background-color: var(--lam-table-background-color-bright);
+}
+
+div.lam-data-table div.tabulator-row-even {
+ background-color: var(--lam-table-background-color-dark);
+}
+
+div.lam-data-table div.tabulator-row:hover {
+ background-color: var(--lam-table-background-color-hover);
+}
+
+div.lam-data-table div.tabulator-col {
+ background: var(--lam-background-color-default) !important;
+ border-color: var(--lam-table-border-color) !important;
+}
+
+div.lam-data-table div.tabulator-cell,div.tabulator-header {
+ border-color: var(--lam-table-border-color) !important;
+}
+
+div.lam-data-table button.tabulator-page.active {
+ color: var(--lam-text-color-default) !important;
+ font-weight: bold;
+}
diff --git a/lam/style/tabulator/tabulator.css b/lam/style/tabulator/tabulator.css
new file mode 100644
index 000000000..ae06cd989
--- /dev/null
+++ b/lam/style/tabulator/tabulator.css
@@ -0,0 +1,1357 @@
+.tabulator {
+ position: relative;
+ border: 1px solid #999;
+ background-color: #888;
+ font-size: 14px;
+ text-align: left;
+ overflow: hidden;
+ -webkit-transform: translateZ(0);
+ -moz-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ -o-transform: translateZ(0);
+ transform: translateZ(0);
+}
+
+.tabulator[tabulator-layout="fitDataFill"] .tabulator-tableholder .tabulator-table {
+ min-width: 100%;
+}
+
+.tabulator[tabulator-layout="fitDataTable"] {
+ display: inline-block;
+}
+
+.tabulator.tabulator-block-select {
+ user-select: none;
+}
+
+.tabulator.tabulator-ranges .tabulator-cell:not(.tabulator-editing) {
+ user-select: none;
+}
+
+.tabulator .tabulator-header {
+ position: relative;
+ box-sizing: border-box;
+ width: 100%;
+ border-bottom: 1px solid #999;
+ background-color: #e6e6e6;
+ color: #555;
+ font-weight: bold;
+ white-space: nowrap;
+ overflow: hidden;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ -o-user-select: none;
+ outline: none;
+}
+
+.tabulator .tabulator-header.tabulator-header-hidden {
+ display: none;
+}
+
+.tabulator .tabulator-header .tabulator-header-contents {
+ position: relative;
+ overflow: hidden;
+}
+
+.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers {
+ display: inline-block;
+}
+
+.tabulator .tabulator-header .tabulator-col {
+ display: inline-flex;
+ position: relative;
+ box-sizing: border-box;
+ flex-direction: column;
+ justify-content: flex-start;
+ border-right: 1px solid #aaa;
+ background: #e6e6e6;
+ text-align: left;
+ vertical-align: bottom;
+ overflow: hidden;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-moving {
+ position: absolute;
+ border: 1px solid #999;
+ background: #cdcdcd;
+ pointer-events: none;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-range-highlight {
+ background-color: #D6D6D6;
+ color: #000000;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-range-selected {
+ background-color: #3876ca;
+ color: #FFFFFF;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
+ box-sizing: border-box;
+ position: relative;
+ padding: 4px;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button {
+ padding: 0 8px;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover {
+ cursor: pointer;
+ opacity: .6;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder {
+ position: relative;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
+ box-sizing: border-box;
+ width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: bottom;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap {
+ white-space: normal;
+ text-overflow: initial;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor {
+ box-sizing: border-box;
+ width: 100%;
+ border: 1px solid #999;
+ padding: 1px;
+ background: #fff;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button + .tabulator-title-editor {
+ width: calc(100% - 22px);
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter {
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 4px;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
+ width: 0;
+ height: 0;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid #bbb;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols {
+ position: relative;
+ display: flex;
+ border-top: 1px solid #aaa;
+ overflow: hidden;
+ margin-right: -1px;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-header-filter {
+ position: relative;
+ box-sizing: border-box;
+ margin-top: 2px;
+ width: 100%;
+ text-align: center;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea {
+ height: auto !important;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg {
+ margin-top: 3px;
+}
+
+.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear {
+ width: 0;
+ height: 0;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
+ padding-right: 25px;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
+ cursor: pointer;
+ background-color: #cdcdcd;
+ }
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-col-sorter {
+ color: #bbb;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover {
+ cursor: pointer;
+ border-bottom: 6px solid #555;
+ }
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
+ border-top: none;
+ border-bottom: 6px solid #bbb;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter {
+ color: #666;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover {
+ cursor: pointer;
+ border-bottom: 6px solid #555;
+ }
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
+ border-top: none;
+ border-bottom: 6px solid #666;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter {
+ color: #666;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover {
+ cursor: pointer;
+ border-top: 6px solid #555;
+ }
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
+ border-bottom: none;
+ border-top: 6px solid #666;
+ color: #666;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title {
+ writing-mode: vertical-rl;
+ text-orientation: mixed;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title {
+ transform: rotate(180deg);
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title {
+ padding-right: 0;
+ padding-top: 20px;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title {
+ padding-right: 0;
+ padding-bottom: 20px;
+}
+
+.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter {
+ justify-content: center;
+ left: 0;
+ right: 0;
+ top: 4px;
+ bottom: auto;
+}
+
+.tabulator .tabulator-header .tabulator-frozen {
+ position: sticky;
+ left: 0;
+ z-index: 11;
+}
+
+.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
+ border-right: 2px solid #aaa;
+}
+
+.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right {
+ border-left: 2px solid #aaa;
+}
+
+.tabulator .tabulator-header .tabulator-calcs-holder {
+ box-sizing: border-box;
+ display: inline-block;
+ background: #f3f3f3 !important;
+ border-top: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+}
+
+.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row {
+ background: #f3f3f3 !important;
+}
+
+.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle {
+ display: none;
+}
+
+.tabulator .tabulator-header .tabulator-frozen-rows-holder {
+ display: inline-block;
+}
+
+.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty {
+ display: none;
+}
+
+.tabulator .tabulator-tableholder {
+ position: relative;
+ width: 100%;
+ white-space: nowrap;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.tabulator .tabulator-tableholder:focus {
+ outline: none;
+}
+
+.tabulator .tabulator-tableholder .tabulator-placeholder {
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 100%;
+ width: 100%;
+}
+
+.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode="virtual"] {
+ min-height: 100%;
+}
+
+.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents {
+ display: inline-block;
+ text-align: center;
+ padding: 10px;
+ color: #ccc;
+ font-weight: bold;
+ font-size: 20px;
+ white-space: normal;
+}
+
+.tabulator .tabulator-tableholder .tabulator-table {
+ position: relative;
+ display: inline-block;
+ background-color: #fff;
+ white-space: nowrap;
+ overflow: visible;
+ color: #333;
+}
+
+.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs {
+ font-weight: bold;
+ background: #e2e2e2 !important;
+}
+
+.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top {
+ border-bottom: 2px solid #aaa;
+}
+
+.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom {
+ border-top: 2px solid #aaa;
+}
+
+.tabulator .tabulator-tableholder .tabulator-range-overlay {
+ position: absolute;
+ inset: 0;
+ z-index: 10;
+ pointer-events: none;
+}
+
+.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range {
+ position: absolute;
+ box-sizing: border-box;
+ border: 1px solid #2975DD;
+}
+
+.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active::after {
+ content: '';
+ position: absolute;
+ right: -3px;
+ bottom: -3px;
+ width: 6px;
+ height: 6px;
+ background-color: #2975DD;
+ border-radius: 999px;
+}
+
+.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active {
+ position: absolute;
+ box-sizing: border-box;
+ border: 2px solid #2975DD;
+}
+
+.tabulator .tabulator-footer {
+ border-top: 1px solid #999;
+ background-color: #e6e6e6;
+ color: #555;
+ font-weight: bold;
+ white-space: nowrap;
+ user-select: none;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ -o-user-select: none;
+}
+
+.tabulator .tabulator-footer .tabulator-footer-contents {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ padding: 5px 10px;
+}
+
+.tabulator .tabulator-footer .tabulator-footer-contents:empty {
+ display: none;
+}
+
+.tabulator .tabulator-footer .tabulator-spreadsheet-tabs {
+ margin-top: -5px;
+ overflow-x: auto;
+}
+
+.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab {
+ display: inline-block;
+ padding: 5px;
+ border: #999 1px solid;
+ border-top: none;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ font-size: .9em;
+}
+
+.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab:hover {
+ cursor: pointer;
+ opacity: .7;
+}
+
+.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active {
+ background: #fff;
+}
+
+.tabulator .tabulator-footer .tabulator-calcs-holder {
+ box-sizing: border-box;
+ width: 100%;
+ text-align: left;
+ background: #f3f3f3 !important;
+ border-bottom: 1px solid #aaa;
+ border-top: 1px solid #aaa;
+ overflow: hidden;
+}
+
+.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row {
+ display: inline-block;
+ background: #f3f3f3 !important;
+}
+
+.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle {
+ display: none;
+}
+
+.tabulator .tabulator-footer .tabulator-calcs-holder:only-child {
+ margin-bottom: -5px;
+ border-bottom: none;
+}
+
+.tabulator .tabulator-footer > * + .tabulator-page-counter {
+ margin-left: 10px;
+}
+
+.tabulator .tabulator-footer .tabulator-page-counter {
+ font-weight: normal;
+}
+
+.tabulator .tabulator-footer .tabulator-paginator {
+ flex: 1;
+ text-align: right;
+ color: #555;
+ font-family: inherit;
+ font-weight: inherit;
+ font-size: inherit;
+}
+
+.tabulator .tabulator-footer .tabulator-page-size {
+ display: inline-block;
+ margin: 0 5px;
+ padding: 2px 5px;
+ border: 1px solid #aaa;
+ border-radius: 3px;
+}
+
+.tabulator .tabulator-footer .tabulator-pages {
+ margin: 0 7px;
+}
+
+.tabulator .tabulator-footer .tabulator-page {
+ display: inline-block;
+ margin: 0 2px;
+ padding: 2px 5px;
+ border: 1px solid #aaa;
+ border-radius: 3px;
+ background: rgba(255, 255, 255, 0.2);
+}
+
+.tabulator .tabulator-footer .tabulator-page.active {
+ color: #d00;
+}
+
+.tabulator .tabulator-footer .tabulator-page:disabled {
+ opacity: .5;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
+ cursor: pointer;
+ background: rgba(0, 0, 0, 0.2);
+ color: #fff;
+ }
+}
+
+.tabulator .tabulator-col-resize-handle {
+ position: relative;
+ display: inline-block;
+ width: 6px;
+ margin-left: -3px;
+ margin-right: -3px;
+ z-index: 11;
+ vertical-align: middle;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator .tabulator-col-resize-handle:hover {
+ cursor: ew-resize;
+ }
+}
+
+.tabulator .tabulator-col-resize-handle:last-of-type {
+ width: 3px;
+ margin-right: 0;
+}
+
+.tabulator .tabulator-col-resize-guide {
+ position: absolute;
+ top: 0;
+ width: 4px;
+ height: 100%;
+ margin-left: -0.5px;
+ background-color: #999;
+ opacity: .5;
+}
+
+.tabulator .tabulator-row-resize-guide {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 4px;
+ margin-top: -0.5px;
+ background-color: #999;
+ opacity: .5;
+}
+
+.tabulator .tabulator-alert {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ top: 0;
+ left: 0;
+ z-index: 100;
+ height: 100%;
+ width: 100%;
+ background: rgba(0, 0, 0, 0.4);
+ text-align: center;
+}
+
+.tabulator .tabulator-alert .tabulator-alert-msg {
+ display: inline-block;
+ margin: 0 auto;
+ padding: 10px 20px;
+ border-radius: 10px;
+ background: #fff;
+ font-weight: bold;
+ font-size: 16px;
+}
+
+.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
+ border: 4px solid #333;
+ color: #000;
+}
+
+.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
+ border: 4px solid #D00;
+ color: #590000;
+}
+
+.tabulator-row {
+ position: relative;
+ box-sizing: border-box;
+ min-height: 22px;
+ background-color: #fff;
+}
+
+.tabulator-row.tabulator-row-even {
+ background-color: #EFEFEF;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row.tabulator-selectable:hover {
+ background-color: #bbb;
+ cursor: pointer;
+ }
+}
+
+.tabulator-row.tabulator-selected {
+ background-color: #9ABCEA;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row.tabulator-selected:hover {
+ background-color: #769BCC;
+ cursor: pointer;
+ }
+}
+
+.tabulator-row.tabulator-row-moving {
+ border: 1px solid #000;
+ background: #fff;
+}
+
+.tabulator-row.tabulator-moving {
+ position: absolute;
+ border-top: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+ pointer-events: none;
+ z-index: 15;
+}
+
+.tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header {
+ background-color: #D6D6D6;
+ color: #000000;
+}
+
+.tabulator-row.tabulator-range-highlight.tabulator-range-selected .tabulator-cell.tabulator-range-row-header {
+ background-color: #3876ca;
+ color: #FFFFFF;
+}
+
+.tabulator-row.tabulator-range-selected .tabulator-cell.tabulator-range-row-header {
+ background-color: #3876ca;
+ color: #FFFFFF;
+}
+
+.tabulator-row .tabulator-row-resize-handle {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 5px;
+}
+
+.tabulator-row .tabulator-row-resize-handle.prev {
+ top: 0;
+ bottom: auto;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row .tabulator-row-resize-handle:hover {
+ cursor: ns-resize;
+ }
+}
+
+.tabulator-row .tabulator-responsive-collapse {
+ box-sizing: border-box;
+ padding: 5px;
+ border-top: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+}
+
+.tabulator-row .tabulator-responsive-collapse:empty {
+ display: none;
+}
+
+.tabulator-row .tabulator-responsive-collapse table {
+ font-size: 14px;
+}
+
+.tabulator-row .tabulator-responsive-collapse table tr td {
+ position: relative;
+}
+
+.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type {
+ padding-right: 10px;
+}
+
+.tabulator-row .tabulator-cell {
+ display: inline-block;
+ position: relative;
+ box-sizing: border-box;
+ padding: 4px;
+ border-right: 1px solid #aaa;
+ vertical-align: middle;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ outline: none;
+}
+
+.tabulator-row .tabulator-cell.tabulator-row-header {
+ border-right: 1px solid #999;
+ border-bottom: 1px solid #aaa;
+ background: #e6e6e6;
+}
+
+.tabulator-row .tabulator-cell.tabulator-frozen {
+ display: inline-block;
+ position: sticky;
+ left: 0;
+ background-color: inherit;
+ z-index: 11;
+}
+
+.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
+ border-right: 2px solid #aaa;
+}
+
+.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
+ border-left: 2px solid #aaa;
+}
+
+.tabulator-row .tabulator-cell.tabulator-editing {
+ border: 1px solid #1D68CD;
+ outline: none;
+ padding: 0;
+}
+
+.tabulator-row .tabulator-cell.tabulator-editing input,
+.tabulator-row .tabulator-cell.tabulator-editing select {
+ border: 1px;
+ background: transparent;
+ outline: none;
+}
+
+.tabulator-row .tabulator-cell.tabulator-validation-fail {
+ border: 1px solid #dd0000;
+}
+
+.tabulator-row .tabulator-cell.tabulator-validation-fail input,
+.tabulator-row .tabulator-cell.tabulator-validation-fail select {
+ border: 1px;
+ background: transparent;
+ color: #dd0000;
+}
+
+.tabulator-row .tabulator-cell.tabulator-row-handle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ -o-user-select: none;
+}
+
+.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box {
+ width: 80%;
+}
+
+.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar {
+ width: 100%;
+ height: 3px;
+ margin-top: 2px;
+ background: #666;
+}
+
+.tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header) {
+ background-color: #9ABCEA;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty {
+ display: inline-block;
+ width: 7px;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-branch {
+ display: inline-block;
+ vertical-align: middle;
+ height: 9px;
+ width: 7px;
+ margin-top: -9px;
+ margin-right: 5px;
+ border-bottom-left-radius: 1px;
+ border-left: 2px solid #aaa;
+ border-bottom: 2px solid #aaa;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-control {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ vertical-align: middle;
+ height: 11px;
+ width: 11px;
+ margin-right: 5px;
+ border: 1px solid #333;
+ border-radius: 2px;
+ background: rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row .tabulator-cell .tabulator-data-tree-control:hover {
+ cursor: pointer;
+ background: rgba(0, 0, 0, 0.2);
+ }
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse {
+ display: inline-block;
+ position: relative;
+ height: 7px;
+ width: 1px;
+ background: transparent;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after {
+ position: absolute;
+ content: "";
+ left: -3px;
+ top: 3px;
+ height: 1px;
+ width: 7px;
+ background: #333;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand {
+ display: inline-block;
+ position: relative;
+ height: 7px;
+ width: 1px;
+ background: #333;
+}
+
+.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after {
+ position: absolute;
+ content: "";
+ left: -3px;
+ top: 3px;
+ height: 1px;
+ width: 7px;
+ background: #333;
+}
+
+.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ -o-user-select: none;
+ height: 15px;
+ width: 15px;
+ border-radius: 20px;
+ background: #666;
+ color: #fff;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover {
+ opacity: .7;
+ cursor: pointer;
+ }
+}
+
+.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close {
+ display: initial;
+}
+
+.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open {
+ display: none;
+}
+
+.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg {
+ stroke: #fff;
+}
+
+.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close {
+ display: none;
+}
+
+.tabulator-row .tabulator-cell .tabulator-traffic-light {
+ display: inline-block;
+ height: 14px;
+ width: 14px;
+ border-radius: 14px;
+}
+
+.tabulator-row.tabulator-group {
+ box-sizing: border-box;
+ border-bottom: 1px solid #999;
+ border-right: 1px solid #aaa;
+ border-top: 1px solid #999;
+ padding: 5px;
+ padding-left: 10px;
+ background: #ccc;
+ font-weight: bold;
+ min-width: 100%;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-row.tabulator-group:hover {
+ cursor: pointer;
+ background-color: rgba(0, 0, 0, 0.1);
+ }
+}
+
+.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow {
+ margin-right: 10px;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-top: 6px solid #666;
+ border-bottom: 0;
+}
+
+.tabulator-row.tabulator-group.tabulator-group-level-1 {
+ padding-left: 30px;
+}
+
+.tabulator-row.tabulator-group.tabulator-group-level-2 {
+ padding-left: 50px;
+}
+
+.tabulator-row.tabulator-group.tabulator-group-level-3 {
+ padding-left: 70px;
+}
+
+.tabulator-row.tabulator-group.tabulator-group-level-4 {
+ padding-left: 90px;
+}
+
+.tabulator-row.tabulator-group.tabulator-group-level-5 {
+ padding-left: 110px;
+}
+
+.tabulator-row.tabulator-group .tabulator-group-toggle {
+ display: inline-block;
+}
+
+.tabulator-row.tabulator-group .tabulator-arrow {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-right: 16px;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-right: 0;
+ border-left: 6px solid #666;
+ vertical-align: middle;
+}
+
+.tabulator-row.tabulator-group span {
+ margin-left: 10px;
+ color: #d00;
+}
+
+.tabulator-toggle {
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ border: 1px solid #ccc;
+ background: #dcdcdc;
+}
+
+.tabulator-toggle.tabulator-toggle-on {
+ background: #1c6cc2;
+}
+
+.tabulator-toggle .tabulator-toggle-switch {
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ background: #fff;
+}
+
+.tabulator-popup-container {
+ position: absolute;
+ display: inline-block;
+ box-sizing: border-box;
+ background: #fff;
+ border: 1px solid #aaa;
+ box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.2);
+ font-size: 14px;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ z-index: 10000;
+}
+
+.tabulator-popup {
+ padding: 5px;
+ border-radius: 3px;
+}
+
+.tabulator-tooltip {
+ max-width: Min(500px, 100%);
+ padding: 3px 5px;
+ border-radius: 2px;
+ box-shadow: none;
+ font-size: 12px;
+ pointer-events: none;
+}
+
+.tabulator-menu .tabulator-menu-item {
+ position: relative;
+ box-sizing: border-box;
+ padding: 5px 10px;
+ user-select: none;
+}
+
+.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled {
+ opacity: .5;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover {
+ cursor: pointer;
+ background: #EFEFEF;
+ }
+}
+
+.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu {
+ padding-right: 25px;
+}
+
+.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu::after {
+ display: inline-block;
+ position: absolute;
+ top: calc(5px + .4em);
+ right: 10px;
+ height: 7px;
+ width: 7px;
+ content: '';
+ border-width: 1px 1px 0 0;
+ border-style: solid;
+ border-color: #aaa;
+ vertical-align: top;
+ transform: rotate(45deg);
+}
+
+.tabulator-menu .tabulator-menu-separator {
+ border-top: 1px solid #aaa;
+}
+
+.tabulator-edit-list {
+ max-height: 200px;
+ font-size: 14px;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item {
+ padding: 4px;
+ color: #333;
+ outline: none;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.active {
+ color: #fff;
+ background: #1D68CD;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.active.focused {
+ outline: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.focused {
+ outline: 1px solid #1D68CD;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-edit-list .tabulator-edit-list-item:hover {
+ cursor: pointer;
+ color: #fff;
+ background: #1D68CD;
+ }
+}
+
+.tabulator-edit-list .tabulator-edit-list-placeholder {
+ padding: 4px;
+ color: #333;
+ text-align: center;
+}
+
+.tabulator-edit-list .tabulator-edit-list-group {
+ border-bottom: 1px solid #aaa;
+ padding: 4px;
+ padding-top: 6px;
+ color: #333;
+ font-weight: bold;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2,
+.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2 {
+ padding-left: 12px;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3,
+.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3 {
+ padding-left: 20px;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4,
+.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4 {
+ padding-left: 28px;
+}
+
+.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5,
+.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5 {
+ padding-left: 36px;
+}
+
+.tabulator.tabulator-ltr {
+ direction: ltr;
+}
+
+.tabulator.tabulator-rtl {
+ text-align: initial;
+ direction: rtl;
+}
+
+.tabulator.tabulator-rtl .tabulator-header .tabulator-col {
+ text-align: initial;
+ border-left: 1px solid #aaa;
+ border-right: initial;
+}
+
+.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols {
+ margin-right: initial;
+ margin-left: -1px;
+}
+
+.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
+ padding-right: 0;
+ padding-left: 25px;
+}
+
+.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter {
+ left: 8px;
+ right: initial;
+}
+
+.tabulator.tabulator-rtl .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active::after {
+ content: '';
+ position: absolute;
+ left: -3px;
+ right: initial;
+ bottom: -3px;
+ width: 6px;
+ height: 6px;
+ background-color: #2975DD;
+ border-radius: 999px;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-cell {
+ border-right: initial;
+ border-left: 1px solid #aaa;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch {
+ margin-right: initial;
+ margin-left: 5px;
+ border-bottom-left-radius: initial;
+ border-bottom-right-radius: 1px;
+ border-left: initial;
+ border-right: 2px solid #aaa;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control {
+ margin-right: initial;
+ margin-left: 5px;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
+ border-left: 2px solid #aaa;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
+ border-right: 2px solid #aaa;
+}
+
+.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type {
+ width: 3px;
+ margin-left: 0;
+ margin-right: -3px;
+}
+
+.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder {
+ text-align: initial;
+}
+
+.tabulator-print-fullscreen {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: 10000;
+}
+
+body.tabulator-print-fullscreen-hide > *:not(.tabulator-print-fullscreen) {
+ display: none !important;
+}
+
+.tabulator-print-table {
+ border-collapse: collapse;
+}
+
+.tabulator-print-table .tabulator-data-tree-branch {
+ display: inline-block;
+ vertical-align: middle;
+ height: 9px;
+ width: 7px;
+ margin-top: -9px;
+ margin-right: 5px;
+ border-bottom-left-radius: 1px;
+ border-left: 2px solid #aaa;
+ border-bottom: 2px solid #aaa;
+}
+
+.tabulator-print-table .tabulator-print-table-group {
+ box-sizing: border-box;
+ border-bottom: 1px solid #999;
+ border-right: 1px solid #aaa;
+ border-top: 1px solid #999;
+ padding: 5px;
+ padding-left: 10px;
+ background: #ccc;
+ font-weight: bold;
+ min-width: 100%;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-print-table .tabulator-print-table-group:hover {
+ cursor: pointer;
+ background-color: rgba(0, 0, 0, 0.1);
+ }
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow {
+ margin-right: 10px;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-top: 6px solid #666;
+ border-bottom: 0;
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td {
+ padding-left: 30px !important;
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td {
+ padding-left: 50px !important;
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td {
+ padding-left: 70px !important;
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td {
+ padding-left: 90px !important;
+}
+
+.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td {
+ padding-left: 110px !important;
+}
+
+.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle {
+ display: inline-block;
+}
+
+.tabulator-print-table .tabulator-print-table-group .tabulator-arrow {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-right: 16px;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-right: 0;
+ border-left: 6px solid #666;
+ vertical-align: middle;
+}
+
+.tabulator-print-table .tabulator-print-table-group span {
+ margin-left: 10px;
+ color: #d00;
+}
+
+.tabulator-print-table .tabulator-data-tree-control {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ vertical-align: middle;
+ height: 11px;
+ width: 11px;
+ margin-right: 5px;
+ border: 1px solid #333;
+ border-radius: 2px;
+ background: rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ .tabulator-print-table .tabulator-data-tree-control:hover {
+ cursor: pointer;
+ background: rgba(0, 0, 0, 0.2);
+ }
+}
+
+.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse {
+ display: inline-block;
+ position: relative;
+ height: 7px;
+ width: 1px;
+ background: transparent;
+}
+
+.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after {
+ position: absolute;
+ content: "";
+ left: -3px;
+ top: 3px;
+ height: 1px;
+ width: 7px;
+ background: #333;
+}
+
+.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand {
+ display: inline-block;
+ position: relative;
+ height: 7px;
+ width: 1px;
+ background: #333;
+}
+
+.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after {
+ position: absolute;
+ content: "";
+ left: -3px;
+ top: 3px;
+ height: 1px;
+ width: 7px;
+ background: #333;
+}
+
+/*# sourceMappingURL=tabulator.css.map */
\ No newline at end of file
diff --git a/lam/templates/config/confImportExport.php b/lam/templates/config/confImportExport.php
index 08338a7ab..cf71af684 100644
--- a/lam/templates/config/confImportExport.php
+++ b/lam/templates/config/confImportExport.php
@@ -19,7 +19,7 @@
/*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
- Copyright (C) 2020 - 2023 Roland Gruber
+ Copyright (C) 2020 - 2024 Roland Gruber
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
@@ -78,7 +78,11 @@
if ($zipTmpFile === false) {
throw new LAMException(_('Unable to create temporary file.'));
}
- $zipFile = stream_get_meta_data($zipTmpFile)['uri'];
+ $metaData = stream_get_meta_data($zipTmpFile);
+ if (empty($metaData['uri'])) {
+ throw new LAMException(_('Unable to create temporary file.'));
+ }
+ $zipFile = $metaData['uri'];
fclose($zipTmpFile);
$zip->open($zipFile, ZipArchive::CREATE);
$json = $exporter->exportAsJson();
diff --git a/lam/templates/config/mainmanage.php b/lam/templates/config/mainmanage.php
index e74679bfd..f273edaca 100644
--- a/lam/templates/config/mainmanage.php
+++ b/lam/templates/config/mainmanage.php
@@ -388,10 +388,17 @@
}
}
$cfg->errorReporting = $_POST['errorReporting'];
+ // module settings
+ $allModules = getAllModules();
+ $moduleSettings = $cfg->getModuleSettings();
+ foreach ($allModules as $module) {
+ $module->checkGlobalConfigOptions($moduleSettings, $messages, $errors);
+ }
+ $cfg->setModuleSettings($moduleSettings);
// save settings
if (isset($_POST['submit'])) {
$cfg->save();
- if (sizeof($errors) == 0) {
+ if (empty($errors)) {
$scriptTag = new htmlJavaScript('window.lam.dialog.showSuccessMessageAndRedirect("' . _("Your settings were successfully saved.") . '", "", "' . _('Ok') . '", "../login.php")');
parseHtml(null, $scriptTag, [], false, null);
echo '