General improvements #92

Merged
jsegarra merged 16 commits from wbuezas/hedera-web-mindshore:feature/GeneralImprovements into 4922-vueMigration 2024-11-25 12:47:25 +00:00
629 changed files with 11920 additions and 36715 deletions

View File

@ -7,12 +7,12 @@ Hedera is the main web page for Verdnatura.
Required dependencies.
- PHP >= 7.0
- Node.js >= 8.0
- Node.js >= 18.0
Launch application for development.
```
$ npm run dev
$ quasar dev
```
Launch project backend.

View File

@ -12,9 +12,20 @@ module.exports = defineConfig({
numTestsKeptInMemory: 0,
video: false,
screenshotOnRunFailure: false,
reporter: 'cypress-mochawesome-reporter',
reporterOptions: {
charts: true,
reportPageTitle: 'Hedera-Web E2E Reporter',
embeddedScreenshots: true,
reportDir: 'src/test/cypress/reports',
inlineAssets: true
},
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
on('after:spec', (spec, results) => {
console.log('Finished running', spec.relative);
console.log('❌spec:', results.stats.failures);
console.log('✅spec:', results.stats.passes);
});
}
}

5
debian/changelog vendored
View File

@ -1,5 +0,0 @@
hedera-web (22.48.2) stable; urgency=low
* Initial Release.
-- Juan Ferrer Toribio <juan@verdnatura.es> Wed, 19 Aug 2015 12:00:00 +0200

1
debian/compat vendored
View File

@ -1 +0,0 @@
10

18
debian/control vendored
View File

@ -1,18 +0,0 @@
Source: hedera-web
Priority: optional
Maintainer: Juan Ferrer Toribio <juan@verdnatura.es>
Build-Depends: build-essential, debhelper, nodejs
Standards-Version: 3.9.3
Section: misc
Homepage: https://verdnatura.es
Vcs-Git: https://gitea.verdnatura.es/verdnatura/hedera-web
Package: hedera-web
Architecture: all
Depends: apache2 | httpd, nodejs, php-cli, php-vn-lib, php-apcu, php-imap, php-soap, libphp-phpmailer, php-gd, php-pear
Suggests: php-text-captcha, php-zip, cron
Section: misc
Priority: optional
Description: Verdnatura's web page
Web page used by Verdnatura, it includes user authetication, a simple CMS and
a webpshop.

24
debian/copyright vendored
View File

@ -1,24 +0,0 @@
Format: http://dep.debian.net/deps/dep5
Name: hedera-web
Source: https://gitea.verdnatura.es/verdnatura/hedera-web
Files: *
Copyright: 2011-2015 Juan Ferrer Toribio <juan@verdnatura.es>
License: GPL-3.0+
License: GPL-3.0+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public
License can be found in "/usr/share/common-licenses/GPL-3".

10
debian/cron.d vendored
View File

@ -1,10 +0,0 @@
MAILTO=webmaster
*/1 * * * * root hedera-web.php -m misc/mail
*/4 * * * * root hedera-web.php -m tpv/confirm-mail
*/2 * * * * root hedera-web.php -m edi/load
0 23 * * * root hedera-web.php -m edi/clean
0 5 * * * root hedera-web.php -m edi/update
0 5 * * * root hedera-web.php -m misc/exchange-rate
0 0 * * * root hedera-web.php -m image/sync
0 1 * * * root /usr/share/hedera-web/utils/image-clean.sh > /dev/null
0 */1 * * * root /usr/share/hedera-web/utils/update-browscap.sh > /dev/null

19
debian/install vendored
View File

