Userlist
@@ -71,6 +71,7 @@ INCLUDE_DIRECTORIES(
|
||||
|
||||
add_executable(nwwebui nwwebui.c)
|
||||
add_executable(check_login check_login.c)
|
||||
add_executable(smart_userlist smart_userlist.c)
|
||||
|
||||
#################################
|
||||
# Linking
|
||||
@@ -86,6 +87,11 @@ target_link_libraries(check_login
|
||||
${DL_LIBRARY}
|
||||
)
|
||||
|
||||
target_link_libraries(smart_userlist
|
||||
${PAM_LIBRARY}
|
||||
${DL_LIBRARY}
|
||||
)
|
||||
|
||||
#################################
|
||||
# Install Files
|
||||
##############
|
||||
@@ -108,12 +114,28 @@ install(FILES static/favicon.ico DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}
|
||||
install(FILES static/favicon-32x32.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/favicon-16x16.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/apple-touch-icon.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-start.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-service.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-general.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-dirs.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-configh.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-security.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-susers.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-volumes.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-devices.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-logging.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-smart.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-stations.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-users.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-groups.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
install(FILES static/icon-queues.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
|
||||
|
||||
if(WITH_SYSTEMD)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mars-nwe-webui.service DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR})
|
||||
endif()
|
||||
|
||||
install(TARGETS check_login DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR})
|
||||
install(TARGETS smart_userlist DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR})
|
||||
|
||||
install(TARGETS nwwebui DESTINATION ${CMAKE_INSTALL_SBINDIR})
|
||||
|
||||
|
||||
181
apply.pl
@@ -22,12 +22,54 @@
|
||||
#
|
||||
#
|
||||
|
||||
sub read_smart_bindery_values()
|
||||
{
|
||||
my( $bind_server, $bind_user, $bind_pass ) = ( '', '', '' );
|
||||
|
||||
if( open( my $fh, '<' . $smart_nwclient_path ) )
|
||||
{
|
||||
my $line = <$fh>;
|
||||
close( $fh );
|
||||
|
||||
chomp( $line ) if defined( $line );
|
||||
( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $line ) if defined( $line );
|
||||
}
|
||||
|
||||
$bind_server = '' unless defined( $bind_server );
|
||||
$bind_user = '' unless defined( $bind_user );
|
||||
$bind_pass = '' unless defined( $bind_pass );
|
||||
|
||||
return( $bind_server, $bind_user, $bind_pass );
|
||||
}
|
||||
|
||||
sub write_smart_bindery_values( $$$ )
|
||||
{
|
||||
my( $bind_server, $bind_user, $bind_pass ) = @_;
|
||||
|
||||
$bind_server = '' unless defined( $bind_server );
|
||||
$bind_user = '' unless defined( $bind_user );
|
||||
$bind_pass = '' unless defined( $bind_pass );
|
||||
|
||||
open( my $fh, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!";
|
||||
print( $fh $bind_server . '/' . $bind_user . ' ' . $bind_pass . "\n" );
|
||||
close( $fh );
|
||||
|
||||
chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path );
|
||||
chmod( 0600, $smart_nwclient_path );
|
||||
}
|
||||
|
||||
|
||||
sub handle_request()
|
||||
{
|
||||
if( $c[1] eq 'general' )
|
||||
{
|
||||
setc( 2, server_name );
|
||||
setc( 3, internal_net );
|
||||
if( defined( $p{sync_smart_bind_server} ) && $p{sync_smart_bind_server} eq 'on' && defined( $p{server_name} ) && $p{server_name} ne '' )
|
||||
{
|
||||
my( $old_bind_server, $old_bind_user, $old_bind_pass ) = read_smart_bindery_values();
|
||||
write_smart_bindery_values( $p{server_name}, $old_bind_user, $old_bind_pass );
|
||||
}
|
||||
setc( 16, test );
|
||||
setc( 210, timing_down );
|
||||
setc( 211, timing_warn );
|
||||
@@ -109,10 +151,6 @@ sub handle_request()
|
||||
{
|
||||
delconfigline( '4 ' . $c[2] );
|
||||
}
|
||||
if( defined( $p{interface_manual} ) && $p{interface_manual} ne '' )
|
||||
{
|
||||
$p{interface} = $p{interface_manual};
|
||||
}
|
||||
$p{interface} =~ s/[^-_\.A-Za-z0-9:\*]//g;
|
||||
if( $p{number} ne '' )
|
||||
{
|
||||
@@ -148,12 +186,13 @@ sub handle_request()
|
||||
close( FILE );
|
||||
}
|
||||
|
||||
open( FILE, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!";
|
||||
print( FILE $p{bind_server} . '/' . $p{bind_user} . ' ' . $p{bind_pass } . "\n" );
|
||||
close( FILE );
|
||||
|
||||
chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path );
|
||||
chmod( 0600, $smart_nwclient_path );
|
||||
write_smart_bindery_values( $p{bind_server}, $p{bind_user}, $p{bind_pass} );
|
||||
|
||||
if( defined( $p{sync_general_server_name} ) && $p{sync_general_server_name} eq 'on' && defined( $p{bind_server} ) && $p{bind_server} ne '' )
|
||||
{
|
||||
$p{server_name} = $p{bind_server};
|
||||
setc( 2, server_name );
|
||||
}
|
||||
}
|
||||
elsif( $c[1] eq 'users' )
|
||||
{
|
||||
@@ -355,6 +394,92 @@ EOF
|
||||
|
||||
redirect( '/settings/queues' );
|
||||
}
|
||||
|
||||
elsif( $c[1] eq 'advanced' )
|
||||
{
|
||||
my $advanced_category = $p{advanced_category};
|
||||
$advanced_category = 'all' if ! defined( $advanced_category ) || $advanced_category eq '';
|
||||
|
||||
my $save_devices = ( $advanced_category eq 'all' || $advanced_category eq 'devices' );
|
||||
my $save_security = ( $advanced_category eq 'all' || $advanced_category eq 'security' );
|
||||
my $save_users = ( $advanced_category eq 'all' || $advanced_category eq 'users' );
|
||||
my $save_queues = ( $advanced_category eq 'all' || $advanced_category eq 'queues' );
|
||||
my $save_configh = ( $advanced_category eq 'all' || $advanced_category eq 'configh' );
|
||||
my $save_stations = ( $advanced_category eq 'all' || $advanced_category eq 'stations' );
|
||||
my $save_network = ( $advanced_category eq 'all' || $advanced_category eq 'network' );
|
||||
|
||||
if( $save_devices )
|
||||
{
|
||||
my $device_flags = 0;
|
||||
$device_flags += 1 if $p{dev_keep} eq 'on';
|
||||
$device_flags += 2 if $p{dev_auto} eq 'on';
|
||||
$device_flags += 4 if $p{dev_remove_all} eq 'on';
|
||||
|
||||
delconfigline( 5 );
|
||||
addconfigline( '5 ' . $device_flags ) if $device_flags != 0;
|
||||
}
|
||||
|
||||
if( $save_security )
|
||||
{
|
||||
my $security_flags = 0;
|
||||
$security_flags += 0x8 if $p{sec_supervisor_ignore} eq 'on';
|
||||
$security_flags += 0x40 if $p{sec_2gb_free} eq 'on';
|
||||
$security_flags += 0x200 if $p{sec_int17} eq 'on';
|
||||
$security_flags += 0x2 if $p{sec_delete_open} eq 'on';
|
||||
$security_flags += 0x4 if $p{sec_rename_open} eq 'on';
|
||||
|
||||
delconfigline( 8 );
|
||||
addconfigline( '8 ' . $security_flags ) if $security_flags != 0;
|
||||
}
|
||||
|
||||
if( $save_users )
|
||||
{
|
||||
my $bindery_flags = 0;
|
||||
$bindery_flags += 1 if $p{bindery_empty_scripts} eq 'on';
|
||||
|
||||
delconfigline( 17 );
|
||||
addconfigline( '17 ' . $bindery_flags ) if $bindery_flags != 0;
|
||||
}
|
||||
|
||||
if( $save_queues )
|
||||
{
|
||||
my $queue_flags = 0;
|
||||
$queue_flags += 1 if $p{queue_no_banner} eq 'on';
|
||||
|
||||
delconfigline( 18 );
|
||||
addconfigline( '18 ' . $queue_flags ) if $queue_flags != 0;
|
||||
|
||||
delconfigline( 22 );
|
||||
foreach my $line ( split( /\r?\n/, $p{print_servers} ) )
|
||||
{
|
||||
$line =~ s/^\s+//;
|
||||
$line =~ s/\s+$//;
|
||||
next if $line eq '';
|
||||
$line =~ s/#.*//;
|
||||
next if $line eq '';
|
||||
addconfigline( '22 ' . $line );
|
||||
}
|
||||
}
|
||||
|
||||
if( $save_configh )
|
||||
{
|
||||
setc( 50, conversion_tables );
|
||||
setc( 80, max_dir_search_handles );
|
||||
}
|
||||
|
||||
if( $save_network )
|
||||
{
|
||||
setc( 310, watchdogs );
|
||||
}
|
||||
|
||||
if( $save_stations )
|
||||
{
|
||||
setc( 400, station_file );
|
||||
setc( 401, nearest_replies );
|
||||
setc( 402, connect_replies );
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
putp();
|
||||
@@ -365,6 +490,42 @@ EOF
|
||||
writeconfig();
|
||||
}
|
||||
|
||||
|
||||
sub add_mask_flag( $$$ )
|
||||
{
|
||||
my( $value, $param, $mask ) = @_;
|
||||
if( defined( $p{$param} ) && $p{$param} ne '' )
|
||||
{
|
||||
$value |= $mask;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub addconfig_hex( $$ )
|
||||
{
|
||||
delconfigline( $_[0] );
|
||||
addconfigline( $_[0] . ' 0x' . sprintf( '%x', $_[1] ) );
|
||||
}
|
||||
|
||||
sub sanitize_simple_value( $ )
|
||||
{
|
||||
my $v = $_[0];
|
||||
$v = '' unless defined $v;
|
||||
$v =~ s/[\r\n]//g;
|
||||
$v =~ s/^\s+//;
|
||||
$v =~ s/\s+$//;
|
||||
$v =~ s/[^-_\.\/\:\~A-Za-z0-9]//g;
|
||||
return $v;
|
||||
}
|
||||
|
||||
sub sanitize_number_value( $ )
|
||||
{
|
||||
my $v = $_[0];
|
||||
$v = '' unless defined $v;
|
||||
$v =~ s/[^0-9xXa-fA-F\-]//g;
|
||||
return $v;
|
||||
}
|
||||
|
||||
sub putp()
|
||||
{
|
||||
$cc =~ s/.*\?//;
|
||||
|
||||
64
cupsutils.cmake
Normal file
@@ -0,0 +1,64 @@
|
||||
# Optional CUPS command line utility support for SMArT WebUI.
|
||||
#
|
||||
# This module intentionally searches for the CUPS command line utilities
|
||||
# used by the WebUI, not for libcups development headers/libraries.
|
||||
#
|
||||
# Variables exported:
|
||||
#
|
||||
# WITH_CUPSUTILS
|
||||
# User option to enable/disable CUPS utility discovery.
|
||||
#
|
||||
# HAVE_CUPSUTILS
|
||||
# ON when the required CUPS utilities were found.
|
||||
#
|
||||
# SMART_CUPS_ENABLE
|
||||
# 1 when HAVE_CUPSUTILS is ON, otherwise 0. Intended for configure_file()
|
||||
# into Perl config files.
|
||||
#
|
||||
# CUPS_LPSTAT_EXECUTABLE
|
||||
# Path to lpstat.
|
||||
#
|
||||
# CUPS_LP_EXECUTABLE
|
||||
# Path to lp.
|
||||
#
|
||||
# CUPS_LPR_EXECUTABLE
|
||||
# Optional path to lpr, if available.
|
||||
|
||||
option(WITH_CUPSUTILS "Enable CUPS utility support for SMArT WebUI" ON)
|
||||
|
||||
set(HAVE_CUPSUTILS OFF)
|
||||
set(SMART_CUPS_ENABLE 0)
|
||||
|
||||
if(WITH_CUPSUTILS)
|
||||
find_program(CUPS_LPSTAT_EXECUTABLE NAMES lpstat)
|
||||
find_program(CUPS_LP_EXECUTABLE NAMES lp)
|
||||
find_program(CUPS_LPR_EXECUTABLE NAMES lpr)
|
||||
|
||||
if(CUPS_LPSTAT_EXECUTABLE AND CUPS_LP_EXECUTABLE)
|
||||
set(HAVE_CUPSUTILS ON)
|
||||
set(SMART_CUPS_ENABLE 1)
|
||||
message(STATUS "Found CUPS utilities: lpstat=${CUPS_LPSTAT_EXECUTABLE}, lp=${CUPS_LP_EXECUTABLE}")
|
||||
if(CUPS_LPR_EXECUTABLE)
|
||||
message(STATUS "Found optional CUPS lpr utility: ${CUPS_LPR_EXECUTABLE}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "CUPS utilities not found; SMArT WebUI CUPS printer discovery disabled")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "CUPS utility support disabled")
|
||||
endif()
|
||||
|
||||
# Provide stable fallback strings for configure_file() consumers. These are
|
||||
# only used when SMART_CUPS_ENABLE is 0 or when the admin later overrides the
|
||||
# paths in smart.conf.
|
||||
if(NOT CUPS_LPSTAT_EXECUTABLE)
|
||||
set(CUPS_LPSTAT_EXECUTABLE "/usr/bin/lpstat")
|
||||
endif()
|
||||
|
||||
if(NOT CUPS_LP_EXECUTABLE)
|
||||
set(CUPS_LP_EXECUTABLE "/usr/bin/lp")
|
||||
endif()
|
||||
|
||||
if(NOT CUPS_LPR_EXECUTABLE)
|
||||
set(CUPS_LPR_EXECUTABLE "/usr/bin/lpr")
|
||||
endif()
|
||||
950
settings.pl
@@ -146,3 +146,7 @@ $nw_cert_file = '@MARS_NWE_INSTALL_FULL_CONFDIR@/server.crt';
|
||||
# TLS private key file in PEM format.
|
||||
# Required only when HTTPS is enabled.
|
||||
$nw_key_file = '@MARS_NWE_INSTALL_FULL_CONFDIR@/server.key';
|
||||
|
||||
# Helper used by SMArT to list Unix/NSS users.
|
||||
$smart_userlist_path = '@MARS_NWE_INSTALL_FULL_LIBEXECDIR@/smart_userlist';
|
||||
$smart_userlist_pam_check = 0;
|
||||
|
||||
171
smart_userlist.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
SMArT
|
||||
|
||||
List local/NSS users for the WebUI.
|
||||
|
||||
PAM itself cannot enumerate users. User enumeration is done through NSS
|
||||
getpwent(), so /etc/nsswitch.conf is honored (files, sss, ldap, nis, ...).
|
||||
Optionally, each user can be checked with pam_acct_mgmt() against the "smart"
|
||||
PAM service.
|
||||
|
||||
Output format:
|
||||
username<TAB>uid<TAB>gid<TAB>gecos<TAB>home<TAB>shell
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int empty_conv(int num_msg, const struct pam_message **msg,
|
||||
struct pam_response **resp, void *appdata_ptr)
|
||||
{
|
||||
struct pam_response *reply;
|
||||
|
||||
(void) msg;
|
||||
(void) appdata_ptr;
|
||||
|
||||
if (num_msg <= 0) {
|
||||
*resp = NULL;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
reply = calloc((size_t) num_msg, sizeof(struct pam_response));
|
||||
if (reply == NULL) {
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
*resp = reply;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
static int pam_account_ok(const char *service, const char *user)
|
||||
{
|
||||
struct pam_conv conv = { empty_conv, NULL };
|
||||
pam_handle_t *pamh = NULL;
|
||||
int rc;
|
||||
|
||||
rc = pam_start(service, user, &conv, &pamh);
|
||||
if (rc == PAM_SUCCESS) {
|
||||
rc = pam_acct_mgmt(pamh, PAM_SILENT);
|
||||
}
|
||||
|
||||
if (pamh != NULL) {
|
||||
pam_end(pamh, rc);
|
||||
}
|
||||
|
||||
return rc == PAM_SUCCESS;
|
||||
}
|
||||
|
||||
static void print_sanitized(const char *s)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) (s != NULL ? s : "");
|
||||
|
||||
while (*p != '\0') {
|
||||
if (*p == '\t' || *p == '\n' || *p == '\r') {
|
||||
putchar(' ');
|
||||
} else {
|
||||
putchar((int) *p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static int is_safe_name(const char *s)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) s;
|
||||
|
||||
if (s == NULL || *s == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*p != '\0') {
|
||||
if (!( (*p >= 'A' && *p <= 'Z') ||
|
||||
(*p >= 'a' && *p <= 'z') ||
|
||||
(*p >= '0' && *p <= '9') ||
|
||||
*p == '_' || *p == '-' || *p == '.' )) {
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct passwd *pw;
|
||||
uid_t min_uid = 1000;
|
||||
int include_system = 0;
|
||||
int pam_check = 0;
|
||||
const char *pam_service = "smart";
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--all") == 0) {
|
||||
include_system = 1;
|
||||
min_uid = 0;
|
||||
} else if (strcmp(argv[i], "--min-uid") == 0 && i + 1 < argc) {
|
||||
char *end = NULL;
|
||||
unsigned long v = strtoul(argv[++i], &end, 10);
|
||||
if (end == NULL || *end != '\0') {
|
||||
fprintf(stderr, "Invalid --min-uid value\n");
|
||||
return 2;
|
||||
}
|
||||
min_uid = (uid_t) v;
|
||||
} else if (strcmp(argv[i], "--pam-check") == 0) {
|
||||
pam_check = 1;
|
||||
} else if (strcmp(argv[i], "--pam-service") == 0 && i + 1 < argc) {
|
||||
pam_service = argv[++i];
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [--all] [--min-uid UID] [--pam-check] [--pam-service SERVICE]\n",
|
||||
argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
setpwent();
|
||||
|
||||
while ((pw = getpwent()) != NULL) {
|
||||
if (!is_safe_name(pw->pw_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!include_system && pw->pw_uid < min_uid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!include_system &&
|
||||
(strcmp(pw->pw_name, "root") == 0 || strcmp(pw->pw_name, "nobody") == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pam_check && !pam_account_ok(pam_service, pw->pw_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
print_sanitized(pw->pw_name);
|
||||
printf("\t%lu\t%lu\t", (unsigned long) pw->pw_uid, (unsigned long) pw->pw_gid);
|
||||
print_sanitized(pw->pw_gecos);
|
||||
putchar('\t');
|
||||
print_sanitized(pw->pw_dir);
|
||||
putchar('\t');
|
||||
print_sanitized(pw->pw_shell);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
endpwent();
|
||||
|
||||
if (errno != 0) {
|
||||
perror("getpwent");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
static/icon-configh.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M42 16h16l3 13 12-7 8 14-10 8 10 8-8 14-12-7-3 13H42l-3-13-12 7-8-14 10-8-10-8 8-14 12 7z"/>
|
||||
<circle cx="50" cy="50" r="12"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 704 B |
19
static/icon-devices.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M32 18v23M68 18v23"/>
|
||||
<path d="M26 41h48v13a24 24 0 0 1-48 0z"/>
|
||||
<path d="M50 78v10M36 88h28"/>
|
||||
<path d="M38 54h24"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 696 B |
18
static/icon-dirs.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M18 34h23l6 8h35v32a6 6 0 0 1-6 6H24a6 6 0 0 1-6-6z"/>
|
||||
<path d="M18 34v-7a5 5 0 0 1 5-5h19l7 8h28a5 5 0 0 1 5 5v7"/>
|
||||
<path d="M27 57h46"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 717 B |
18
static/icon-general.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M50 20v10M50 70v10M20 50h10M70 50h10M29 29l7 7M64 64l7 7M71 29l-7 7M36 64l-7 7"/>
|
||||
<circle cx="50" cy="50" r="14"/>
|
||||
<circle cx="50" cy="50" r="5" fill="currentColor" stroke="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 759 B |
18
static/icon-groups.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M24 29h27l8 8h17v34a6 6 0 0 1-6 6H24z"/>
|
||||
<path d="M31 50h38M31 61h28"/>
|
||||
<circle cx="72" cy="27" r="9"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 682 B |
19
static/icon-logging.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M28 16h34l10 10v58H28z"/>
|
||||
<path d="M62 16v14h14"/>
|
||||
<path d="M37 43h26M37 55h26M37 67h18"/>
|
||||
<path d="M70 58l9 9-17 17-10 2 2-10z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 709 B |
20
static/icon-queues.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M30 20h40v20H30z"/>
|
||||
<path d="M22 40h56a8 8 0 0 1 8 8v22H14V48a8 8 0 0 1 8-8z"/>
|
||||
<path d="M30 62h40v22H30z"/>
|
||||
<path d="M38 70h24"/>
|
||||
<circle cx="72" cy="51" r="3" fill="currentColor" stroke="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 775 B |
17
static/icon-security.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M50 14l30 12v20c0 20-12 33-30 40-18-7-30-20-30-40V26z"/>
|
||||
<path d="M37 51l9 9 18-23"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 664 B |
23
static/icon-service.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
.icon-fill{fill:#ad1d1c;stroke:none}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape">
|
||||
<path d="M30 24h40a6 6 0 0 1 6 6v12H24V30a6 6 0 0 1 6-6z"/>
|
||||
<path d="M24 42h52v28a6 6 0 0 1-6 6H30a6 6 0 0 1-6-6z"/>
|
||||
<path d="M34 34h2M45 34h2M56 34h2"/>
|
||||
<path d="M37 58h26"/>
|
||||
<path d="M50 49v18"/>
|
||||
<path d="M68 54l7 7-7 7"/>
|
||||
<path d="M32 54l-7 7 7 7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 843 B |
18
static/icon-smart.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M34 63c-12-10-11-29 4-39 13-9 34-2 37 15 3 19-16 29-25 40"/>
|
||||
<path d="M36 63h28M39 74h22"/>
|
||||
<path d="M41 39c6-7 15-7 21 0M43 50c5 4 10 4 15 0"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 723 B |
22
static/icon-start.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
.icon-fill{fill:#ad1d1c;stroke:none}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape">
|
||||
<path d="M24 62c0-20 14-38 34-43"/>
|
||||
<path d="M58 19l-6 13 15-4"/>
|
||||
<path d="M28 70h44"/>
|
||||
<path d="M35 80h30"/>
|
||||
<path d="M50 38v18"/>
|
||||
<path d="M41 47l9 9 13-17"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 751 B |
19
static/icon-stations.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<circle cx="50" cy="50" r="8"/>
|
||||
<path d="M35 35a22 22 0 0 0 0 30M65 35a22 22 0 0 1 0 30"/>
|
||||
<path d="M25 25a36 36 0 0 0 0 50M75 25a36 36 0 0 1 0 50"/>
|
||||
<path d="M50 58v22"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 741 B |
18
static/icon-susers.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<circle cx="50" cy="32" r="14"/>
|
||||
<path d="M25 78c3-18 14-28 25-28s22 10 25 28z"/>
|
||||
<path d="M34 78h32"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 673 B |
19
static/icon-users.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<circle cx="38" cy="34" r="12"/>
|
||||
<circle cx="65" cy="36" r="10"/>
|
||||
<path d="M16 78c3-17 12-26 23-26s20 9 23 26z"/>
|
||||
<path d="M52 78c2-12 9-20 18-20 7 0 13 5 16 20z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 734 B |
19
static/icon-volumes.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 100 100" role="img" aria-hidden="true">
|
||||
<style>
|
||||
.icon-bg{fill:url(#g);stroke:#d6bf9c;stroke-width:1.8}
|
||||
.icon-shape{fill:none;stroke:#ad1d1c;stroke-width:5.2;stroke-linecap:round;stroke-linejoin:round}
|
||||
</style>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#fffaf2"/>
|
||||
<stop offset="1" stop-color="#ead9bd"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect class="icon-bg" x="6" y="6" width="88" height="88" rx="20"/>
|
||||
<g class="icon-shape" color="#ad1d1c">
|
||||
<path d="M25 18h50v64H25z"/>
|
||||
<path d="M34 18v24h32V18"/>
|
||||
<path d="M36 64h28"/>
|
||||
<circle cx="66" cy="70" r="4" fill="currentColor" stroke="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 714 B |
441
static/menu.html
@@ -9,47 +9,219 @@
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
|
||||
<link rel="apple-touch-icon" href="/static/apple-touch-icon.png">
|
||||
<style>
|
||||
:root{--bg:#f4f1ea;--panel:#faf8f4;--line:#dfd2bf;--soft:#efe6d7;--text:#3d342c;--muted:#6f6257;--accent:#ad1d1c;--accent2:#c96b3d;--gold:#b9813d;}
|
||||
*{box-sizing:border-box} html,body{margin:0;padding:0;background:var(--bg);color:var(--text);font:15px/1.55 Arial,Helvetica,sans-serif}
|
||||
:root{
|
||||
--bg:#f4f1ea;--panel:#faf8f4;--line:#dfd2bf;--soft:#efe6d7;--text:#3d342c;
|
||||
--muted:#6f6257;--accent:#ad1d1c;--accent2:#c96b3d;--gold:#b9813d;--warm:#d6bf9c;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{margin:0;padding:0;background:var(--bg);color:var(--text);font:15px/1.55 Arial,Helvetica,sans-serif}
|
||||
body{padding:18px}
|
||||
a{color:inherit} code,tt{font-family:"DejaVu Sans Mono",monospace}
|
||||
.shell{max-width:1100px;margin:0 auto}
|
||||
.shell{max-width:1250px;margin:0 auto}
|
||||
.hero{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:22px 24px;border:1px solid var(--line);border-radius:18px;background:linear-gradient(135deg,#a80f18,#c44731 60%,#d79a54);color:#fff;box-shadow:0 12px 30px rgba(64,36,12,.08)}
|
||||
.hero img{height:42px;width:auto;display:block;background:#fff;border-radius:10px;padding:5px;box-shadow:0 8px 20px rgba(0,0,0,.12)}
|
||||
.hero h1{margin:0;font-size:28px;line-height:1.1}
|
||||
.hero p{margin:6px 0 0;font-size:15px;opacity:.95}
|
||||
.grid{margin-top:18px;display:grid;gap:16px}
|
||||
.card{display:block;text-decoration:none;background:var(--panel);border:1px solid var(--line);border-radius:16px;overflow:hidden;box-shadow:0 6px 18px rgba(64,36,12,.04)}
|
||||
.card-header{padding:16px 18px;background:linear-gradient(90deg,#efe7da,#e8dfcf);border-bottom:1px solid var(--line)}
|
||||
.card-title{margin:0;font-size:18px;color:var(--accent)}
|
||||
.card-sub{margin:6px 0 0;color:var(--gold);font-size:12px;text-transform:uppercase;letter-spacing:.12em}
|
||||
.card-body{padding:0}
|
||||
.workspace{margin-top:18px;display:grid;grid-template-columns:180px minmax(0,1fr);gap:18px;align-items:start}
|
||||
.nav-shell{background:var(--panel);border:1px solid var(--line);border-radius:18px;box-shadow:0 6px 18px rgba(64,36,12,.05);padding:12px;position:sticky;top:14px}
|
||||
.nav-title{margin:4px 6px 10px;font-size:13px;text-transform:uppercase;letter-spacing:.12em;color:var(--gold)}
|
||||
.nav-list{display:flex;flex-direction:column;gap:10px}
|
||||
.nav-item{appearance:none;-webkit-appearance:none;width:100%;border:1px solid #e6d8c6;border-radius:16px;background:#fffdf9;color:var(--text);padding:10px 8px;display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;transition:all .16s ease;box-shadow:0 2px 8px rgba(64,36,12,.03)}
|
||||
.nav-item:hover{transform:translateY(-1px);border-color:#d0b089;box-shadow:0 8px 18px rgba(64,36,12,.06)}
|
||||
.nav-item.active{background:linear-gradient(180deg,#fffaf2,#f3e7d4);border-color:#caa46f;box-shadow:0 10px 20px rgba(64,36,12,.08)}
|
||||
.nav-icon{width:52px;height:52px;border-radius:16px;display:flex;align-items:center;justify-content:center;font-size:28px;line-height:1;background:linear-gradient(180deg,#f4eadc,#e4d4bb);border:1px solid #d6bf9c;box-shadow:inset 0 1px 0 rgba(255,255,255,.7)}
|
||||
.nav-item.active .nav-icon{background:linear-gradient(180deg,#d24835,#b62022);color:#fff;border-color:#9f2f26}
|
||||
.nav-label{font-size:12px;line-height:1.25;text-align:center;font-weight:bold;color:#5a4c3f}
|
||||
.detail-shell{background:var(--panel);border:1px solid var(--line);border-radius:18px;box-shadow:0 6px 18px rgba(64,36,12,.05);overflow:hidden;min-height:720px}
|
||||
.detail-topbar{padding:16px 18px;background:linear-gradient(90deg,#efe7da,#e8dfcf);border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:16px}
|
||||
.detail-topbar .left h2{margin:0;font-size:22px;color:var(--accent)}
|
||||
.detail-topbar .left p{margin:4px 0 0;color:var(--muted);font-size:14px}
|
||||
.detail-container{padding:0}
|
||||
.detail-section{display:none}
|
||||
.detail-section.active{display:block}
|
||||
.detail-header-row{padding:16px 18px;background:#fbf7f1;border-bottom:1px solid #eee5d7;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
|
||||
.detail-kicker{margin:0 0 6px;color:var(--gold);font-size:12px;text-transform:uppercase;letter-spacing:.12em}
|
||||
.detail-header-row h2{margin:0;font-size:28px;line-height:1.15;color:#332920}
|
||||
.open-button{display:inline-block;text-decoration:none;border:1px solid #a33d2f;border-radius:10px;padding:8px 14px;background:#b84434;color:#fff;font-weight:bold;white-space:nowrap;box-shadow:0 6px 14px rgba(165,50,36,.16)}
|
||||
.open-button:hover{filter:brightness(.96)}
|
||||
.detail-body{padding:0}
|
||||
.info{padding:16px 18px;border-top:1px solid #eee5d7}
|
||||
.info:first-child{border-top:0}
|
||||
.info h3{margin:0 0 8px;font-size:15px;color:#8b4a1d}
|
||||
.info p,.info ul,.info ol{margin:0 0 10px;color:var(--muted)}
|
||||
.info p:last-child,.info ul:last-child,.info ol:last-child{margin-bottom:0}
|
||||
.info p,.info ul,.info ol,.info div{margin:0 0 10px;color:var(--muted)}
|
||||
.info p:last-child,.info ul:last-child,.info ol:last-child,.info div:last-child{margin-bottom:0}
|
||||
.info ul,.info ol{padding-left:22px}
|
||||
.note{color:#5f5349}
|
||||
@media (max-width:700px){body{padding:12px}.hero{padding:18px;align-items:flex-start;flex-direction:column}.hero img{height:36px}.card-header{padding:14px 16px}.info{padding:14px 16px}}
|
||||
.tipbar{padding:10px 18px;border-top:1px solid #eadfce;background:#fffaf4;color:#80695a;font-size:13px}
|
||||
@media (max-width:980px) {
|
||||
.workspace{grid-template-columns:1fr;}
|
||||
.nav-shell{position:static}
|
||||
.nav-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:10px}
|
||||
.detail-shell{min-height:auto}
|
||||
}
|
||||
@media (max-width:700px){
|
||||
body{padding:12px}
|
||||
.hero{padding:18px;align-items:flex-start;flex-direction:column}
|
||||
.hero img{height:36px}
|
||||
.detail-topbar,.detail-header-row{padding:14px 16px}
|
||||
.info{padding:14px 16px}
|
||||
.detail-header-row{flex-direction:column}
|
||||
}
|
||||
|
||||
.nav-icon{background:none;border:0;box-shadow:none}
|
||||
.nav-icon img{width:58px;height:58px;display:block;filter:drop-shadow(0 4px 8px rgba(64,36,12,.10))}
|
||||
.nav-item.active .nav-icon{background:none;color:inherit;border:0}
|
||||
.nav-item.active .nav-icon img{filter:drop-shadow(0 6px 12px rgba(173,29,28,.22))}
|
||||
|
||||
.setup-first .detail-header-row{background:linear-gradient(90deg,#fff7ec,#f1dfc6)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="hero">
|
||||
<div>
|
||||
<h1>Main menu</h1>
|
||||
<p>SMArT configuration navigation with the original explanations preserved.</p>
|
||||
<div class="hero">
|
||||
<div>
|
||||
<h1>Main menu</h1>
|
||||
<p>Choose a section from the icon list. The explanation opens here on the left, and the editor opens on the right.</p>
|
||||
</div>
|
||||
<img src="/static/smart_icon.jpg" alt="SMArT logo">
|
||||
</div>
|
||||
<img src="/static/smart_icon.jpg" alt="SMArT logo">
|
||||
</div>
|
||||
<div class="grid">
|
||||
<a class="card" href="/settings/general" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">General settings</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
|
||||
<div class="workspace">
|
||||
<aside class="nav-shell">
|
||||
<div class="nav-title">Sections</div>
|
||||
<div class="nav-list">
|
||||
<button class="nav-item active" type="button" data-target="setup-first" data-href="/settings/smart" aria-pressed="true" title="Setup first">
|
||||
<span class="nav-icon icon-start"><img src="/static/icon-start.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Setup first</span>
|
||||
</button>
|
||||
<button class="nav-item" type="button" data-target="mars-nwe-service" data-href="/static/start.html" aria-pressed="false" title="MARS_NWE service">
|
||||
<span class="nav-icon icon-service"><img src="/static/icon-service.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">MARS_NWE service</span>
|
||||
</button>
|
||||
<button class="nav-item" type="button" data-target="general-settings" data-href="/settings/general" aria-pressed="false" title="General settings">
|
||||
<span class="nav-icon icon-general"><img src="/static/icon-general.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">General settings</span>
|
||||
</button><button class="nav-item" type="button" data-target="directories" data-href="/settings/dirs" aria-pressed="false" title="Directories">
|
||||
<span class="nav-icon icon-dirs"><img src="/static/icon-dirs.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Directories</span>
|
||||
</button><button class="nav-item" type="button" data-target="precompiled-settings" data-href="/settings/configh" aria-pressed="false" title="Precompiled settings">
|
||||
<span class="nav-icon icon-configh"><img src="/static/icon-configh.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Precompiled settings</span>
|
||||
</button><button class="nav-item" type="button" data-target="security" data-href="/settings/security" aria-pressed="false" title="Security">
|
||||
<span class="nav-icon icon-security"><img src="/static/icon-security.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Security</span>
|
||||
</button><button class="nav-item" type="button" data-target="user-configuration" data-href="/settings/susers" aria-pressed="false" title="User configuration">
|
||||
<span class="nav-icon icon-susers"><img src="/static/icon-susers.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">User configuration</span>
|
||||
</button><button class="nav-item" type="button" data-target="volumes" data-href="/settings/volumes" aria-pressed="false" title="Volumes">
|
||||
<span class="nav-icon icon-volumes"><img src="/static/icon-volumes.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Volumes</span>
|
||||
</button><button class="nav-item" type="button" data-target="devices" data-href="/settings/devices" aria-pressed="false" title="Devices">
|
||||
<span class="nav-icon icon-devices"><img src="/static/icon-devices.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Devices</span>
|
||||
</button><button class="nav-item" type="button" data-target="logging" data-href="/settings/logging" aria-pressed="false" title="Logging">
|
||||
<span class="nav-icon icon-logging"><img src="/static/icon-logging.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Logging</span>
|
||||
</button><button class="nav-item" type="button" data-target="smart-settings" data-href="/settings/smart" aria-pressed="false" title="SMArT settings">
|
||||
<span class="nav-icon icon-smart"><img src="/static/icon-smart.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">SMArT settings</span>
|
||||
</button><button class="nav-item" type="button" data-target="stations-access-control" data-href="/settings/advanced/stations" aria-pressed="false" title="Stations / access control">
|
||||
<span class="nav-icon icon-stations"><img src="/static/icon-stations.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Stations / access control</span>
|
||||
</button><button class="nav-item" type="button" data-target="users" data-href="/settings/users" aria-pressed="false" title="Users">
|
||||
<span class="nav-icon icon-users"><img src="/static/icon-users.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Users</span>
|
||||
</button><button class="nav-item" type="button" data-target="groups" data-href="/settings/groups" aria-pressed="false" title="Groups">
|
||||
<span class="nav-icon icon-groups"><img src="/static/icon-groups.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Groups</span>
|
||||
</button><button class="nav-item" type="button" data-target="print-queues" data-href="/settings/queues" aria-pressed="false" title="Print queues">
|
||||
<span class="nav-icon icon-queues"><img src="/static/icon-queues.svg" alt="" aria-hidden="true"></span>
|
||||
<span class="nav-label">Print queues</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="detail-shell">
|
||||
<div class="detail-topbar">
|
||||
<div class="left">
|
||||
<h2 id="panel-title">Setup first</h2>
|
||||
<p>Explanation on the left, editor opens in the right pane.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-container">
|
||||
<section class="detail-section active setup-first" id="detail-setup-first" data-href="/settings/smart" data-title="Setup first">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">First step</div>
|
||||
<h2>Setup first</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/smart" target="OPTS">Open SMArT settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<h3>Fill SMArT settings first</h3>
|
||||
<div class="note">Before editing users, groups, bindery objects, trustees or print queues, configure the SMArT settings first.</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h3>Bindery / Supervisor access</h3>
|
||||
<div class="note">SMArT needs the NetWare bindery server name, the supervisor login and the supervisor password. Use the supervisor password that is configured for your MARS_NWE server in <tt>nwserv.conf</tt>. Without this, SMArT can still show configuration pages, but operations which talk to the running server can fail.</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h3>Why this matters</h3>
|
||||
<div class="note">User, group and trustee actions use the MARS_NWE tools against the bindery. If the bindery credentials are missing or wrong, SMArT cannot reliably create objects, update memberships, set passwords or modify trustees.</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h3>Recommended order</h3>
|
||||
<div class="note">
|
||||
<ol>
|
||||
<li>Open <b>SMArT settings</b>.</li>
|
||||
<li>Set the <tt>nwserv.conf</tt> path if needed.</li>
|
||||
<li>Enter bindery server, supervisor user and supervisor password.</li>
|
||||
<li>Save, then continue with users, groups, volumes, trustees and queues.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="detail-section" id="detail-mars-nwe-service" data-href="/static/start.html" data-title="MARS_NWE service">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Service control</div>
|
||||
<h2>MARS_NWE service</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/static/start.html" target="OPTS">Open start page</a>
|
||||
</div>
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<h3>Start, stop, restart and status</h3>
|
||||
<div class="note">Use this page to control the systemd service for the running MARS_NWE server.</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h3>Available actions</h3>
|
||||
<div class="note">
|
||||
<ul>
|
||||
<li><tt>status</tt> shows the current service state.</li>
|
||||
<li><tt>start</tt> starts the MARS_NWE service.</li>
|
||||
<li><tt>stop</tt> waits until the service is really stopped.</li>
|
||||
<li><tt>restart</tt> restarts the service and then shows the final status.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h3>When to use it</h3>
|
||||
<div class="note">After changing <tt>nwserv.conf</tt>, restart the service so the server reloads the changed configuration. Use the start page buttons on the right to run start, stop, restart or status.</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="detail-section" id="detail-general-settings" data-href="/settings/general" data-title="General settings">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>General settings</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/general" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<h3>Servername</h3>
|
||||
<div class="note">The servername is the name under which this server will show up when using
|
||||
@@ -119,39 +291,45 @@ Don't ask me what they mean, but they're hexadecimal, so don't forget to
|
||||
prepend <tt>0x</tt>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/dirs" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Directories</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-directories" data-href="/settings/dirs" data-title="Directories">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Directories</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/dirs" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">Some directories for MARS_NWE files.
|
||||
The path cache directory is needed for Client-32 and the namespace calls,
|
||||
the spool directory is used for internal print queue handling.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/configh" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Precompiled settings</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-precompiled-settings" data-href="/settings/configh" data-title="Precompiled settings">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Precompiled settings</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/configh" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">When you just leave these fields empty, the values in your <tt>config.h</tt>
|
||||
file will be used. If you want to change those settings without recompiling
|
||||
<tt>MARS_NWE</tt>, you can change them here.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/security" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Security</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-security" data-href="/settings/security" data-title="Security">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Security</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/security" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<h3>Modes</h3>
|
||||
<div class="note">Here you can change the standard modes for new files and directories.
|
||||
@@ -170,13 +348,15 @@ not-encrypted sending of passwords over the net.<br/>
|
||||
On the Linux-side, passwords will only be stored in encrypted format.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/susers" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">User configuration</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-user-configuration" data-href="/settings/susers" data-title="User configuration">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>User configuration</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/susers" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<h3>Guest user</h3>
|
||||
<div class="note">Here you can set the UID a user will get before logging in.</div>
|
||||
@@ -217,13 +397,15 @@ Only those Linux-logins will handled automatically that don't have a
|
||||
x or asterisk as their encrypted password.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/volumes" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Volumes</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-volumes" data-href="/settings/volumes" data-title="Volumes">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Volumes</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/volumes" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">The OS/2 additional namespace can be used by Windows 9x too. The
|
||||
'no fixed i-nodes' option is necessary when exporting DOS or CD-ROM
|
||||
@@ -233,13 +415,15 @@ For more information about pipe filesystems you can take a look at
|
||||
MARS_NWE's documentation directory.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/devices" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Devices</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-devices" data-href="/settings/devices" data-title="Devices">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Devices</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/devices" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">This section contains information for the ipx-router built into mars_nwe
|
||||
and/or the external program <tt>nwrouted</tt>.<br/>
|
||||
@@ -289,13 +473,15 @@ in internal device/routing table at runtime.<br/>
|
||||
<b>You don't have to set this in FreeBSD!</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/logging" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Logging</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-logging" data-href="/settings/logging" data-title="Logging">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Logging</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/logging" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">MARS_NWE can keep a log file with error messages, click here to set what
|
||||
kind of messages must be logged and where.<br/>
|
||||
@@ -305,48 +491,69 @@ According to <tt>nwserv.conf</tt>, the NWCLIENT tag must always be set
|
||||
to <i>No debugging</i>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/smart" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">SMArT settings</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-smart-settings" data-href="/settings/smart" data-title="SMArT settings">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>SMArT settings</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/smart" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">Some things have to be configured here before you can use SMArT.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/users" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Users</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-stations-access-control" data-href="/settings/advanced/stations" data-title="Stations / access control">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Stations / access control</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/advanced/stations" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">Configure station file based nearest-server and connection replies.</div>
|
||||
</div>
|
||||
</div>
|
||||
</section><section class="detail-section" id="detail-users" data-href="/settings/users" data-title="Users">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Users</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/users" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">You can edit the userlist from the bindery files here. This option will not
|
||||
change anything to the <tt>nwserv.conf</tt> configuration file.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/groups" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Groups</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-groups" data-href="/settings/groups" data-title="Groups">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Groups</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/groups" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">You can edit the group list from the bindery files here. This option will not
|
||||
change anything to the <tt>nwserv.conf</tt> configuration file.</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="/settings/queues" target="OPTS">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Print queues</h2>
|
||||
<div class="card-sub">Open settings</div>
|
||||
</section><section class="detail-section" id="detail-print-queues" data-href="/settings/queues" data-title="Print queues">
|
||||
<div class="detail-header-row">
|
||||
<div>
|
||||
<div class="detail-kicker">Section</div>
|
||||
<h2>Print queues</h2>
|
||||
</div>
|
||||
<a class="open-button" href="/settings/queues" target="OPTS">Open settings</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-body">
|
||||
<div class="info">
|
||||
<div class="note">Here you can edit the list of print queues. The things you have to fill in are:
|
||||
<ol>
|
||||
@@ -366,8 +573,58 @@ default directory.
|
||||
</li></li></li></ol></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="tipbar">Tip: click an icon on the left to switch topics. The corresponding settings page is opened automatically in the editor pane on the right.</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
function openInEditor(href) {
|
||||
try {
|
||||
if (window.parent && window.parent.frames && window.parent.frames['OPTS']) {
|
||||
window.parent.frames['OPTS'].location = href;
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
window.open(href, 'OPTS');
|
||||
}
|
||||
|
||||
function activate(target, openEditor) {
|
||||
var buttons = document.querySelectorAll('.nav-item');
|
||||
var sections = document.querySelectorAll('.detail-section');
|
||||
buttons.forEach(function(btn) {
|
||||
var active = btn.getAttribute('data-target') === target;
|
||||
btn.classList.toggle('active', active);
|
||||
btn.setAttribute('aria-pressed', active ? 'true' : 'false');
|
||||
});
|
||||
sections.forEach(function(sec) {
|
||||
sec.classList.toggle('active', sec.id === 'detail-' + target);
|
||||
});
|
||||
var activeSection = document.getElementById('detail-' + target);
|
||||
if (activeSection) {
|
||||
var title = activeSection.getAttribute('data-title') || '';
|
||||
var href = activeSection.getAttribute('data-href') || '';
|
||||
var titleNode = document.getElementById('panel-title');
|
||||
if (titleNode) titleNode.textContent = title;
|
||||
if (openEditor && href) openInEditor(href);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.nav-item').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
activate(btn.getAttribute('data-target'), true);
|
||||
});
|
||||
});
|
||||
|
||||
// Load the first section into the editor on first view.
|
||||
var first = document.querySelector('.nav-item.active') || document.querySelector('.nav-item');
|
||||
if (first) {
|
||||
activate(first.getAttribute('data-target'), true);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||