1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

Compare commits

...

12 Commits

12 changed files with 437 additions and 52 deletions

View File

@@ -8,7 +8,8 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
# os: [macos-latest, ubuntu-latest, windows-latest]
os: [macos-latest, ubuntu-latest]
steps:
- name: Check out Git repository

View File

@@ -2,6 +2,26 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.1.6](https://github.com/Fabio286/antares/compare/v0.1.5...v0.1.6) (2021-05-08)
### Features
* **MySQL:** ENUM and SET fields support, closes [#61](https://github.com/Fabio286/antares/issues/61) ([bebba64](https://github.com/Fabio286/antares/commit/bebba64d06532990405763284e27cb768dc050f7))
### Bug Fixes
* better detection and handling of field default type ([3baf6fa](https://github.com/Fabio286/antares/commit/3baf6fa1736a405c95fb02d17c11514861ca9e04))
* no quotes around strings in field default custom value ([29e2d92](https://github.com/Fabio286/antares/commit/29e2d92b5bf66ff9e80bb1fee1274967c4418601))
* **UI:** data type figure twice on type select ([9dfe7cc](https://github.com/Fabio286/antares/commit/9dfe7cca2234ce6de512bb4c21205c2217e7f765))
* support to mDNS/zeroconf in snap build, closes [#58](https://github.com/Fabio286/antares/issues/58) ([35ef070](https://github.com/Fabio286/antares/commit/35ef070725f5779923bf3ad428b44accddf22dbe))
### Improvements
* italian translation updated ([5dc0b0b](https://github.com/Fabio286/antares/commit/5dc0b0bea40f9d5a5944af2f1c5dc6ff3e60c396))
### [0.1.5](https://github.com/Fabio286/antares/compare/v0.1.4...v0.1.5) (2021-04-30)

BIN
build/appx/LargeTile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
build/appx/SmallTile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.1.5",
"version": "0.1.6",
"description": "A cross-platform easy to use SQL client.",
"license": "MIT",
"repository": "https://github.com/Fabio286/antares.git",
@@ -70,33 +70,32 @@
"@electron/remote": "^1.1.0",
"@mdi/font": "^5.9.55",
"ace-builds": "^1.4.12",
"electron-log": "^4.3.0",
"electron-log": "^4.3.5",
"electron-store": "^8.0.0",
"electron-updater": "^4.3.5",
"faker": "^5.3.1",
"marked": "^2.0.2",
"moment": "^2.29.1",
"mysql2": "^2.2.5",
"node-sql-parser": "^3.1.0",
"pg": "^8.5.1",
"pgsql-ast-parser": "^7.0.2",
"pgsql-ast-parser": "^7.2.1",
"source-map-support": "^0.5.16",
"spectre.css": "^0.5.9",
"sql-formatter": "^4.0.2",
"v-mask": "^2.2.4",
"vue-i18n": "^8.22.4",
"vue-i18n": "^8.24.4",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.13.14",
"cross-env": "^7.0.2",
"electron": "^12.0.5",
"electron": "^12.0.7",
"electron-builder": "^22.9.1",
"electron-devtools-installer": "^3.2.0",
"electron-webpack": "^2.8.2",
"electron-webpack-vue": "^2.4.0",
"eslint": "^7.24.0",
"eslint": "^7.26.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
@@ -104,8 +103,8 @@
"eslint-plugin-vue": "^7.9.0",
"node-sass": "^5.0.0",
"sass-loader": "^10.1.1",
"standard-version": "^9.2.0",
"stylelint": "^13.12.0",
"standard-version": "^9.3.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.19.0",
"vue": "^2.6.12",

View File

@@ -14,6 +14,9 @@ confinement: strict
architectures:
- build-on: amd64
compression: lzo
layout:
/etc/nsswitch.conf:
bind-file: $SNAP/etc/nsswitch.conf
parts:
antares:
@@ -71,11 +74,28 @@ parts:
cleanup:
after: [antares]
plugin: nil
build-snaps: [ gnome-3-28-1804 ]
build-snaps: [gnome-3-28-1804]
override-prime: |
set -eux
cd /snap/gnome-3-28-1804/current
find . -type f,l -exec rm -f $SNAPCRAFT_PRIME/{} \;
set -eux
cd /snap/gnome-3-28-1804/current
find . -type f,l -exec rm -f $SNAPCRAFT_PRIME/{} \;
mdns-lookup:
# Make resolution of ".local" host names (Zero-Conf/mDNS/DNS-SD)
# working: Take the original nsswitch.conf file from the base
# Snap and add "mdns4_minimal [NOTFOUND=return]" to its "hosts:" line
# Also install corresponding mdns4_minimal plug-in
# See: https://forum.snapcraft.io/t/no-mdns-support-in-snaps-should-core-have-a-modified-nsswitch-conf/
plugin: nil
stage-packages:
- libnss-mdns
override-prime: |
set -eux
sed -Ee 's/^\s*hosts:(\s+)files/hosts:\1files mdns4_minimal \[NOTFOUND=return\]/' /snap/core18/current/etc/nsswitch.conf > $SNAPCRAFT_STAGE/etc/nsswitch.conf
snapcraftctl prime
prime:
- lib/$SNAPCRAFT_ARCH_TRIPLET/libnss_mdns4_minimal*
- etc/nsswitch.conf
apps:
antares:
@@ -93,4 +113,4 @@ apps:
- opengl
- pulseaudio
- removable-media
- unity7
- unity7

View File

@@ -277,13 +277,6 @@ module.exports = [
{
group: 'other',
types: [
{
name: 'UNKNOWN',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'ENUM',
length: true,
@@ -299,5 +292,17 @@ module.exports = [
zerofill: false
}
]
},
{
group: 'unknown',
types: [
{
name: 'UNKNOWN',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
}
];

View File

@@ -310,6 +310,9 @@ export class MySQLClient extends AntaresCore {
return rows.map(field => {
let numLength = field.COLUMN_TYPE.match(/int\(([^)]+)\)/);
numLength = numLength ? +numLength.pop() : null;
const enumValues = /(enum|set)/.test(field.COLUMN_TYPE)
? field.COLUMN_TYPE.match(/\(([^)]+)\)/)[0].slice(1, -1)
: null;
return {
name: field.COLUMN_NAME,
@@ -319,6 +322,7 @@ export class MySQLClient extends AntaresCore {
table: field.TABLE_NAME,
numPrecision: field.NUMERIC_PRECISION,
numLength,
enumValues,
datePrecision: field.DATETIME_PRECISION,
charLength: field.CHARACTER_MAXIMUM_LENGTH,
nullable: field.IS_NULLABLE.includes('YES'),
@@ -691,7 +695,7 @@ export class MySQLClient extends AntaresCore {
}, []).join(',')
: '';
const sql = `CREATE ${routine.definer ? `DEFINER=${routine.definer} ` : ''}PROCEDURE \`${routine.name}\`(${parameters})
const sql = `CREATE ${routine.definer ? `DEFINER=${routine.definer} ` : ''}PROCEDURE \`${this._schema}\`.\`${routine.name}\`(${parameters})
LANGUAGE SQL
${routine.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
${routine.dataAccess}
@@ -1116,7 +1120,7 @@ export class MySQLClient extends AntaresCore {
// CHANGE FIELDS
changes.forEach(change => {
const typeInfo = this._getTypeInfo(change.type);
const length = typeInfo.length ? change.numLength || change.charLength || change.datePrecision : false;
const length = typeInfo.length ? change.enumValues || change.numLength || change.charLength || change.datePrecision : false;
alterColumns.push(`CHANGE COLUMN \`${change.orgName}\` \`${change.name}\`
${change.type.toUpperCase()}${length ? `(${length})` : ''}
@@ -1190,7 +1194,7 @@ export class MySQLClient extends AntaresCore {
* @memberof MySQLClient
*/
async truncateTable (params) {
const sql = `TRUNCATE TABLE \`${params.table}\``;
const sql = `TRUNCATE TABLE \`${this._schema}\`.\`${params.table}\``;
return await this.raw(sql);
}
@@ -1201,7 +1205,7 @@ export class MySQLClient extends AntaresCore {
* @memberof MySQLClient
*/
async dropTable (params) {
const sql = `DROP TABLE \`${params.table}\``;
const sql = `DROP TABLE \`${this._schema}\`.\`${params.table}\``;
return await this.raw(sql);
}

View File

@@ -233,6 +233,20 @@ export default {
const { status, response } = await Tables.getTableColumns(params);
if (status === 'success') {
this.originalFields = response.map(field => {
if (field.autoIncrement)
field.defaultType = 'autoincrement';
else if (field.default === null)
field.defaultType = 'noval';
else if (field.default === 'NULL')
field.defaultType = 'null';
else if (field.default.match(/^\s*(\w+)\s*\((.*)\)$/))
field.defaultType = 'expression';
else {
field.defaultType = 'custom';
if (isNaN(field.default) && !field.default.includes('\''))
field.default = `'${field.default}'`;
}
return { ...field, _id: uidGen() };
});
this.localFields = JSON.parse(JSON.stringify(this.originalFields));

View File

@@ -98,6 +98,15 @@
>
{{ localLength }}
</span>
<input
v-else-if="localRow.enumValues"
ref="editField"
v-model="editingContent"
type="text"
autofocus
class="editable-field px-2"
@blur="editOFF"
>
<input
v-else
ref="editField"
@@ -352,7 +361,7 @@ export default {
getWorkspace: 'workspaces/getWorkspace'
}),
localLength () {
return this.localRow.numLength || this.localRow.charLength || this.localRow.datePrecision || this.localRow.numPrecision || 0;
return this.localRow.enumValues || this.localRow.numLength || this.localRow.charLength || this.localRow.datePrecision || this.localRow.numPrecision || 0;
},
fieldType () {
const fieldType = this.dataTypes.reduce((acc, group) => [...acc, ...group.types], []).filter(type =>
@@ -381,10 +390,12 @@ export default {
isInDataTypes () {
let typeNames = [];
for (const group of this.dataTypes) {
typeNames = group.types.reduce((acc, curr) => {
const groupTypeNames = group.types.reduce((acc, curr) => {
acc.push(curr.name);
return acc;
}, []);
typeNames = [...groupTypeNames, ...typeNames];
}
return typeNames.includes(this.row.type);
}
@@ -433,37 +444,30 @@ export default {
});
this.defaultValue.onUpdate = this.localRow.onUpdate;
if (this.localRow.autoIncrement)
this.defaultValue.type = 'autoincrement';
else if (this.localRow.default === null)
this.defaultValue.type = 'noval';
else if (this.localRow.default === 'NULL')
this.defaultValue.type = 'null';
else if (this.localRow.default.match(/^'.*'$/g)) {
this.defaultValue.type = 'custom';
this.defaultValue.custom = this.localRow.default.replace(/(^')|('$)/g, '');
}
else if (!isNaN(this.localRow.default.replace(/[:.-\s]/g, ''))) {
this.defaultValue.type = 'custom';
this.defaultValue.type = this.localRow.defaultType;
if (this.defaultValue.type === 'custom')
this.defaultValue.custom = this.localRow.default;
}
else {
this.defaultValue.type = 'expression';
if (this.defaultValue.type === 'expression')
this.defaultValue.expression = this.localRow.default;
}
},
editON (event, content, field) {
if (field === 'length') {
if (['integer', 'float', 'binary', 'spatial'].includes(this.fieldType.group)) this.editingField = 'numLength';
if (['string', 'other'].includes(this.fieldType.group)) this.editingField = 'charLength';
if (['time'].includes(this.fieldType.group)) this.editingField = 'datePrecision';
else if (['string', 'unknown'].includes(this.fieldType.group)) this.editingField = 'charLength';
else if (['other'].includes(this.fieldType.group)) this.editingField = 'enumValues';
else if (['time'].includes(this.fieldType.group)) this.editingField = 'datePrecision';
}
else
this.editingField = field;
this.editingContent = content;
this.originalContent = content;
if (this.localRow.enumValues && field === 'length') {
this.editingContent = this.localRow.enumValues;
this.originalContent = this.localRow.enumValues;
}
else {
this.editingContent = content;
this.originalContent = content;
}
const obj = { [field]: true };
this.isInlineEditor = { ...this.isInlineEditor, ...obj };
@@ -519,7 +523,7 @@ export default {
break;
case 'custom':
this.localRow.autoIncrement = false;
this.localRow.default = `'${this.defaultValue.custom}'`;
this.localRow.default = this.defaultValue.custom;
break;
case 'expression':
this.localRow.autoIncrement = false;

View File

@@ -43,6 +43,16 @@
<option>true</option>
<option>false</option>
</select>
<select
v-else-if="enumArray"
v-model="editingContent"
class="form-select small-select editable-field"
@blur="editOFF"
>
<option v-for="value in enumArray" :key="value">
{{ value }}
</option>
</select>
<input
v-else
ref="editField"
@@ -336,6 +346,11 @@ export default {
}
return false;
},
enumArray () {
if (this.fields[this.editingField].enumValues)
return this.fields[this.editingField].enumValues.replaceAll('\'', '').split(',');
return false;
}
},
watch: {

View File

@@ -39,7 +39,73 @@ module.exports = {
data: 'Dati',
properties: 'Proprietà',
insert: 'Inserisci',
connecting: 'Connessione in corso'
connecting: 'Connessione in corso',
name: 'Nome',
collation: 'Confronto',
clear: 'Scarta',
options: 'Opzioni',
autoRefresh: 'Auto-aggiorna',
indexes: 'Indici',
foreignKeys: 'Chiavi esterne',
length: 'Lunghezza',
unsigned: 'Senza segno',
default: 'Default',
comment: 'Commento',
key: 'Chiave | Chiavi',
order: 'Ordine',
expression: 'Espressione',
autoIncrement: 'Auto Incremento',
engine: 'Motore',
field: 'Campo | Campi',
approximately: 'Approssimativamente',
total: 'Totali',
table: 'Tabella',
discard: 'Scarta',
stay: 'Resta',
author: 'Autore',
light: 'Chiaro',
dark: 'Scuro',
autoCompletion: 'Auto Completamento',
application: 'Applicazione',
editor: 'Editor',
view: 'Vista',
definer: 'Definer',
algorithm: 'Algoritmo',
trigger: 'Trigger | Triggers',
storedRoutine: 'Stored routine | Stored routines',
scheduler: 'Scheduler | Schedulers',
event: 'Evento',
parameters: 'Parametri',
function: 'Funzione | Funzioni',
deterministic: 'Deterministico',
context: 'Contesto',
export: 'Esporta',
returns: 'Ritorna',
timing: 'Temporizzazione',
state: 'Stato',
execution: 'Esecuzione',
starts: 'Inizia',
ends: 'Finisce',
ssl: 'SSL',
privateKey: 'Chiave privata',
certificate: 'Certificato',
caCertificate: 'Certificato CA',
ciphers: 'Ciphers',
upload: 'Carica',
browse: 'Sfoglia',
faker: 'Faker',
content: 'Contenuto',
cut: 'Taglia',
copy: 'Copia',
paste: 'Incolla',
tools: 'Strumenti',
variables: 'Variabili',
processes: 'Processi',
database: 'Database',
scratchpad: 'Blocco appunti',
array: 'Array',
changelog: 'Changelog',
format: 'Formatta'
},
message: {
appWelcome: 'Benvenuto in Antares SQL Client!',
@@ -71,6 +137,243 @@ module.exports = {
addNewRow: 'Aggiungi nuova riga',
numberOfInserts: 'Numero di insert',
openNewTab: 'Apri nuova scheda',
affectedRows: 'Righe interessate'
affectedRows: 'Righe interessate',
createNewDatabase: 'Crea nuovo database',
databaseName: 'Nome database',
serverDefault: 'Default del server',
deleteDatabase: 'Cancella database',
editDatabase: 'Modifica database',
clearChanges: 'Scarta modifiche',
addNewField: 'Aggiungi nuovo campo',
manageIndexes: 'Gestisci indici',
manageForeignKeys: 'Gestisci chiavi esterne',
allowNull: 'Permetti NULL',
zeroFill: 'Riempimento con zero',
customValue: 'Varore personalizzato',
onUpdate: 'All\'aggiornamento',
deleteField: 'Cancella campo',
createNewIndex: 'Crea nuovo indice',
addToIndex: 'Aggiungi a indice',
createNewTable: 'Crea nuova tabella',
emptyTable: 'Svuota tabella',
deleteTable: 'Cancella tabella',
emptyCorfirm: 'Confermi di voler svuotare',
unsavedChanges: 'Modifiche non salvate',
discardUnsavedChanges: 'Hai modifiche non salvate. Lasciando questa scheda le modifiche saranno scartate.',
thereAreNoIndexes: 'Non ci sono indici',
thereAreNoForeign: 'Non ci sono chiavi esterne',
createNewForeign: 'Crea nuova chiave esterna',
referenceTable: 'Tabella di rif.',
referenceField: 'Campo di rif.',
foreignFields: 'Campi esterni',
invalidDefault: 'Default non valido',
onDelete: 'All\'eliminazione',
applicationTheme: 'Tema applicazione',
editorTheme: 'Tema editor',
wrapLongLines: 'A capo righe lunghe',
selectStatement: 'Dichiarazione select',
triggerStatement: 'Dichiarazione trigger',
sqlSecurity: 'Sicurezza SQL',
updateOption: 'Update option',
deleteView: 'Elimina vista',
createNewView: 'Crea nuova vista',
deleteTrigger: 'Elimina trigger',
createNewTrigger: 'Crea nuovo trigger',
currentUser: 'Utente attuale',
routineBody: 'Corpo della routine',
dataAccess: 'Accesso dati',
thereAreNoParameters: 'Non ci sono parametri',
createNewParameter: 'Crea nuovo parametro',
createNewRoutine: 'Crea nuova stored routine',
deleteRoutine: 'Elimina stored routine',
functionBody: 'Corpo della funzione',
createNewFunction: 'Crea nuova funzione',
deleteFunction: 'Elimina funzione',
schedulerBody: 'Corpo dello scheduler',
createNewScheduler: 'Crea nuovo scheduler',
deleteScheduler: 'Elimina scheduler',
preserveOnCompletion: 'Preserva al completamento',
enableSsl: 'Abilita SSL',
manualValue: 'Valore manuale',
tableFiller: 'Riempitore Tabella',
fakeDataLanguage: 'Lingua dati falsi',
searchForElements: 'Cerca elementi',
selectAll: 'Seleziona tutto',
queryDuration: 'Durata query',
includeBetaUpdates: 'Includi aggiornamenti beta',
setNull: 'Imposta NULL',
processesList: 'Lista processi',
processInfo: 'Info processo',
manageUsers: 'Gestisci utenti',
createNewSchema: 'Crea nuovo schema',
schemaName: 'Nome schema',
editSchema: 'Modifica schema',
deleteSchema: 'Elimina schema',
markdownSupported: 'Markdown supportato',
plantATree: 'Pianta un albero'
},
faker: {
address: 'Indirizzo',
commerce: 'Commercio',
company: 'Compagnia',
database: 'Database',
date: 'Data',
finance: 'Finanza',
git: 'Git',
hacker: 'Hacker',
internet: 'Internet',
lorem: 'Lorem',
name: 'Nome',
music: 'Musica',
phone: 'Telefono',
random: 'Casuale',
system: 'Sistema',
time: 'Tempo',
vehicle: 'Veicolo',
zipCode: 'Codice zip',
zipCodeByState: 'Codice zip per stato',
city: 'Città',
cityPrefix: 'Prefisso città',
citySuffix: 'Suffisso città',
streetName: 'Nome strada',
streetAddress: 'Indirizzo strada',
streetSuffix: 'Suffisso strada',
streetPrefix: 'Prefisso strada',
secondaryAddress: 'Indirizzo secondario',
county: 'Contea',
country: 'Nazione',
countryCode: 'Codice nazione',
state: 'Stato',
stateAbbr: 'Abbreviazione stato',
latitude: 'Latitudine',
longitude: 'Longitudine',
direction: 'Direzione',
cardinalDirection: 'Direzione cardinale',
ordinalDirection: 'Direzione ordinale',
nearbyGPSCoordinate: 'Coordinate GPS vicine',
timeZone: 'Time zone',
color: 'Colore',
department: 'Dipartimento',
productName: 'Nome prodotto',
price: 'Prezzo',
productAdjective: 'Aggettivo prodotto',
productMaterial: 'Materiale prodotto',
product: 'Prodotto',
productDescription: 'Descrizione prodotto',
suffixes: 'Suffissi',
companyName: 'Nome compagnia',
companySuffix: 'Suffisso compagnia',
catchPhrase: 'Slogan',
bs: 'BS',
catchPhraseAdjective: 'Aggettivo slogan',
catchPhraseDescriptor: 'Descrittore slogan',
catchPhraseNoun: 'Sostantivo slogan',
bsAdjective: 'Aggettivo BS',
bsBuzz: 'Buzz BS',
bsNoun: 'Sostantivo BS',
column: 'Colonna',
type: 'Tipo',
collation: 'Confronto',
engine: 'Motore',
past: 'Passato',
future: 'Futuro',
between: 'Tra',
recent: 'Recente',
soon: 'Presto',
month: 'Mese',
weekday: 'Giorno della settimana',
account: 'Account',
accountName: 'Nome account',
routingNumber: 'Numero di instradamento',
mask: 'Maschera',
amount: 'Ammontare',
transactionType: 'Tipo transazione',
currencyCode: 'Codice valuta',
currencyName: 'Nome valuta',
currencySymbol: 'Simbolo valuta',
bitcoinAddress: 'Indirizzo Bitcoin',
litecoinAddress: 'Indirizzo Litecoin',
creditCardNumber: 'Numero carta di credito',
creditCardCVV: 'CVV carta di credito',
ethereumAddress: 'Indirizzo Ethereum',
iban: 'Iban',
bic: 'Bic',
transactionDescription: 'Descrizione transazione',
branch: 'Ramo',
commitEntry: 'Commit entry',
commitMessage: 'Messaggio di commit',
commitSha: 'SHA del commit',
shortSha: 'SHA breve',
abbreviation: 'Abbreviazione',
adjective: 'Aggettivo',
noun: 'Sostantivo',
verb: 'Verbo',
ingverb: 'Ingverb',
phrase: 'Frase',
avatar: 'Avatar',
email: 'Email',
exampleEmail: 'Email di esempio',
userName: 'Username',
protocol: 'Protocollo',
url: 'Url',
domainName: 'Nome dominio',
domainSuffix: 'Suffisso dominio',
domainWord: 'Parola dominio',
ip: 'Ip',
ipv6: 'Ipv6',
userAgent: 'User agent',
mac: 'Mac',
password: 'Password',
word: 'Parola',
words: 'Parole',
sentence: 'Sentenza',
slug: 'Slug',
sentences: 'Sentenze',
paragraph: 'Paragrafo',
paragraphs: 'Paragrafi',
text: 'Testo',
lines: 'Righe',
genre: 'Genere',
firstName: 'Nome',
lastName: 'Cognome',
middleName: 'Secondo nome',
findName: 'Nome completo',
jobTitle: 'Titolo di lavoro',
gender: 'Genere',
prefix: 'Prefisso',
suffix: 'Suffisso',
title: 'Titolo',
jobDescriptor: 'Descrittore del lavoro',
jobArea: 'Area di lavoro',
jobType: 'Tipo di lavoro',
phoneNumber: 'Numero di telefono',
phoneNumberFormat: 'Formato numeri di telefono',
phoneFormats: 'Formati di telefono',
number: 'Numero',
float: 'Float',
arrayElement: 'Elemento array',
arrayElements: 'Elementi array',
objectElement: 'Elemento object',
uuid: 'Uuid',
boolean: 'Booleano',
image: 'Immagine',
locale: 'Localizzazione',
alpha: 'Alfabetico',
alphaNumeric: 'Alfanumerico',
hexaDecimal: 'Esadecimale',
fileName: 'Nome file',
commonFileName: 'Nome file comune',
mimeType: 'Mime type',
commonFileType: 'Tipo file comune',
commonFileExt: 'Estensione file comune',
fileType: 'Tipo file',
fileExt: 'Estensione file',
directoryPath: 'Percorso directory',
filePath: 'Percorso file',
semver: 'Semver',
manufacturer: 'Produttore',
model: 'Modello',
fuel: 'Carburante',
vin: 'Vin'
}
};