@ -1,19 +0,0 @@
apache.conf etc/hedera-web
config.php etc/hedera-web
php.ini etc/hedera-web
web usr/share/php/vn
doc/* usr/share/doc/hedera-web
hedera-web.php usr/share/hedera-web
forms usr/share/hedera-web
image usr/share/hedera-web
js usr/share/hedera-web
pages usr/share/hedera-web
reports usr/share/hedera-web
rest usr/share/hedera-web
utils usr/share/hedera-web
index.php usr/share/hedera-web
package.json usr/share/hedera-web
build usr/share/hedera-web
README.md usr/share/hedera-web
webpack.config.json usr/share/hedera-web
build-deps/node_modules usr/share/hedera-web

3
debian/links vendored
View File

@ -1,3 +0,0 @@
usr/share/hedera-web/hedera-web.php usr/bin/hedera-web.php
etc/hedera-web/apache.conf etc/apache2/conf-available/hedera-web.conf
etc/hedera-web/php.ini etc/php/7.0/apache2/conf.d/99-hedera-web.ini

16
debian/postinst vendored
View File

@ -1,16 +0,0 @@
#!/bin/bash
set -e
/usr/share/hedera-web/utils/update-browscap.sh > /dev/null
if [ -e /usr/share/apache2/apache2-maintscript-helper ]
then
. /usr/share/apache2/apache2-maintscript-helper
apache2_invoke enmod rewrite
apache2_invoke enmod headers
apache2_invoke enconf hedera-web.conf
fi
#service php7.3-fpm restart
#service cron restart

12
debian/postrm vendored
View File

@ -1,12 +0,0 @@
#!/bin/bash
set -e
if [ -e /usr/share/apache2/apache2-maintscript-helper ]
then
. /usr/share/apache2/apache2-maintscript-helper
apache2_invoke disconf hedera-web.conf
fi
#rm -rf /usr/share/hedera-web/node_modules
#service cron restart

18
debian/rules vendored
View File

@ -1,18 +0,0 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
%:
dh $@
clean:
npm run clean
dh_clean $@
build:
npm install --no-audit --prefer-offline
npm --omit=dev run build
mkdir -p build-deps
cp package.json package-lock.json build-deps
(cd build-deps && npm install --omit=dev --no-audit --prefer-offline)

View File

@ -1 +0,0 @@
hedera-web: package-contains-npm-ignore-file

Binary file not shown.

View File

@ -1,43 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,activate() {
this.$.userModel.setInfo('c', 'myClient', 'hedera');
this.$.addresses.setInfo('a', 'myAddress', 'hedera');
}
,onAddAddressClick() {
this.hash.setAll({
form: 'account/address',
address: 0
});
}
,onReturnClick() {
window.history.back();
}
,onSetDefaultClick(event, addressId) {
if (event.defaultPrevented) return;
this.$.defaultAddress.value = addressId;
Htk.Toast.showMessage(_('DefaultAddressModified'));
}
,async onRemoveAddressClick(form) {
if (confirm(_('AreYouSureDeleteAddress'))) {
await form.set('isActive', false);
await form.refresh();
}
}
,onEditAddressClick(address) {
this.hash.setAll({
form: 'account/address',
address
});
}
});

View File

@ -1,8 +0,0 @@
Addresses: Adreces
Return: Tornar
AddAddress: Afegir adreça
SetAsDefault: Establir com per defecte
RemoveAddress: Esborrar direcció
EditAddress: Modificar direcció
AreYouSureDeleteAddress: Estàs segur de que vols eliminar la direcció?
DefaultAddressModified: Adreça per defecte modificada

View File

@ -1,8 +0,0 @@
Addresses: Addresses
Return: Return
AddAddress: Add address
SetAsDefault: Set as default
RemoveAddress: Remove address
EditAddress: Edit address
AreYouSureDeleteAddress: Are you sure you want to delete the address?
DefaultAddressModified: Default address modified

View File

@ -1,8 +0,0 @@
Addresses: Direcciones
Return: Volver
AddAddress: Añadir dirección
SetAsDefault: Establecer como predeterminada
RemoveAddress: Borrar dirección
EditAddress: Modificar dirección
AreYouSureDeleteAddress: ¿Estás seguro de que quieres borrar la dirección?
DefaultAddressModified: Dirección por defecto modificada

View File

@ -1,8 +0,0 @@
Addresses: Adresses
Return: Retour
AddAddress: Ajouter une adresse
SetAsDefault: Définir par défaut
RemoveAddress: Supprimer l'adresse
EditAddress: Changement d'adresse
AreYouSureDeleteAddress: Souhaitez-vous vraiment supprier l'adresse?
DefaultAddressModified: Adresse par défaut modifiée

View File

@ -1,8 +0,0 @@
Addresses: Moradas
Return: Voltar
AddAddress: Adicionar Morada
SetAsDefault: Selecionar como pre-determinado
RemoveAddress: Eliminar Morada
EditAddress: Modificar Morada
AreYouSureDeleteAddress: Tens certeza que queres eliminar esta morada?
DefaultAddressModified: Endereço padrão modificado

View File

@ -1,6 +0,0 @@
hedera-address-list {
.htk-list .side {
padding-right: 16px;
}
}

View File

@ -1,70 +0,0 @@
<vn>
<vn-group>
<db-form id="user-form">
<db-model property="model" id="user-model" updatable="true">
SELECT id, defaultAddressFk
FROM myClient c
</db-model>
</db-form>
<db-model id="addresses" updatable="true">
SELECT a.id, a.nickname, p.name province, a.postalCode,
a.city, a.street, a.isActive
FROM myAddress a
LEFT JOIN vn.province p ON p.id = a.provinceFk
WHERE a.isActive
</db-model>
</vn-group>
<div id="title">
<h1><t>Addresses</t></h1>
</div>
<div id="actions">
<htk-bar-button
icon="add"
tip="_AddAddress"
on-click="this.onAddAddressClick()"/>
</div>
<div id="form" class="hedera-address-list">
<div class="box vn-w-sm">
<htk-radio-group
id="default-address"
column="defaultAddressFk"
form="user-form"/>
<htk-repeater model="addresses" form-id="address" class="htk-list">
<custom>
<div class="item clickable" on-click="this.onSetDefaultClick($event, address.id)">
<div class="side">
<htk-radio
radio-group="default-address"
val="{{address.id}}"
tip="_SetAsDefault"
name="test"/>
</div>
<div class="content">
<p class="important">
{{address.nickname}}
</p>
<p>
{{address.street}}
</p>
<p>
{{address.postalCode}}, {{address.city}}
</p>
</div>
<div
class="actions"
on-click="$event.preventDefault()">
<htk-button
icon="delete"
tip="_RemoveAddress"
on-click="this.onRemoveAddressClick($iter)"/>
<htk-button
icon="edit"
tip="_EditAddress"
on-click="this.onEditAddressClick(address.id)"/>
</div>
</div>
</custom>
</htk-repeater>
</div>
</div>
</vn>

View File

@ -1,20 +0,0 @@
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml'),
activate() {
this.$.model.setInfo('a', 'myAddress', 'hedera', ['id'], 'id');
this.$.model.setDefault('clientFk', 'a',
new Sql.Function({schema: 'account', name: 'myUser_getId'}));
},
onStatusChange() {
if (this.$.iter.ready && this.hash.$.address == 0)
this.$.iter.insertRow();
},
onOperationsDone() {
Htk.Toast.showMessage(_('AddressChangedSuccessfully'));
window.history.back()
}
});

View File

@ -1,10 +0,0 @@
AddEditAddress: Afegir o modificar adreça
Name: Consignatari
Address: Direcció
City: Ciutat
ZipCode: Codi postal
Country: País
Province: Província
Return: Tornar
Accept: Acceptar
AddressChangedSuccessfully: Adreça modificada correctament

View File

@ -1,10 +0,0 @@
AddEditAddress: Add or edit address
Name: Consignee
Address: Address
City: City
ZipCode: Zip code
Country: Country
Province: Province
Return: Return
Accept: Accept
AddressChangedSuccessfully: Address changed successfully

View File

@ -1,10 +0,0 @@
AddEditAddress: Añadir o modificar dirección
Name: Consignatario
Address: Dirección
City: Ciudad
ZipCode: Código postal
Country: País
Province: Provincia
Return: Volver
Accept: Aceptar
AddressChangedSuccessfully: Dirección modificada correctamente

View File

@ -1,10 +0,0 @@
AddEditAddress: Ajouter ou modifier l'adresse
Name: Destinataire
Address: Numéro Rue
City: Ville
ZipCode: Code postal
Country: Pays
Province: Province
Return: Reviens
Accept: Accepter
AddressChangedSuccessfully: Adresse modifié avec succès

View File

@ -1,10 +0,0 @@
AddEditAddress: Adicionar ou modificar morada
Name: Consignatario
Address: Morada
City: Concelho
ZipCode: Código postal
Country: País
Province: Distrito
Return: Voltar
Accept: Aceitar
AddressChangedSuccessfully: Morada modificada corretamente

View File

@ -1,87 +0,0 @@
<vn>
<vn-group>
<vn-lot-query id="params">
<vn-spec name="address" type="Number"/>
</vn-lot-query>
<db-form id="iter" on-status-changed="this.onStatusChange()">
<db-model
id="model"
property="model"
updatable="true"
mode="ON_DEMAND"
lot="params"
on-operations-done="this.onOperationsDone()">
SELECT a.id, a.street, a.nickname, a.city,
a.postalCode, a.provinceFk, p.countryFk
FROM myAddress a
LEFT JOIN vn.province p ON p.id = a.provinceFk
WHERE a.id = #address
</db-model>
</db-form>
</vn-group>
<div id="title">
<h1><t>Configuration</t></h1>
</div>
<div id="actions">
<htk-bar-button
icon="close"
tip="_Return"
on-click="window.history.back()"/>
<htk-bar-button
icon="check"
tip="_Accept"
on-click="iter.performOperations()"/>
</div>
<div id="form" class="hedera-address">
<div class="form box vn-w-sm vn-pa-lg">
<h5 class="vn-mb-md">
<t>AddEditAddress</t>
</h5>
<div class="form-group">
<htk-entry
placeholder="_Name"
form="iter" column="nickname"/>
</div>
<div class="form-group">
<htk-entry
placeholder="_Address"
form="iter" column="street"/>
</div>
<div class="form-group">
<htk-entry
placeholder="_City"
form="iter" column="city"/>
</div>
<div class="form-group">
<htk-entry
placeholder="_ZipCode"
form="iter" column="postalCode"/>
</div>
<div class="form-group">
<htk-combo
placeholder="_Country"
form="iter" column="countryFk"
id="country"
one-way="true"
one-time="true">
<db-model property="model">
SELECT id, country FROM vn.country
ORDER BY country
</db-model>
</htk-combo>
</div>
<div class="form-group">
<htk-combo
placeholder="_Province"
column="provinceFk"
form="iter">
<db-model property="model" lot="country">
SELECT id, name FROM vn.province
WHERE countryFk = #id
ORDER BY name
</db-model>
</htk-combo>
</div>
</div>
</div>
</vn>

View File

@ -1,76 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml'),
activate() {
this.$.userModel.setInfo('c', 'myClient', 'hedera');
this.$.userModel.setInfo('u', 'myUser', 'account');
if (this.hash.$.verificationToken)
this.onPassChangeClick();
}
,onPassChangeClick() {
this.$.oldPassword.value = '';
this.$.newPassword.value = '';
this.$.repeatPassword.value = '';
var verificationToken = this.hash.$.verificationToken;
this.$.oldPassword.style.display = verificationToken ? 'none' : 'block';
this.$.changePassword.show();
if (verificationToken)
this.$.newPassword.focus();
else
this.$.oldPassword.focus();
}
,async onPassModifyClick() {
var oldPassword = this.$.oldPassword.value;
var newPassword = this.$.newPassword.value;
var repeatedPassword = this.$.repeatPassword.value;
if (newPassword == '' && repeatedPassword == '')
throw new Error(_('Passwords empty'));
if (newPassword !== repeatedPassword)
throw new Error(_('Passwords doesn\'t match'));
var verificationToken = this.hash.$.verificationToken;
var params = {newPassword};
let err;
try {
if (verificationToken) {
params.verificationToken = verificationToken;
await this.conn.send('user/restore-password', params);
} else {
let userId = this.gui.user.id;
params.oldPassword = oldPassword;
await this.conn.patch(
`Accounts/${userId}/changePassword`, params);
}
} catch(e) {
err = e;
Htk.Toast.showError(err.message);
if (this.hash.$.verificationToken)
this.$.newPassword.select();
else
this.$.oldPassword.select();
return;
}
this.$.changePassword.hide();
this.hash.unset('verificationToken');
Htk.Toast.showMessage(_('Password changed!'));
this.$.userForm.refresh();
}
,onPassInfoClick() {
this.$.passwordInfo.show();
}
});

View File

@ -1,26 +0,0 @@
Configuration: Configuració
Personal information: Dades personals
Username: Nom d'usuari
Password: Contrasenya
Email: Correu electrònic
Display name: Nom a mostrar
Language: Idioma
Billing: Facturació
Receive invoices by email: Rebre factures per correu electrònic
Old password: Contrasenya antiga
New password: Nova contrasenya
Repeat password: Repetir contrasenya
Requirements: Requisits
Modify: Modificar
Password requirements: Requisits de contrasenya
characters long: caràcters de longitud
alphabetic characters: caràcters alfabètics
capital letters: majúscules
digits: dígits
symbols: símbols
Password changed!: Contrasenya modificada!
Password doesn't meet the requirements: ''
Passwords doesn't match: Les contrasenyes no coincideixen!
Passwords empty: Les contrasenyes en blanc
Addresses: Adreces
Change password: Canvia la contrasenya

View File

@ -1,26 +0,0 @@
Configuration: Configuration
Personal information: Personal information
Username: Username
Password: Password
Email: Email
Display name: Display name
Language: Language
Billing: Billing
Receive invoices by email: Receive invoices by email
Old password: Old password
New password: New password
Repeat password: Repeat password
Requirements: Requirements
Modify: Modify
Password requirements: Password requirements
characters long: characters long
alphabetic characters: alphabetic characters
capital letters: capital letters
digits: digits
symbols: 'symbols. Ej: $%&.'
Password changed!: Password changed!
Password doesn't meet the requirements: 'Password doesn''t meet the requirements, press info button for more details'
Passwords doesn't match: Passwords doesn't match
Passwords empty: Passwords empty
Addresses: Addresses
Change password: Change password

View File

@ -1,28 +0,0 @@
Configuration: Configuración
Personal information: Datos personales
Username: Nombre de usuario
Password: Contraseña
Email: Correo electrónico
Display name: Nombre a mostrar
Language: Idioma
Billing: Facturación
Receive invoices by email: Recibir facturas por correo electrónico
Old password: Contaseña antigua
New password: Nueva contraseña
Repeat password: Repetir contraseña
Requirements: Requisitos
Modify: Modificar
Password requirements: Requisitos de constraseña
characters long: carácteres de longitud
alphabetic characters: carácteres alfabéticos
capital letters: letras mayúsculas
digits: dígitos
symbols: 'símbolos. Ej: $%&.'
Password changed!: ¡Contraseña modificada!
Password doesn't meet the requirements: >-
La nueva contraseña no reune los requisitos de seguridad necesarios, pulsa en
info para más detalle
Passwords doesn't match: ¡Las contraseñas no coinciden!
Passwords empty: Contraseña vacía
Addresses: Direcciones
Change password: Cambiar contraseña

View File

@ -1,26 +0,0 @@
Configuration: Configuration
Personal information: Informations personnelles
Username: Utilisateur
Password: Mot de passe
Email: Courriel
Display name: Nom à afficher
Language: Langage
Billing: Facturation
Receive invoices by email: Recevoir des factures par e-mail
Old password: Ancien mot de passe
New password: Nouveau mot de passe
Repeat password: Répéter le mot de passe
Requirements: Exigences
Modify: Modifier
Password requirements: Mot de passe exigences
characters long: Longs caractères
alphabetic characters: les caractères alphabétiques
capital letters: lettres majuscules
digits: chiffres
symbols: 'symboles. Ej: $%&.'
Password changed!: Mot de passe modifié!
Password doesn't meet the requirements: ''
Passwords doesn't match: Les mots de passe ne correspondent pas!
Passwords empty: ''
Addresses: Adresses
Change password: Changer le mot de passe

View File

@ -1,26 +0,0 @@
Configuration: Configuração
Personal information: Dados pessoais
Username: Nome de usuario
Password: Palavra-passe
Email: E-Mail
Display name: Nome para mostrar
Language: Idioma
Billing: Facturação
Receive invoices by email: Receber facturas por e-mail
Old password: Palavra-passe antiga
New password: Nova Palavra-passe
Repeat password: Repetir Palavra-passe
Requirements: Requisitos
Modify: Modificar
Password requirements: Requisitos de Palavra-passe
characters long: caracteres
alphabetic characters: caracteres alfabéticos
capital letters: letras maiúsculas
digits: dígitos
symbols: 'símbolos. Ej: $%&.'
Password changed!: Palavra-passe Modificada!
Password doesn't meet the requirements: Palavra-passe não atende aos requisitos
Passwords doesn't match: As Palavras-Passe não coincidem!
Passwords empty: Palavra-passe vazia
Addresses: Moradas
Change password: Mudar Palavra-passe

View File

@ -1,4 +0,0 @@
.pass-info ul {
list-style-type: none;
}

View File

@ -1,135 +0,0 @@
<vn>
<vn-group>
<db-form v-model="passwordForm">
<db-model property="model">
SELECT length, nAlpha, nUpper, nDigits, nPunct
FROM account.userPassword
</db-model>
</db-form>
<db-form id="user-form">
<db-model property="model" id="user-model" updatable="true">
SELECT u.id, u.name, u.email, u.nickname,
u.lang, c.isToBeMailed, c.id clientFk
FROM account.myUser u
LEFT JOIN myClient c
ON u.id = c.id
</db-model>
</db-form>
</vn-group>
<div id="title">
<h1><t>Configuration</t></h1>
</div>
<div id="actions">
<htk-bar-button
icon="place"
tip="_Addresses"
on-click="hash.setAll({form: 'account/address-list'})"/>
<htk-bar-button
icon="lock_reset"
tip="_Change password"
on-click="this.onPassChangeClick()"/>
</div>
<div id="form" class="conf">
<div class="form box vn-w-sm vn-pa-lg">
<h5 class="vn-mb-md">
<t>Personal information</t>
</h5>
<div class="form-group">
<htk-entry
placeholder="_Username"
disabled="true"
form="user-form"
column="name"/>
</div>
<div class="form-group">
<htk-entry
placeholder="_Email"
form="user-form"
column="email">
</htk-entry>
</div>
<div class="form-group">
<htk-entry
placeholder="_Display name"
form="user-form"
column="nickname"/>
</div>
<div class="form-group">
<htk-combo
placeholder="_Language"
form="user-form"
column="lang">
<db-model property="model">
<custom>
SELECT code, name FROM language WHERE isActive
</custom>
</db-model>
</htk-combo>
</div>
<div class="form-group">
<label>
<htk-check form="user-form" column="isToBeMailed"/>
<t>Receive invoices by email</t>
</label>
</div>
</div>
</div>
<htk-popup
id="change-password"
modal="true">
<div property="child-node" class="htk-dialog vn-w-xs vn-pa-lg">
<div class="form">
<h5 class="vn-mb-md">
<t>Change password</t>
</h5>
<input
id="old-password"
type="password"
placeholder="_Old password"/>
<input
id="new-password"
type="password"
placeholder="_New password"/>
<input
id="repeat-password"
type="password"
placeholder="_Repeat password"/>
</div>
<div class="button-bar">
<button class="thin" on-click="this.onPassModifyClick()">
<t>Modify</t>
</button>
<button class="thin" on-click="this.onPassInfoClick()">
<t>Requirements</t>
</button>
<div class="clear"/>
</div>
</div>
</htk-popup>
<htk-popup
id="password-info"
modal="true">
<div property="child-node" class="htk-dialog pass-info vn-w-xs vn-pa-lg">
<h5 class="vn-mb-md">
<t>Password requirements</t>
</h5>
<ul>
<li>
{{passwordForm.length}} <t>characters long</t>
</li>
<li>
{{passwordForm.nAlpha}} <t>alphabetic characters</t>
</li>
<li>
{{passwordForm.nUpper}} <t>capital letters</t>
</li>
<li>
{{passwordForm.nDigits}} <t>digits</t>
</li>
<li>
{{passwordForm.nPunct}} <t>symbols</t>
</li>
</ul>
</div>
</htk-popup>
</vn>

View File

@ -1,7 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
});

View File

@ -1,11 +0,0 @@
AccessLog: Registre d'accessos
'UserNumber:': 'N d''usuari:'
'User:': 'Usuari:'
'Phone:': 'Telèfon:'
'Mobile:': 'Mòbil:'
Access: Accés
OS: SO
Browser: Navegador
Version: Versió
Javascript: Javascript
Cookies: Cookies

View File

@ -1,11 +0,0 @@
AccessLog: Access log
'UserNumber:': 'User Number:'
'User:': 'User:'
'Phone:': 'Phone:'
'Mobile:': 'Mobile:'
Access: Access
OS: OS
Browser: Browser
Version: Version
Javascript: Javascript
Cookies: Cookies

View File

@ -1,11 +0,0 @@
AccessLog: Registro de accesos
'UserNumber:': 'Nº usuario:'
'User:': 'Usuario:'
'Phone:': 'Teléfono:'
'Mobile:': 'Móvil:'
Access: Acceso
OS: SO
Browser: Navegador
Version: Versión
Javascript: Javascript
Cookies: Cookies

View File

@ -1,11 +0,0 @@
AccessLog: Fiche d'accès
'UserNumber:': 'Numéro utilisateur:'
'User:': 'Utilisateur:'
'Phone:': 'Téléphone:'
'Mobile:': 'Portable:'
Access: Accès
OS: OS
Browser: Navigateur
Version: Version
Javascript: Javascript
Cookies: Cookies

View File

@ -1,11 +0,0 @@
AccessLog: Registro de acessos
'UserNumber:': 'Nº utilizador:'
'User:': 'Utilizador:'
'Phone:': 'Telefone:'
'Mobile:': 'Telemóvel:'
Access: Acceso
OS: OS
Browser: Navegador
Version: Versão
Javascript: Javascript
Cookies: Cookies

View File

@ -1,12 +0,0 @@
.access-log .form > p {
font-size: 1.2rem;
margin: .1em 0;
}
/* List */
.access-log .htk-list {
margin-top: 16px;
}

