v1
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<html lang="{{ session.get('language', 'ru') }}">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>MyHoreca OLAPer</title>
|
||||
<title>{{ _('MyHoreca OLAPer') }}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>MyHoreca OLAP-to-GoogleSheets</h1>
|
||||
<h1>{{ _('MyHoreca OLAP-to-GoogleSheets') }}</h1>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="user-info">
|
||||
Logged in as: <strong>{{ current_user.username }}</strong> |
|
||||
<a href="{{ url_for('logout') }}">Logout</a>
|
||||
{{ _('Logged in as:') }} <strong>{{ current_user.username }}</strong> |
|
||||
<a href="{{ url_for('.logout') }}">{{ _('Logout') }}</a>
|
||||
<span class="lang-switcher">
|
||||
<a href="{{ url_for('.set_language', language='ru') }}" title="{{ _('Русский') }}">🇷🇺</a> /
|
||||
<a href="{{ url_for('.set_language', language='en') }}" title="{{ _('English') }}">🇬🇧</a>
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="user-info">
|
||||
<a href="{{ url_for('login') }}">Login</a> |
|
||||
<a href="{{ url_for('register') }}">Register</a>
|
||||
<a href="{{ url_for('.login') }}">{{ _('Login') }}</a> |
|
||||
<a href="{{ url_for('.register') }}">{{ _('Register') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -34,105 +38,105 @@
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="container">
|
||||
<!-- Секция RMS-сервера -->
|
||||
<button type="button" class="collapsible">1. Connection to RMS-server</button>
|
||||
<button type="button" class="collapsible">1. {{ _('Connection to RMS-server') }}</button>
|
||||
<div class="content">
|
||||
<h3>RMS Server Configuration</h3>
|
||||
<h3>{{ _('RMS Server Configuration') }}</h3>
|
||||
<p>
|
||||
Enter the details for your RMS server API. This information is used to connect,
|
||||
authenticate, and retrieve the list of available OLAP report presets.
|
||||
{% trans %}Enter the details for your RMS server API. This information is used to connect,
|
||||
authenticate, and retrieve the list of available OLAP report presets.{% endtrans %}
|
||||
</p>
|
||||
<form action="{{ url_for('configure_rms') }}" method="post">
|
||||
<label for="host">RMS-host (e.g., http://your-rms-api.com/resto):</label>
|
||||
<form action="{{ url_for('.configure_rms') }}" method="post">
|
||||
<label for="host">{{ _('RMS-host (e.g., http://your-rms-api.com/resto):') }}</label>
|
||||
<input type="text" id="host" name="host" value="{{ rms_config.get('host', '') }}" required /><br />
|
||||
|
||||
<label for="login">API Login:</label>
|
||||
<label for="login">{{ _('API Login:') }}</label>
|
||||
<input type="text" id="login" name="login" value="{{ rms_config.get('login', '') }}" required /><br />
|
||||
|
||||
<label for="password">API Password (enter if you want to change):</label>
|
||||
<input type="password" id="password" name="password" value="" {% if not rms_config.get('password') %}required{% endif %} /><br />
|
||||
{% if rms_config.get('password') %}
|
||||
<small>Password is saved and will be used. Enter only if you need to change it.</small><br/>
|
||||
<label for="password">{{ _('API Password:') }}</label>
|
||||
<input type="password" id="password" name="password" value="" {% if not rms_config.password_is_set %}required{% endif %} /><br />
|
||||
{% if rms_config.password_is_set %}
|
||||
<small>{{ _('Password is saved. Enter a new one only if you need to change it.') }}</small><br/>
|
||||
{% else %}
|
||||
<small>Enter the API password for your RMS server.</small><br/>
|
||||
<small>{{ _('Enter the API password for your RMS server.') }}</small><br/>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit">Check and Save RMS-config</button>
|
||||
<button type="submit">{{ _('Check and Save RMS-config') }}</button>
|
||||
</form>
|
||||
{% if presets %}
|
||||
<p><strong>Status:</strong> Successfully connected to RMS. Found {{ presets|length }} OLAP presets.</p>
|
||||
<p><strong>{{ _('Status:') }}</strong> {% trans num=presets|length %}Successfully connected to RMS. Found %(num)s OLAP presets.{% endtrans %}</p>
|
||||
{% elif rms_config.get('host') %}
|
||||
<p><strong>Status:</strong> RMS configuration saved. Presets not yet loaded or connection failed.</p>
|
||||
<p><strong>{{ _('Status:') }}</strong> {{ _('RMS configuration saved. Presets not yet loaded or connection failed.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Секция Google-таблиц -->
|
||||
<button type="button" class="collapsible" {% if not rms_config.get('host') %}disabled title="Configure RMS first"{% endif %}>
|
||||
2. Google Sheets Configuration
|
||||
<button type="button" class="collapsible" {% if not rms_config.get('host') %}disabled title="{{ _('Configure RMS first') }}"{% endif %}>
|
||||
2. {{ _('Google Sheets Configuration') }}
|
||||
</button>
|
||||
<div class="content">
|
||||
<h3>Google Sheets Configuration</h3>
|
||||
<h3>{{ _('Google Sheets Configuration') }}</h3>
|
||||
<p>
|
||||
To allow the application to write to your Google Sheet, you need to provide
|
||||
{% trans %}To allow the application to write to your Google Sheet, you need to provide
|
||||
credentials for a Google Service Account. This account will act on behalf
|
||||
of the application.
|
||||
of the application.{% endtrans %}
|
||||
</p>
|
||||
<p>
|
||||
<strong>How to get credentials:</strong>
|
||||
<br>1. Go to Google Cloud Console.
|
||||
<br>2. Create a new project or select an existing one.
|
||||
<br>3. Enable the "Google Sheets API" and "Google Drive API" for the project.
|
||||
<br>4. Go to "Credentials", click "Create Credentials", choose "Service Account".
|
||||
<br>5. Give it a name, grant it necessary permissions (e.g., Editor role for simplicity, or more granular roles for Sheets/Drive).
|
||||
<br>6. Create a JSON key for the service account. Download this file.
|
||||
<br>7. Share your target Google Sheet with the service account's email address (found in the downloaded JSON file, key `client_email`).
|
||||
<strong>{{ _('How to get credentials:') }}</strong>
|
||||
<br>1. {{ _('Go to Google Cloud Console.') }}
|
||||
<br>2. {{ _('Create a new project or select an existing one.') }}
|
||||
<br>3. {{ _('Enable the "Google Sheets API" and "Google Drive API" for the project.') }}
|
||||
<br>4. {{ _('Go to "Credentials", click "Create Credentials", choose "Service Account".') }}
|
||||
<br>5. {{ _('Give it a name and grant it the "Editor" role.') }}
|
||||
<br>6. {{ _('Create a JSON key for the service account and download the file.') }}
|
||||
<br>7. {% trans %}Share your target Google Sheet with the service account's email address (found in the downloaded JSON file, key `client_email`).{% endtrans %}
|
||||
</p>
|
||||
<form action="{{ url_for('upload_credentials') }}" method="post" enctype="multipart/form-data">
|
||||
<label for="cred_file">Service Account Credentials (JSON file):</label>
|
||||
<input type="file" id="cred_file" name="cred_file" accept=".json" {% if not google_config.get('cred_file') %}required{% endif %} /><br />
|
||||
<form action="{{ url_for('.upload_credentials') }}" method="post" enctype="multipart/form-data">
|
||||
<label for="cred_file">{{ _('Service Account Credentials (JSON file):') }}</label>
|
||||
<input type="file" id="cred_file" name="cred_file" accept=".json" /><br />
|
||||
{% if client_email %}
|
||||
<p><strong>Current Service Account Email:</strong> <code>{{ client_email }}</code></p>
|
||||
<small>Upload a new file only if you need to change credentials.</small><br/>
|
||||
<p><strong>{{ _('Current Service Account Email:') }}</strong> <code>{{ client_email }}</code></p>
|
||||
<small>{{ _('Upload a new file only if you need to change credentials.') }}</small><br/>
|
||||
{% else %}
|
||||
<small>Upload the JSON file downloaded from Google Cloud Console.</small><br/>
|
||||
<small>{{ _('Upload the JSON file downloaded from Google Cloud Console.') }}</small><br/>
|
||||
{% endif %}
|
||||
<button type="submit">Upload Credentials</button>
|
||||
<button type="submit">{{ _('Upload Credentials') }}</button>
|
||||
</form>
|
||||
<hr>
|
||||
<p>
|
||||
Enter the URL of the Google Sheet you want to use. The service account email
|
||||
(shown above after uploading credentials) must have edit access to this sheet.
|
||||
{% trans %}Enter the URL of the Google Sheet you want to use. The service account email
|
||||
(shown above after uploading credentials) must have edit access to this sheet.{% endtrans %}
|
||||
</p>
|
||||
<form action="{{ url_for('configure_google') }}" method="post">
|
||||
<label for="sheet_url">Google Sheet URL:</label>
|
||||
<form action="{{ url_for('.configure_google') }}" method="post">
|
||||
<label for="sheet_url">{{ _('Google Sheet URL:') }}</label>
|
||||
<input type="text" id="sheet_url" name="sheet_url" value="{{ google_config.get('sheet_url', '') }}" required placeholder="https://docs.google.com/spreadsheets/d/..."/>
|
||||
<button type="submit" {% if not client_email %}disabled title="Upload Service Account Credentials first"{% endif %}>
|
||||
Connect Google Sheets
|
||||
<button type="submit" {% if not client_email %}disabled title="{{ _('Upload Service Account Credentials first') }}"{% endif %}>
|
||||
{{ _('Connect Google Sheets') }}
|
||||
</button>
|
||||
{% if sheets %}
|
||||
<p><strong>Status:</strong> Successfully connected to Google Sheet. Found {{ sheets|length }} worksheets.</p>
|
||||
<p><strong>{{ _('Status:') }}</strong> {% trans num=sheets|length %}Successfully connected to Google Sheet. Found %(num)s worksheets.{% endtrans %}</p>
|
||||
{% elif google_config.get('sheet_url') %}
|
||||
<p><strong>Status:</strong> Google Sheet URL saved. Worksheets not yet loaded or connection failed.</p>
|
||||
<p><strong>{{ _('Status:') }}</strong> {{ _('Google Sheet URL saved. Worksheets not yet loaded or connection failed.') }}</p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Секция сопоставления листов-отчетов -->
|
||||
<button type="button" class="collapsible" {% if not sheets or not presets %}disabled title="Configure RMS and Google Sheets first"{% endif %}>
|
||||
3. Mapping Sheets to OLAP Reports
|
||||
<button type="button" class="collapsible" {% if not sheets or not presets %}disabled title="{{ _('Configure RMS and Google Sheets first') }}"{% endif %}>
|
||||
3. {{ _('Mapping Sheets to OLAP Reports') }}
|
||||
</button>
|
||||
<div class="content">
|
||||
<h3>Map Worksheets to OLAP Reports</h3>
|
||||
<h3>{{ _('Map Worksheets to OLAP Reports') }}</h3>
|
||||
<p>
|
||||
Select which OLAP report from RMS should be rendered into each specific worksheet
|
||||
(tab) in your Google Sheet.
|
||||
{% trans %}Select which OLAP report from RMS should be rendered into each specific worksheet
|
||||
(tab) in your Google Sheet.{% endtrans %}
|
||||
</p>
|
||||
{% if sheets and presets %}
|
||||
<form action="{{ url_for('mapping_set') }}" method="post">
|
||||
<form action="{{ url_for('.mapping_set') }}" method="post">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Worksheet (Google Sheets)</th>
|
||||
<th>OLAP-report (RMS)</th>
|
||||
<th>{{ _('Worksheet (Google Sheets)') }}</th>
|
||||
<th>{{ _('OLAP-report (RMS)') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -140,9 +144,8 @@
|
||||
<tr>
|
||||
<td>{{ sheet.title }}</td>
|
||||
<td>
|
||||
<!-- Use sheet.id for unique name -->
|
||||
<select name="sheet_{{ sheet.id }}">
|
||||
<option value="">-- Not set --</option>
|
||||
<option value="">-- {{ _('Not set') }} --</option>
|
||||
{% for preset in presets %}
|
||||
<option value="{{ preset['id'] }}" {% if mappings.get(sheet.title) == preset['id'] %}selected{% endif %}>
|
||||
{{ preset['name'] }} ({{ preset['id'] }})
|
||||
@@ -154,58 +157,53 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit">Save Mappings</button>
|
||||
<button type="submit">{{ _('Save Mappings') }}</button>
|
||||
</form>
|
||||
{% elif not sheets and not presets %}
|
||||
<p>Worksheets and OLAP presets are not loaded. Please configure RMS and Google Sheets first.</p>
|
||||
<p>{{ _('Worksheets and OLAP presets are not loaded. Please configure RMS and Google Sheets first.') }}</p>
|
||||
{% elif not sheets %}
|
||||
<p>Worksheets are not loaded. Check Google Sheets configuration.</p>
|
||||
<p>{{ _('Worksheets are not loaded. Check Google Sheets configuration.') }}</p>
|
||||
{% elif not presets %}
|
||||
<p>OLAP presets are not loaded. Check RMS configuration.</p>
|
||||
<p>{{ _('OLAP presets are not loaded. Check RMS configuration.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Секция отрисовки отчетов на листах -->
|
||||
<button type="button" class="collapsible" {% if not mappings or mappings|length == 0 %}disabled title="Configure Mappings first"{% endif %}>
|
||||
4. Render Reports to Sheets
|
||||
<button type="button" class="collapsible" {% if not mappings or mappings|length == 0 %}disabled title="{{ _('Configure Mappings first') }}"{% endif %}>
|
||||
4. {{ _('Render Reports to Sheets') }}
|
||||
</button>
|
||||
<div class="content">
|
||||
<h3>Render Reports</h3>
|
||||
<h3>{{ _('Render Reports') }}</h3>
|
||||
<p>
|
||||
Select the date range and click "Render to sheet" for each mapping you wish to execute.
|
||||
{% trans %}Select the date range and click "Render to sheet" for each mapping you wish to execute.
|
||||
The application will retrieve the OLAP data from RMS for the selected report and period,
|
||||
clear the corresponding worksheet in Google Sheets, and write the new data.
|
||||
clear the corresponding worksheet in Google Sheets, and write the new data.{% endtrans %}
|
||||
</p>
|
||||
{% if mappings and mappings|length > 0 %}
|
||||
<form action="{{ url_for('render_olap') }}" method="post">
|
||||
<label for="start_date">From Date:</label>
|
||||
<form action="{{ url_for('.render_olap') }}" method="post">
|
||||
<label for="start_date">{{ _('From Date:') }}</label>
|
||||
<input type="date" id="start_date" name="start_date" required /><br />
|
||||
|
||||
<label for="end_date">To Date:</label>
|
||||
<label for="end_date">{{ _('To Date:') }}</label>
|
||||
<input type="date" id="end_date" name="end_date" required /><br />
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Worksheet</th>
|
||||
<th>Mapped OLAP Report</th>
|
||||
<th>Action</th>
|
||||
<th>{{ _('Worksheet') }}</th>
|
||||
<th>{{ _('Mapped OLAP Report') }}</th>
|
||||
<th>{{ _('Action') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{# Iterate through sheets loaded from Google, check for mapping #}
|
||||
{% for sheet in sheets %}
|
||||
{% set report_id = mappings.get(sheet.title) %}
|
||||
{% if report_id %} {# Only display rows with a valid mapping #}
|
||||
{# Find the preset name by ID using Jinja filters #}
|
||||
{# Find the preset dictionary where 'id' attribute equals report_id #}
|
||||
{% if report_id %}
|
||||
{% set matching_presets = presets | selectattr('id', 'equalto', report_id) | list %}
|
||||
{% set preset_name = 'ID: ' + report_id %} {# Default display if preset not found or unnamed #}
|
||||
|
||||
{# If a matching preset was found, get its name #}
|
||||
{% set preset_name = _('ID: ') + report_id %}
|
||||
{% if matching_presets %}
|
||||
{% set preset = matching_presets[0] %}
|
||||
{% set preset_name = preset.get('name', 'Unnamed Preset') %}
|
||||
{% set preset_name = preset.get('name', _('Unnamed Preset')) %}
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
@@ -213,7 +211,7 @@
|
||||
<td>{{ preset_name }}</td>
|
||||
<td>
|
||||
<button type="submit" name="render_{{ sheet.title }}">
|
||||
Render to sheet
|
||||
{{ _('Render to sheet') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -223,8 +221,8 @@
|
||||
</table>
|
||||
</form>
|
||||
{% else %}
|
||||
<p>No mappings configured yet.</p>
|
||||
<p><small>Please go to the "Mapping Sheets to OLAP Reports" section (Step 3) to set up mappings.</small></p>
|
||||
<p>{{ _('No mappings configured yet.') }}</p>
|
||||
<p><small>{{ _('Please go to the "Mapping Sheets to OLAP Reports" section (Step 3) to set up mappings.') }}</small></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -235,56 +233,27 @@
|
||||
var coll = document.getElementsByClassName("collapsible");
|
||||
for (var i = 0; i < coll.length; i++) {
|
||||
coll[i].addEventListener("click", function () {
|
||||
// Не переключать, если кнопка отключена
|
||||
if (this.disabled) return;
|
||||
// Не выполнять действие, если кнопка отключена
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.toggle("active");
|
||||
var content = this.nextElementSibling;
|
||||
if (content.style.display === "block") {
|
||||
content.style.display = "none";
|
||||
|
||||
// Если max-height установлен (т.е. секция открыта), то скрыть ее
|
||||
if (content.style.maxHeight) {
|
||||
content.style.maxHeight = null;
|
||||
} else {
|
||||
content.style.display = "block";
|
||||
// Иначе (секция закрыта), установить max-height равным высоте контента
|
||||
// Это "раскроет" секцию с плавной анимацией
|
||||
content.style.maxHeight = content.scrollHeight + "px";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Optional: Auto-expand sections based on config state?
|
||||
// This requires passing more state from the Flask app to the template.
|
||||
// For now, keep it simple with manual expansion.
|
||||
// window.addEventListener('load', () => {
|
||||
// // Example logic: if RMS configured but Google not, open Google section
|
||||
// const rmsConfigured = '{{ rms_config.get("host") }}' !== '';
|
||||
// const googleCredsExist = '{{ client_email }}' !== '';
|
||||
// const googleSheetUrlSet = '{{ google_config.get("sheet_url") }}' !== '';
|
||||
// // Corrected lines:
|
||||
// const presetsLoaded = {{ (presets|length > 0) | lower }};
|
||||
// const sheetsLoaded = {{ (sheets|length > 0) | lower }};
|
||||
// const mappingsExist = {{ (mappings|length > 0) | lower }};
|
||||
|
||||
// const collapsibles = document.getElementsByClassName("collapsible");
|
||||
|
||||
// if (rmsConfigured && !googleCredsExist) {
|
||||
// // Find and click Google Sheets collapsible
|
||||
// for (let i = 0; i < collapsibles.length; i++) {
|
||||
// if (collapsibles[i].innerText.includes("Google Sheets Configuration")) {
|
||||
// collapsibles[i].click();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// } else if (rmsConfigured && googleCredsExist && googleSheetUrlSet && presetsLoaded && sheetsLoaded && !mappingsExist) {
|
||||
// // Find and click Mapping collapsible
|
||||
// for (let i = 0; i in collapsibles.length; i++) { // <-- Potential typo here, should be <
|
||||
// if (collapsibles[i].innerText.includes("Mapping Sheets to OLAP Reports")) {
|
||||
// collapsibles[i].click();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Add more conditions as needed
|
||||
// });
|
||||
</script>
|
||||
{% else %}
|
||||
<p style="text-align: center; margin-top: 50px;">Please, <a href="{{ url_for('login') }}">login</a> or <a href="{{ url_for('register') }}">register</a></p>
|
||||
<p style="text-align: center; margin-top: 50px;">{{ _('Please,') }} <a href="{{ url_for('.login') }}">{{ _('login') }}</a> {{ _('or') }} <a href="{{ url_for('.register') }}">{{ _('register') }}</a></p>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user