View File

@ -1,50 +0,0 @@
<vn>
<vn-group>
<db-form v-model="user">
<db-model property="model" lot="hash">
SELECT u.id, u.name user, u.nickname, u.email, c.phone, r.name role
FROM account.user u
JOIN account.role r ON r.id = u.role
LEFT JOIN vn.client c ON c.id = u.id
WHERE u.id = #user
</db-model>
</db-form>
</vn-group>
<div id="title">
<h1><t>AccessLog</t></h1>
</div>
<div id="form" class="access-log">
<div class="box vn-w-xs vn-pa-lg">
<div class="form">
<h4>{{user.nickname}}</h4>
<p>#{{user.id}} - {{user.user}}</p>
<p>{{user.role}}</p>
<p>{{user.email}}</p>
<p>{{user.phone}}</p>
</div>
</div>
<htk-repeater form-id="iter" class="box vn-w-xs htk-list vn-mt-md">
<db-model property="model" lot="hash">
SELECT u.stamp, a.platform, a.browser, a.version, a.javascript, a.cookies
FROM visitUser u
JOIN visitAccess c ON c.id = u.accessFk
JOIN visitAgent a ON a.id = c.agentFk
WHERE u.userFk = #user
ORDER BY u.stamp DESC
LIMIT 8
</db-model>
<custom>
<div class="item">
<div class="content">
<p>
{{Vn.Value.format(iter.stamp, _('%a, %e %b %Y at %T'))}}
</p>
<p>
{{iter.platform}} - {{iter.browser}} {{iter.version}}
</p>
</div>
</div>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,33 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,_timeoutId: null
,onModelStatusChange() {
if (!this.$.sessions.ready)
return;
if (this._timeoutId)
clearTimeout(this._timeoutId);
this._timeoutId = setTimeout(
() => this.$.sessions.refresh(), 60000);
}
,deactivate() {
clearTimeout(this._timeoutId);
}
,async onChangeUserClick(userName) {
await this.gui.supplantUser(userName);
this.hash.setAll({form: 'ecomerce/orders'});
}
,sessionsFunc() {
return 1;
}
});

View File

@ -1,4 +0,0 @@
Connections: Connexions
Refresh: Actualitzar
Visits: Visites
connections: connexions

View File

@ -1,4 +0,0 @@
Connections: Connections
Refresh: Refresh
Visits: Visits
connections: connections

View File

@ -1,4 +0,0 @@
Connections: Conexiones
Refresh: Actualizar
Visits: Visitas
connections: conexiones

View File

@ -1,4 +0,0 @@
Connections: Connexions
Refresh: Actualiser
Visits: Visites
connections: connexions

View File

@ -1,4 +0,0 @@
Connections: холболт
Refresh: Сэргээх
Visits: уулзалт
connections: холболт

View File

@ -1,4 +0,0 @@
Connections: Conexões
Refresh: actualização
Visits: Visualizações
connections: conexões

View File

@ -1,9 +0,0 @@
.action-bar .connections-sum {
padding: .4em;
background-color: #1e88e5;
border-radius: .1em;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}

View File

@ -1,63 +0,0 @@
<vn>
<div id="title">
<h1><t>Connections</t></h1>
</div>
<div id="actions">
<htk-bar-button
icon="refresh"
tip="_Refresh"
on-click="sessions.refresh()"/>
<div class="connections-sum">
<htk-text>
<db-calc-sum
property="param"
model="sessions"
func="sessionsFunc"/>
</htk-text>
<t>connections</t>
</div>
</div>
<div id="form" class="connections">
<htk-repeater form-id="iter" class="box htk-list vn-w-xs">
<db-model
property="model"
id="sessions"
on-status-changed="this.onModelStatusChange()">
SELECT vu.userFk userId, vu.stamp, u.nickname, s.lastUpdate,
a.platform, a.browser, a.version, u.name user
FROM userSession s
JOIN visitUser vu ON vu.id = s.userVisitFk
JOIN visitAccess ac ON ac.id = vu.accessFk
JOIN visitAgent a ON a.id = ac.agentFk
JOIN visit v ON v.id = a.visitFk
JOIN account.user u ON u.id = vu.userFk
ORDER BY lastUpdate DESC
</db-model>
<custom>
<a class="item"
href="{{`#!form=admin/access-log&amp;user=${iter.userId}`}}"
title="_Access log">
<div class="content">
<p class="important">
{{iter.nickname}}
</p>
<p>
{{Vn.Value.format(iter.stamp, '%a, %T')}} -
{{Vn.Value.format(iter.lastUpdate, '%T')}}
</p>
<p>
{{iter.platform}} - {{iter.browser}} {{iter.version}}
</p>
</div>
<div class="actions"
on-click="$event.preventDefault()">
<htk-button
tip="_Supplant user"
icon="supervisor_account"
on-click="this.onChangeUserClick(iter.user)"/>
</div>
</a>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,10 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml'),
activate() {
this.$.items.setInfo('i', 'item', 'vn', ['id']);
}
});

View File

@ -1,2 +0,0 @@
Items: Artícles
Enter a search term: Introdueix un terme de cerca

View File

@ -1,2 +0,0 @@
Items: Items
Enter a search term: Enter a search term

View File

@ -1,2 +0,0 @@
Items: Artículos
Enter a search term: Introduce un término de búsqueda

View File

@ -1,2 +0,0 @@
Items: Articles
Enter a search term: Entrez un terme de recherche

View File

@ -1,2 +0,0 @@
Items: Ítens
Enter a search term: Digite um termo de pesquisa

View File

@ -1,6 +0,0 @@
.items .item .photo {
border-radius: 10px;
height: 80px;
width: 80px;
}

View File

@ -1,57 +0,0 @@
<vn>
<div id="title">
<h1><t>Items</t></h1>
</div>
<div id="actions">
<htk-search-entry form="hash" column="search"/>
</div>
<div id="form" class="items">
<htk-repeater
class="htk-list rows box vn-w-xs"
form-id="iter"
empty-message="_Enter a search term">
<db-model property="model" id="items" lot="hash">
SELECT i.id, i.longName, i.size, i.category,
i.value5, i.value6, i.value7,
i.image, im.updated
FROM vn.item i
LEFT JOIN image im
ON im.collectionFk = 'catalog'
AND im.name = i.image
WHERE i.longName LIKE CONCAT('%', #search, '%')
OR i.id = #search
ORDER BY i.longName LIMIT 50
</db-model>
<custom>
<div class="item">
<div class="side vn-mr-md">
<htk-image
form="$iter"
column="image"
stamp-column="updated"
class="photo"
directory="catalog"
subdir="200x200"
full-dir="1600x900"
editable="true"
conn="conn"/>
</div>
<div class="content">
<p class="important">
{{iter.longName}}
</p>
<p class="tags">
{{iter.value5}} {{iter.value6}} {{iter.value7}}
</p>
<p>
{{iter.id}}
</p>
<p>
{{iter.image}}
</p>
</div>
</div>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,7 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
});

View File

@ -1,3 +0,0 @@
ControlPanel: Panell de control
Module: Mòdul
Description: Descripció

View File

@ -1,3 +0,0 @@
ControlPanel: Control panel
Module: Module
Description: Description

View File

@ -1,3 +0,0 @@
ControlPanel: Panel de control
Module: Módulo
Description: Descripción

View File

@ -1,3 +0,0 @@
ControlPanel: Panneau de configuration
Module: Module
Description: Description

View File

@ -1,3 +0,0 @@
ControlPanel: Painel de controle
Module: Módulo
Description: Descrição

View File

@ -1,50 +0,0 @@
.cpanel .items > div {
max-width: 900px;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16px;
margin: 0 auto;
}
.cpanel .item {
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
width: 140px;
padding: 15px;
text-align: center;
transition: background-color 250ms ease-out;
}
.cpanel .item:hover {
background-color: rgba(1, 1, 1, 0.05);
}
.cpanel .item > .htk-image {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
float: left;
height: 80px;
}
.cpanel .item > .htk-image > img {
max-height: 60px;
max-width: 60px;
padding: 0;
}
.cpanel .item > h6 {
flex: none;
margin: .1em 0;
font-size: .9rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.cpanel .item > .text-secondary {
flex: none;
margin: 0;
font-size: .8rem;
height: 40px;
overflow: hidden;
}

View File

@ -1,31 +0,0 @@
<vn>
<div id="title">
<h1><t>ControlPanel</t></h1>
</div>
<div id="form" class="cpanel">
<htk-repeater form-id="iter" class="items">
<db-model property="model">
<custom>
SELECT image, name, description, link FROM link
ORDER BY name
</custom>
</db-model>
<custom>
<a class="item box"
href="{{iter.link}}"
target="_blank">
<htk-image
value="{{iter.image}}"
directory="link"
subdir="full"/>
<h6>
{{iter.name}}
</h6>
<p class="text-secondary">
{{iter.description}}
</p>
</a>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,201 +0,0 @@
import './style.scss';
var Status = {
NONE : 0
,WAITING : 1
,UPLOADING : 2
,UPLOADED : 3
};
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,filesData: []
,uploadCount: 0
,isUploading: false
,activate() {
this.$.schema.value = 'catalog';
}
,addFiles(files) {
if (!files)
return;
for (var i = 0; i < files.length; i++)
this.addFile(files[i]);
}
,addFile(file) {
var doc = document;
var li = doc.createElement('div');
var div = doc.createElement('div');
div.className = 'thumb';
li.appendChild(div);
var thumb = doc.createElement('img');
thumb.file = file;
div.appendChild(thumb);
var reader = new FileReader();
reader.onload = function(e) {
thumb.src = e.target.result;
};
reader.readAsDataURL(file);
var name = doc.createElement('input');
name.type = 'text';
name.value = getFileName(file.name);
li.appendChild(name);
var statusNode = doc.createElement('div');
statusNode.className = 'status';
li.appendChild(statusNode);
var fileData = {
li: li,
file: file,
name: name,
statusNode: statusNode
};
var button = new Htk.Button({
tip: 'Remove',
icon: 'delete'
});
button.node.addEventListener('click',
() => this.onFileRemove(fileData));
li.appendChild(button.node);
this.filesData.push(fileData);
this.$.fileList.appendChild(li);
this.setImageStatus(fileData, Status.NONE, 'add', _('Pending upload'));
}
,async onUploadClick() {
if (this.isUploading) return;
const uploadQueue = [];
let hasFiles = false;
for (const fileData of this.filesData) {
if (fileData.status !== Status.NONE) continue;
this.setImageStatus(
fileData, Status.WAITING, 'cloud_upload', _('Waiting for upload'));
fileData.name.disabled = true;
uploadQueue.push(fileData);
hasFiles = true;
}
if (!hasFiles) {
Htk.Toast.showWarning(_('There are no files to upload'));
return;
}
this.isUploading = true;
let hasErrors = false;
for (const fileData of uploadQueue) {
this.setImageStatus(
fileData, Status.UPLOADING, 'upload', _('Uploading file'));
const formData = new FormData();
formData.append('updateMatching', this.$.updateMatching.value);
formData.append('image', fileData.file);
formData.append('name', fileData.name.value);
formData.append('schema', this.$.schema.value);
formData.append('srv', 'json:image/upload');
try {
await this.conn.sendFormData(formData);
this.setImageStatus(
fileData, Status.UPLOADED, 'cloud_done', _('Image uploaded'));
} catch(err) {
this.setImageStatus(
fileData, Status.NONE, 'error', err.message);
fileData.name.disabled = false;
hasErrors = true;
}
}
this.isUploading = false;
if (hasErrors)
Htk.Toast.showError(_('Some errors happened on upload'));
else
Htk.Toast.showMessage(_('Upload finished successfully'));
}
,setImageStatus(fileData, status, icon, title) {
fileData.status = status;
var statusNode = fileData.statusNode;
Vn.Node.removeChilds(statusNode);
var iconNode = new Htk.Icon({name: icon});
statusNode.appendChild(iconNode.node);
statusNode.title = title ? title : '';
}
,onFileRemove(fileData) {
this.$.fileList.removeChild(fileData.li);
for (var i = 0; i < this.filesData.length; i++)
if (this.filesData[i] === fileData) {
this.filesData.splice(i, 1);
break;
}
}
,onClearClick() {
this.filesData = [];
Vn.Node.removeChilds(this.$.fileList);
}
,onDropzoneClick() {
this.$.file.click();
}
,onFileChange() {
this.addFiles(this.$.file.files);
}
,onDragEnter() {
this.$.dropzone.classList.add('dragover');
}
,onDragLeave() {
this.$.dropzone.classList.remove('dragover');
}
,onDragOver(event) {
event.preventDefault();
}
,onDragEnd(event) {
this.$.dropzone.classList.remove('dragover');
event.dataTransfer.clearData();
}
,onDrop(event) {
event.preventDefault();
this.addFiles(event.dataTransfer.files);
}
});
function getFileName(path) {
var barIndex = path.lastIndexOf('/');
if (barIndex === -1)
barIndex = path.lastIndexOf('\\');
if (barIndex === -1)
barIndex = 0;
var dotIndex = path.lastIndexOf('.');
if (dotIndex === -1)
dotIndex = 0;
return path.substr(barIndex, dotIndex);
}

View File

@ -1,13 +0,0 @@
Images: Imatges
Collection: Col·lecció
Click or drop files here: Prem o deixa anar els arxius aquí
Pending upload: Pujada pendent
Update items with matching id: Actualitzar els elements amb id coincident
Clear all: Netejar tot
Upload files: Pujar arxius
Waiting for upload: Esperant per pujar
Uploading file: Pujant fitxer
Image uploaded: Imatge pujada
Upload finished successfully: Imatges pujades correctament
Some errors happened on upload: Van ocórrer errors en pujar alguna de les imatges
There are no files to upload: No s'ha seleccionat arxius per pujar

View File

@ -1,13 +0,0 @@
Images: Images
Collection: Collection
Click or drop files here: Click or drop files here
Pending upload: Pending upload
Update items with matching id: Update items with matching id
Clear all: Clear all
Upload files: Upload files
Waiting for upload: Waiting for upload
Uploading file: Uploading file
Image uploaded: Image uploaded
Upload finished successfully: Upload finished successfully
Some errors happened on upload: Some errors happened on upload
There are no files to upload: There are no files to upload

View File

@ -1,13 +0,0 @@
Images: Imágenes
Collection: Colección
Click or drop files here: Pulsa o suelta los archivos aquí
Pending upload: Subida pendiente
Update items with matching id: Actualizar ítems con id coincidente
Clear all: Limpiar todo
Upload files: Subir archivos
Waiting for upload: Esperando para subir
Uploading file: Subiendo fichero
Image uploaded: Imagen subida
Upload finished successfully: Imágenes subidas correctamente
Some errors happened on upload: Ocurrieron errores al subir alguna de las imágenes
There are no files to upload: No se han seleccionado archivos para subir

View File

@ -1,13 +0,0 @@
Images: Images
Collection: Collection
Click or drop files here: Cliquez ici ou déposer des fichiers
Pending upload: Hausse en attente
Update items with matching id: Mettre à jour les éléments avec l'identifiant correspondant
Clear all: Tout effacer
Upload files: Upload Files
Waiting for upload: En attente de télécharger
Uploading file: Uploader des fichiers
Image uploaded: Fichier uploadé
Upload finished successfully: Les images téléchargées correctement
Some errors happened on upload: Des erreurs sont survenues lors du téléchargement des images
There are no files to upload: Aucun fichier sélectionné pour télécharger

View File

@ -1,13 +0,0 @@
Images: Imagens
Collection: Coleção
Click or drop files here: Clique ou solte arquivos aqui
Pending upload: Ascensão pendente
Update items with matching id: Atualizar itens com id correspondente
Clear all: Limpar tudo
Upload files: Fazer upload de arquivos
Waiting for upload: Esperando para enviar
Uploading file: Enviando arquivo
Image uploaded: Imagem Enviada
Upload finished successfully: Upload concluído com sucesso
Some errors happened on upload: Ocorreram erros ao subir alguma das imagens
There are no files to upload: Não há arquivos selecionados para upload

View File

@ -1,81 +0,0 @@
/* Dropzone */
.photos .dropzone {
background-color: white;
border-style: dashed;
border-radius: .4em;
border-color: #2196F3;
padding: 2em 1em;
text-align: center;
color: #666;
cursor: pointer;
}
.photos .dropzone.dragover {
color: #CCC;
border-style: solid;
}
.photos input[type=file] {
display: none;
}
/* File list */
.photos .file-list {
margin-top: 1em;
}
.photos .file-list > div {
height: 2.5em;
display: flex;
align-items: center;
}
.photos .file-list > div > * {
overflow: hidden;
}
.photos .file-list .thumb {
width: 2em;
padding-right: .5em;
text-align: center;
}
.photos .file-list .thumb > img {
max-height: 2em;
max-width: 2em;
vertical-align: middle;
}
.photos .file-list input {
flex: 1;
min-width: 0;
}
.photos .file-list .status {
cursor: pointer;
width: 1.2em;
padding-left: .5em;
padding-right: .5em;
}
.photos .file-list .status > .htk-icon {
display: block;
}
.photos .file-list .htk-button {
opacity: .2;
}
.photos .file-list .htk-button:hover {
background-color: transparent;
opacity: 1;
}
.photos .file-list .htk-button > img {
display: block;
}
/* Footer */
.photos .update-matching {
margin-top: 1.5em;
}
.photos .footer {
margin-top: 1.5em;
text-align: center;
}
.photos .footer > button {
font-size: 1.2rem;
margin-left: 1em;
}

View File

@ -1,50 +0,0 @@
<vn>
<div id="title">
<h1><t>Images</t></h1>
</div>
<div id="form" class="photos">
<div class="box form vn-w-sm vn-pa-lg">
<div class="form-group">
<label><t>Collection</t></label>
<htk-combo id="schema">
<db-model property="model">
<custom>
SELECT name, `desc` FROM imageCollection ORDER BY `desc`
</custom>
</db-model>
</htk-combo>
</div>
<div id="dropzone" class="dropzone"
on-dragenter="onDragEnter"
on-dragleave="onDragLeave"
on-mouseout="onDragLeave"
on-dragover="onDragOver"
on-drop="onDrop"
on-dragend="onDragEnd"
on-click="onDropzoneClick">
<t>Click or drop files here</t>
</div>
<input
id="file"
type="file"
multiple="true"
name="image"
on-change="onFileChange"/>
<div id="file-list" class="file-list"/>
<div class="update-matching">
<label>
<htk-check id="update-matching" value="true"/>
<t>Update items with matching id</t>
</label>
</div>
<div class="footer">
<button class="thin" on-click="onClearClick">
<t>Clear all</t>
</button>
<button class="thin" on-click="onUploadClick">
<t>Upload files</t>
</button>
</div>
</div>
</div>
</vn>

View File

@ -1,93 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,activate() {
this.$.resultIndex.value = 0;
}
,clean() {
if (this._grid) {
this.$.gridHolder.removeChild(this._grid.node);
this._grid.unref();
this._grid = null;
}
}
,onExecuteClick() {
this.clean();
var model = new Db.Model({
conn: this.conn,
query: this.$.sql.value,
resultIndex: this.$.resultIndex.value,
updatable: this.$.updatable.value
});
model.on('status-changed', this.onModelChange, this);
}
,onCleanClick() {
this.clean();
}
,onModelChange(model, status) {
if (status !== Db.Model.Status.LOADING) {
model.disconnect('status-changed', this.onModelChange, this);
model.unref();
}
if (status !== Db.Model.Status.READY)
return;
Htk.Toast.showMessage(_('Query executed!'));
var gridHolder = this.$.gridHolder;
if (gridHolder.firstChild)
gridHolder.removeChilds(gridHolder.firstChild);
var grid = new Htk.Grid();
var columns = model.columns;
for (var i = 0; i < columns.length; i++) {
var c = columns[i];
switch (c.type) {
case Db.Conn.Type.BOOLEAN:
var column = new Htk.ColumnCheck();
break;
case Db.Conn.Type.INTEGER:
var column = new Htk.ColumnSpin();
break;
case Db.Conn.Type.DOUBLE:
var column = new Htk.ColumnSpin({digits: 2});
break;
case Db.Conn.Type.DATE:
var column = new Htk.ColumnDate({format: '%a, %e %b %Y'});
break;
case Db.Conn.Type.DATE_TIME:
var column = new Htk.ColumnDate({format: '%a, %e %b %Y, %T'});
break;
case Db.Conn.Type.STRING:
default:
var column = new Htk.ColumnText();
}
column.setProperties({
title: c.name,
editable: this.$.updatable.value,
columnIndex: i
});
grid.appendColumn(column);
}
grid.model = model;
gridHolder.appendChild(grid.node);
this._grid = grid;
}
});

View File

@ -1,6 +0,0 @@
Queries: Consultes
Execute: Executar
Clean: Netejar
SQL query: Consulta SQL
Updatable: Actualitzable
Query executed!: Consulta executada!

View File

@ -1,6 +0,0 @@
Queries: Queries
Execute: Execute
Clean: Clean
SQL query: SQL query
Updatable: Updatable
Query executed!: Query executed!

View File

@ -1,6 +0,0 @@
Queries: Consultas
Execute: Ejecutar
Clean: Limpiar
SQL query: Consulta SQL
Updatable: Actualizable
Query executed!: ¡Consulta ejecutada!

View File

@ -1,6 +0,0 @@
Queries: Queries
Execute: Execute
Clean: Clean
SQL query: SQL query
Updatable: Updatable
Query executed!: Query executed!

View File

@ -1,6 +0,0 @@
Queries: Consultas
Execute: Executar
Clean: Limpar
SQL query: Consulta SQL
Updatable: Actualizável
Query executed!: Consulta executada!

View File

@ -1,10 +0,0 @@
.queries textarea {
display: block;
width: 100%;
height: 8em;
}
.queries .result {
margin-top: 1em;
overflow: auto;
}

View File

@ -1,38 +0,0 @@
<vn>
<div id="title">
<h1><t>Queries</t></h1>
</div>
<div id="actions">
<htk-bar-button
icon="ok"
tip="_Execute"
on-click="this.onExecuteClick()"/>
<htk-bar-button
icon="delete"
tip="_Clean"
on-click="this.onCleanClick()"/>
</div>
<div id="form" class="queries">
<div class="box form vn-w-sm vn-pa-lg">
<div class="form-group">
<label><t>SQL query</t></label>
<textarea
id="sql"
autocorrect="off"
autocapitalize="off"
spellcheck="false"/>
</div>
<div class="form-group">
<label><t>Result index</t></label>
<htk-spin id="result-index"/>
</div>
<div class="form-group">
<label><t>Updatable</t></label>
<htk-check id="updatable"/>
</div>
</div>
<div class="box result">
<div id="grid-holder"/>
</div>
</div>
</vn>

View File

@ -1,20 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,rendererFunc(scope, form) {
var isEnabled = form.$.active
scope.$.disabled.style.display = isEnabled ?
'none' : 'block';
scope.$.impersonate.node.style.display = isEnabled ?
'block' : 'none';
}
,async onChangeUserClick(userName) {
await this.gui.supplantUser(userName);
this.hash.setAll({form: 'ecomerce/orders'});
}
});

View File

@ -1,4 +0,0 @@
User management: Gestió d'usuaris
Disabled: Deshabilitat
Impersonate user: Suplantar usuari
Access log: Registre d'accessos

View File

@ -1,4 +0,0 @@
User management: User management
Disabled: Disabled
Impersonate user: Impersonate user
Access log: Access log

View File

@ -1,4 +0,0 @@
User management: Gestión de usuarios
Disabled: Desactivado
Impersonate user: Suplantar usuario
Access log: Registro de accesos

View File

@ -1,4 +0,0 @@
User management: Gestion des utilisateurs
Disabled: Désactivé
Impersonate user: Accès utilisateur
Access log: Journal des accès

View File

@ -1,4 +0,0 @@
User management: Gestão de usuarios
Disabled: Desativado
Impersonate user: Suplantar usuario
Access log: Registro de acessos

View File

@ -1,11 +0,0 @@
.users-box.item > .actions {
display: flex;
}
.users-box .disabled {
color: white;
background-color: #F66;
border-radius: .2em;
padding: .3em;
font-size: .8em;
}

View File

@ -1,48 +0,0 @@
<vn>
<div id="title">
<h1><t>User management</t></h1>
</div>
<div id="actions">
<htk-search-entry form="hash" column="user"/>
</div>
<div id="form" class="users">
<htk-repeater
form-id="iter"
renderer="rendererFunc"
class="htk-list box vn-w-xs">
<db-model property="model" lot="hash">
SELECT u.id, u.name, u.nickname, u.active
FROM account.user u
WHERE u.name LIKE CONCAT('%', #user, '%')
OR u.nickname LIKE CONCAT('%', #user, '%')
OR u.id = #user
ORDER BY u.name LIMIT 200
</db-model>
<custom>
<a class="users-box item"
href="{{`#!form=admin/access-log&amp;user=${iter.id}`}}"
title="_Access log">
<div class="content">
<p class="important">
{{iter.nickname}}
</p>
<p>
#{{iter.id}} - {{iter.name}}
</p>
</div>
<div class="actions"
on-click="$event.preventDefault()">
<span id="disabled" class="disabled">
<t>Disabled</t>
</span>
<htk-button
id="impersonate"
icon="supervisor_account"
tip="_Impersonate user"
on-click="this.onChangeUserClick(iter.name)"/>
</div>
</a>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,15 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
,activate() {
if (!this.hash.$.to)
this.hash.assign({
from: new Date(),
to: new Date()
});
}
});

View File

@ -1,9 +0,0 @@
Visits: Visites
Refresh: Actualitzar
Connections: Connexions
From: Desde
To: Fins
Select date interval: Selecciona un interval de dates
visits: visites
news: noves
'%a, %e %b %Y at %T': '%a, %e %b %Y a les %T'

View File

@ -1,9 +0,0 @@
Visits: Visits
Refresh: Refresh
Connections: Connections
From: From
To: To
Select date interval: Select date interval
visits: visits
news: news
'%a, %e %b %Y at %T': '%a, %e %b %Y at %T'

View File

@ -1,9 +0,0 @@
Visits: Visitas
Refresh: Actualizar
Connections: Conexiones
From: Desde
To: Hasta
Select date interval: Selecciona un intérvalo de fechas
visits: visitas
news: nuevas
'%a, %e %b %Y at %T': '%a, %e %b %Y a las %T'

View File

@ -1,9 +0,0 @@
Visits: Visites
Refresh: Actualiser
Connections: Connexions
From: À partir de
To: À
Select date interval: Sélectionnez une plage de dates
visits: visites
news: nouvelles
'%a, %e %b %Y at %T': '%a, %e %b %Y à %T'

View File

@ -1,9 +0,0 @@
Visits: уулзалт
Refresh: Сэргээх
Connections: холболт
From: эхлэн
To: нь
Select date interval: Сонгох огноо интервал
visits: уулзалт
news: мэдээ
'%a, %e %b %Y at %T': '%a, %e %b %Y нь %T'

Some files were not shown because too many files have changed in this diff Show More