Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design

# Conflicts:
#	composer.json
#	css/light-grey.scss
#	lib/composer/autoload_classmap.php
#	lib/composer/autoload_static.php
This commit is contained in:
Molkobain
2020-09-08 17:30:32 +02:00
144 changed files with 19950 additions and 1687 deletions

View File

@@ -6,7 +6,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
'CAS:Login:SignIn' => 'Sign in with CAS~~',
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
'CAS:Error:UserNotAllowed' => 'Usuário não permitido',
'CAS:Login:SignIn' => 'Autenticar com CAS',
'CAS:Login:SignInTooltip' => 'Clique aqui para se autenticar no servidor CAS',
));

View File

@@ -496,7 +496,7 @@ class CASUserProvisioning
}
// Now synchronize the profiles
LoginWebPage::SynchroniseProfiles($oUser, $aProfiles, 'CAS/LDAP Synchro');
LoginWebPage::SynchronizeProfiles($oUser, $aProfiles, 'CAS/LDAP Synchro');
phpCAS::log("Info: the user '".$oUser->GetName()."' (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
if ($oUser->IsModified())

View File

@@ -25,18 +25,18 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserLocal/Attribute:password' => 'Senha',
'Class:UserLocal/Attribute:password+' => '',
'Class:UserLocal/Attribute:expiration' => 'Password expiration~~',
'Class:UserLocal/Attribute:expiration+' => 'Password expiration status (requires an extension to have an effect)~~',
'Class:UserLocal/Attribute:expiration/Value:can_expire' => 'Can expire~~',
'Class:UserLocal/Attribute:expiration/Value:can_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:never_expire' => 'Never expire~~',
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Class:UserLocal/Attribute:expiration' => 'Expiração de senha',
'Class:UserLocal/Attribute:expiration+' => 'Status de expiraçãoo de senha (requer uma extensão para fazer efeito)',
'Class:UserLocal/Attribute:expiration/Value:can_expire' => 'Pode expirar',
'Class:UserLocal/Attribute:expiration/Value:can_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:never_expire' => 'Nunca expira',
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expirada',
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
'Class:UserLocal/Attribute:password_renewed_date' => 'Renovação de senha',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Quando a senha foi trocada antiormente',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A senha deve ter no mínimo 8 caracteres e incluir letras maiúsculas, minúsculas, números e símbolos.',
'UserLocal:password:expiration' => 'The fields below require an extension~~'
'UserLocal:password:expiration' => 'O campo abaixo requer uma extensão'
));

View File

@@ -23,67 +23,67 @@
// Database inconsistencies
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'Menu:DBToolsMenu' => 'Ferramentas de Base de Dados',
'DBTools:Class' => 'Classe',
'DBTools:Title' => 'Manutenção da Base de Dados',
'DBTools:ErrorsFound' => 'Erros Encontrados',
'DBTools:Error' => 'Erros',
'DBTools:Count' => 'Quantidade',
'DBTools:SQLquery' => 'Query SQL',
'DBTools:FixitSQLquery' => 'Query SQL para correção (sugestão)',
'DBTools:SQLresult' => 'Resultado do SQL',
'DBTools:NoError' => 'Sem problemas na base de dados',
'DBTools:HideIds' => 'Lista de erros',
'DBTools:ShowIds' => 'Visualização detalhada',
'DBTools:ShowReport' => 'Relatório',
'DBTools:IntegrityCheck' => 'Verificação de integridade',
'DBTools:FetchCheck' => 'Verificação de Busca (longo)',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Analyze' => 'Analisar',
'DBTools:Details' => 'Mostrar detalhes',
'DBTools:ShowAll' => 'Mostrar todos erros',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBTools:Inconsistencies' => 'Inconsistências na base de dados',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
'DBAnalyzer-Integrity-FinalClass' => 'Field `%2$s`.`%1$s` must have the same value as `%3$s`.`%1$s`~~',
'DBAnalyzer-Integrity-RootFinalClass' => 'Field `%2$s`.`%1$s` must contains a valid class~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Item orfão em `%1$s`, ele deveria ter seu registro irmão na tabela `%2$s`',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Chave externa inválida %1$s (coluna: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => 'Chave externa ausente %1$s (coluna: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => 'Valor inválido par %1$s (coluna: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Algumas contas de usuário não possuem perfil',
'DBAnalyzer-Fetch-Count-Error' => 'Erro na busca em `%1$s`, %2$d registros buscados / %3$d contados',
'DBAnalyzer-Integrity-FinalClass' => 'Campo `%2$s`.`%1$s` precisa ter o mesmo valor que `%3$s`.`%1$s`',
'DBAnalyzer-Integrity-RootFinalClass' => 'Campo `%2$s`.`%1$s` precisa conter uma classe válida',
));
// Database Info
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
'DBTools:DatabaseInfo' => 'Informação da base de dados',
'DBTools:Base' => 'Base',
'DBTools:Size' => 'Tamanho',
));
// Lost attachments
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments' => 'Anexos perdidos',
'DBTools:LostAttachments:Disclaimer' => 'Aqui você procurará na sua base de dados por anexos perdidos. Isto NÃO é uma ferramenta de recuperação de dados, pois não busca dados apagados.',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analisar',
'DBTools:LostAttachments:Button:Restore' => 'Recuperar',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'Esta ação não pode ser desfeita, você confirma que quer recuperar os arquivos selecionados?',
'DBTools:LostAttachments:Button:Busy' => 'Aguarde...',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:Analyze' => 'Primeiro, procure anexos perdidos pela análise da base de dados.',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Resultados da análise:',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Ótimo! Tudo parece estar nos seus devidos lugares.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Alguns anexos (%1$d) parecem estar perdidos. Verifique a lista abaixo e escolha os que você deseja mover.',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Nome do arquivo',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Local atual',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Mover para',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Resultados:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d de anexos recuperados.',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
'DBTools:LostAttachments:StoredAsInlineImage' => 'Armazenar como imagem embedada.',
'DBTools:LostAttachments:History' => 'Anexo "%1$s" recuperada com as Ferramentas de Base de Dados'
));

View File

@@ -34,13 +34,13 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Attachment:Max_Mo' => '(Tamanho máximo arquivo: %1$s Mb)',
'Attachment:Max_Ko' => '(Tamanho máximo arquivo: %1$s Kb)',
'Attachments:NoAttachment' => 'Nenhum anexo. ',
'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~',
'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~',
'Attachments:Error:UploadedFileEmpty' => 'The received file is empty and cannot be attached.
Either you have pushed an empty file,
or ask your iTop administrator if the iTop server disk is full.~~',
'Attachments:Render:Icons' => 'Display as icons~~',
'Attachments:Render:Table' => 'Display as list~~',
'Attachments:PreviewNotAvailable' => 'A pré-visualização não está disponível para este tipo de anexo.',
'Attachments:Error:FileTooLarge' => 'Arquivo muito grande para ser anexado. %1$s',
'Attachments:Error:UploadedFileEmpty' => 'O arquivo recebido está vazio e não pode ser anexado.
Ou você anexou um arquivo vazio,
ou entre em contato com o seu administrador do iTOP pois o servidor pode estar sem espaço de armazenamento.',
'Attachments:Render:Icons' => 'Mostrar como ícones',
'Attachments:Render:Table' => 'Mostrar como lista',
));
//
@@ -48,40 +48,40 @@ or ask your iTop administrator if the iTop server disk is full.~~',
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Attachment' => 'Attachment~~',
'Class:Attachment+' => '~~',
'Class:Attachment/Attribute:expire' => 'Expire~~',
'Class:Attachment/Attribute:expire+' => '~~',
'Class:Attachment/Attribute:temp_id' => 'Temporary id~~',
'Class:Attachment/Attribute:temp_id+' => '~~',
'Class:Attachment/Attribute:item_class' => 'Item class~~',
'Class:Attachment/Attribute:item_class+' => '~~',
'Class:Attachment/Attribute:item_id' => 'Item~~',
'Class:Attachment/Attribute:item_id+' => '~~',
'Class:Attachment/Attribute:item_org_id' => 'Item organization~~',
'Class:Attachment/Attribute:item_org_id+' => '~~',
'Class:Attachment/Attribute:contents' => 'Contents~~',
'Class:Attachment/Attribute:contents+' => '~~',
'Class:Attachment' => 'Anexo',
'Class:Attachment+' => '',
'Class:Attachment/Attribute:expire' => 'Expira',
'Class:Attachment/Attribute:expire+' => '',
'Class:Attachment/Attribute:temp_id' => 'Identificador temporário',
'Class:Attachment/Attribute:temp_id+' => '',
'Class:Attachment/Attribute:item_class' => 'Classe do item',
'Class:Attachment/Attribute:item_class+' => '',
'Class:Attachment/Attribute:item_id' => 'Item',
'Class:Attachment/Attribute:item_id+' => '',
'Class:Attachment/Attribute:item_org_id' => 'Organização do item',
'Class:Attachment/Attribute:item_org_id+' => '',
'Class:Attachment/Attribute:contents' => 'Conteúdo',
'Class:Attachment/Attribute:contents+' => '',
));
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Attachments:File:Thumbnail' => 'Icon~~',
'Attachments:File:Name' => 'File name~~',
'Attachments:File:Date' => 'Upload date~~',
'Attachments:File:Uploader' => 'Uploaded by~~',
'Attachments:File:Size' => 'Size~~',
'Attachments:File:MimeType' => 'Type~~',
'Attachments:File:Thumbnail' => 'Ícone',
'Attachments:File:Name' => 'Nome do arquivo',
'Attachments:File:Date' => 'Data de envio',
'Attachments:File:Uploader' => 'Enviado por',
'Attachments:File:Size' => 'Tamanho',
'Attachments:File:MimeType' => 'Tipo',
));
//
// Class: Attachment
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Attachment/Attribute:creation_date' => 'Creation date~~',
'Class:Attachment/Attribute:creation_date+' => '~~',
'Class:Attachment/Attribute:user_id' => 'User id~~',
'Class:Attachment/Attribute:user_id+' => '~~',
'Class:Attachment/Attribute:contact_id' => 'Contact id~~',
'Class:Attachment/Attribute:contact_id+' => '~~',
'Class:Attachment/Attribute:creation_date' => 'Data de criação',
'Class:Attachment/Attribute:creation_date+' => '',
'Class:Attachment/Attribute:user_id' => 'Identificador do usuário',
'Class:Attachment/Attribute:user_id+' => '',
'Class:Attachment/Attribute:contact_id' => 'Identificador do contato',
'Class:Attachment/Attribute:contact_id+' => '',
));

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

View File

@@ -437,6 +437,13 @@ class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExt
$sIcon = 'zip.png';
break;
case 'avi':
case 'mp4':
case 'mpeg':
case 'mpg':
$sIcon = 'movie.png';
break;
default:
$sIcon = 'document.png';
break;

View File

@@ -97,14 +97,14 @@ if (!class_exists('AttachmentInstaller'))
$iCount = CMDBSource::QueryToScalar($sCountQuery);
if ($iCount > 0)
{
SetupPage::log_info("Cleanup of orphan attachments that cannot be migrated to the new ObjKey model: $iCount record(s) must be deleted.");
SetupLog::Info("Cleanup of orphan attachments that cannot be migrated to the new ObjKey model: $iCount record(s) must be deleted.");
$sRepairQuery = "DELETE FROM `$sTableName` WHERE (`item_id`='' OR `item_id` IS NULL)";
$iRet = CMDBSource::Query($sRepairQuery); // Throws an exception in case of error
SetupPage::log_info("Cleanup of orphan attachments successfully completed.");
SetupLog::Info("Cleanup of orphan attachments successfully completed.");
}
else
{
SetupPage::log_info("No orphan attachment found.");
SetupLog::Info("No orphan attachment found.");
}
}
}
@@ -121,12 +121,12 @@ if (!class_exists('AttachmentInstaller'))
// get the org_id from the container object
//
// Prerequisite: change null into 0 (workaround to the fact that we cannot use IS NULL in OQL)
SetupPage::log_info("Initializing attachment/item_org_id - null to zero");
SetupLog::Info("Initializing attachment/item_org_id - null to zero");
$sTableName = MetaModel::DBGetTable('Attachment');
$sRepair = "UPDATE `$sTableName` SET `item_org_id` = 0 WHERE `item_org_id` IS NULL";
CMDBSource::Query($sRepair);
SetupPage::log_info("Initializing attachment/item_org_id - zero to the container");
SetupLog::Info("Initializing attachment/item_org_id - zero to the container");
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_org_id = 0");
$oSet = new DBObjectSet($oSearch);
$iUpdated = 0;
@@ -140,7 +140,7 @@ if (!class_exists('AttachmentInstaller'))
}
}
SetupPage::log_info("Initializing attachment/item_org_id - $iUpdated records have been adjusted");
SetupLog::Info("Initializing attachment/item_org_id - $iUpdated records have been adjusted");
}
}
}

View File

@@ -43,8 +43,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'UI-ChangeManagementOverview-Last-7-days' => 'Número de mudanças nos últimos 7 dias',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Mudanças por domínio nos últimos 7 dias',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Mudanças por status nos últimos 7 dias',
'Tickets:Related:OpenChanges' => 'Open changes~~',
'Tickets:Related:RecentChanges' => 'Recent changes (72h)~~',
'Tickets:Related:OpenChanges' => 'Mudanças abertas',
'Tickets:Related:RecentChanges' => 'Mudanças recentes (72h)',
));
// Dictionnay conventions
@@ -132,9 +132,9 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Change/Stimulus:ev_finish' => 'Fechar',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Attribute:outage' => 'Outage',
'Class:Change/Attribute:outage+' => '~~',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => 'Não',
'Class:Change/Attribute:outage/Value:no+' => '~~',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => 'Sim',
'Class:Change/Attribute:outage/Value:yes+' => '~~',
'Class:Change/Attribute:outage/Value:yes+' => '',
));

View File

@@ -8328,6 +8328,7 @@
<stylesheet id="jqueryui">../css/ui-lightness/jqueryui.scss</stylesheet>
<stylesheet id="main">../css/light-grey.scss</stylesheet>
</stylesheets>
<precompiled_stylesheet>itop-config-mgmt/precompiled-themes/light-grey/main.css</precompiled_stylesheet>
</theme>
<theme id="test-red" _delta="define">
<variables>
@@ -8343,6 +8344,7 @@
<stylesheet id="main">../css/light-grey.scss</stylesheet>
<stylesheet id="environment-banner">../css/backoffice-environment-banner.scss</stylesheet>
</stylesheets>
<precompiled_stylesheet>itop-config-mgmt/precompiled-themes/test-red/main.css</precompiled_stylesheet>
</theme>
</themes>
</branding>

View File

@@ -709,10 +709,10 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:ApplicationSolution/Attribute:status/Value:active+' => 'Ativo',
'Class:ApplicationSolution/Attribute:status/Value:inactive' => 'Inativo',
'Class:ApplicationSolution/Attribute:status/Value:inactive+' => 'Inativo',
'Class:ApplicationSolution/Attribute:redundancy' => 'Impact analysis: configuration of the redundancy~~',
'Class:ApplicationSolution/Attribute:redundancy/disabled' => 'The solution is up if all CIs are up~~',
'Class:ApplicationSolution/Attribute:redundancy/count' => 'The solution is up if at least %1$s CI(s) is(are) up~~',
'Class:ApplicationSolution/Attribute:redundancy/percent' => 'The solution is up if at least %1$s %% of the CIs are up~~',
'Class:ApplicationSolution/Attribute:redundancy' => 'Análise de impacto: configuração da redundância',
'Class:ApplicationSolution/Attribute:redundancy/disabled' => 'A solução está funcionando se todos os CIs estiverem funcionando',
'Class:ApplicationSolution/Attribute:redundancy/count' => 'A solução está funcionando se no mínimo %1$s CI(s) estiver(em) funcionando',
'Class:ApplicationSolution/Attribute:redundancy/percent' => 'A solução está funcionando se no mínimo %1$s %% dos CIs estiverem funcionando',
));
//

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,17 +22,17 @@
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Menu:ConfigEditor' => 'Configuration~~',
'config-edit-title' => 'Configuration File Editor~~',
'config-edit-intro' => 'Be very cautious when editing the configuration file.~~',
'config-apply' => 'Apply~~',
'config-apply-title' => 'Apply (Ctrl+S)~~',
'config-cancel' => 'Reset~~',
'config-saved' => 'Successfully recorded.~~',
'config-confirm-cancel' => 'Your changes will be lost.~~',
'config-no-change' => 'No change: the file has been left unchanged.~~',
'config-reverted' => 'The configuration has been reverted.~~',
'config-parse-error' => 'Line %2$d: %1$s.<br/>The file has NOT been updated.~~',
'config-current-line' => 'Editing line: %1$s~~',
'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~',
'Menu:ConfigEditor' => 'Configuração',
'config-edit-title' => 'Editor do arquivo de configuração',
'config-edit-intro' => 'Tenha cuidado ao editar o arquivo de configuração.',
'config-apply' => 'Aplicar',
'config-apply-title' => 'Aplicar (Ctrl+S)',
'config-cancel' => 'Resetar',
'config-saved' => 'Gravado com sucesso.',
'config-confirm-cancel' => 'Suas mudanças serão perdidas.',
'config-no-change' => 'Sem alteração: o arquivo ficou sem alteração.',
'config-reverted' => 'A configuração foi restaurada.',
'config-parse-error' => 'Linha %2$d: %1$s.<br/>O arquivo não foi atualizado.',
'config-current-line' => 'Editando linha: %1$s',
'config-saved-warning-db-password' => 'Salvado com sucesso, mas o backup não vai funcionar devido aos caracteres não suportados na senha da base de dados.',
));

View File

@@ -21,98 +21,98 @@
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'iTopUpdate:UI:PageTitle' => 'Application Upgrade~~',
'itop-core-update:UI:SelectUpdateFile' => 'Application Upgrade~~',
'itop-core-update:UI:ConfirmUpdate' => 'Application Upgrade~~',
'itop-core-update:UI:UpdateCoreFiles' => 'Application Upgrade~~',
'iTopUpdate:UI:MaintenanceModeActive' => 'The application is currently under maintenance, no user can access the application. You have to run a setup or restore the application archive to return in normal mode.~~',
'itop-core-update:UI:UpdateDone' => 'Application Upgrade~~',
'iTopUpdate:UI:PageTitle' => 'Atualização da Aplicação',
'itop-core-update:UI:SelectUpdateFile' => 'Atualização da Aplicação',
'itop-core-update:UI:ConfirmUpdate' => 'Atualização da Aplicação',
'itop-core-update:UI:UpdateCoreFiles' => 'Atualização da Aplicação',
'iTopUpdate:UI:MaintenanceModeActive' => 'A aplicação encontrasse em manutenção, nenhum usuário pode acessar a aplicação. Você precisa rodar o setup ou restaurar os arquivos da aplicação para voltar ao modo normal.',
'itop-core-update:UI:UpdateDone' => 'Atualização da Aplicação',
'itop-core-update/Operation:SelectUpdateFile/Title' => 'Application Upgrade~~',
'itop-core-update/Operation:ConfirmUpdate/Title' => 'Confirm Application Upgrade~~',
'itop-core-update/Operation:UpdateCoreFiles/Title' => 'Application Upgrading~~',
'itop-core-update/Operation:UpdateDone/Title' => 'Application Upgrade Done~~',
'itop-core-update/Operation:SelectUpdateFile/Title' => 'Atualização da Aplicação',
'itop-core-update/Operation:ConfirmUpdate/Title' => 'Confirma Atualização da Aplicação',
'itop-core-update/Operation:UpdateCoreFiles/Title' => 'Aplicação em atualização',
'itop-core-update/Operation:UpdateDone/Title' => 'Atualização da Aplicação Finalizada',
'iTopUpdate:UI:SelectUpdateFile' => 'Select an upgrade file to upload~~',
'iTopUpdate:UI:CheckUpdate' => 'Verify upgrade file~~',
'iTopUpdate:UI:ConfirmInstallFile' => 'You are about to install %1$s~~',
'iTopUpdate:UI:DoUpdate' => 'Upgrade~~',
'iTopUpdate:UI:CurrentVersion' => 'Current installed version~~',
'iTopUpdate:UI:NewVersion' => 'Newly installed version~~',
'iTopUpdate:UI:Back' => 'Back~~',
'iTopUpdate:UI:Cancel' => 'Cancel~~',
'iTopUpdate:UI:Continue' => 'Continue~~',
'iTopUpdate:UI:RunSetup' => 'Run Setup~~',
'iTopUpdate:UI:WithDBBackup' => 'Database backup~~',
'iTopUpdate:UI:WithFilesBackup' => 'Application files backup~~',
'iTopUpdate:UI:WithoutBackup' => 'No backup is planned~~',
'iTopUpdate:UI:Backup' => 'Backup generated before update~~',
'iTopUpdate:UI:DoFilesArchive' => 'Archive application files~~',
'iTopUpdate:UI:UploadArchive' => 'Select a package to upload~~',
'iTopUpdate:UI:ServerFile' => 'Path of a package already on the server~~',
'iTopUpdate:UI:WarningReadOnlyDuringUpdate' => 'During the upgrade, the application will be read-only.~~',
'iTopUpdate:UI:SelectUpdateFile' => 'Escolha o arquivo atualização para enviar',
'iTopUpdate:UI:CheckUpdate' => 'Verificando arquivo de atualização',
'iTopUpdate:UI:ConfirmInstallFile' => 'Você está para instalar %1$s',
'iTopUpdate:UI:DoUpdate' => 'Atualizar',
'iTopUpdate:UI:CurrentVersion' => 'Versão atual',
'iTopUpdate:UI:NewVersion' => 'Nova versão',
'iTopUpdate:UI:Back' => 'Voltar',
'iTopUpdate:UI:Cancel' => 'Cancelar',
'iTopUpdate:UI:Continue' => 'Continuar',
'iTopUpdate:UI:RunSetup' => 'Rodar setup',
'iTopUpdate:UI:WithDBBackup' => 'Backup da base de dados',
'iTopUpdate:UI:WithFilesBackup' => 'Backup dos arquivos da aplicação',
'iTopUpdate:UI:WithoutBackup' => 'Backup não planejado',
'iTopUpdate:UI:Backup' => 'Backup gerado antes da atualização',
'iTopUpdate:UI:DoFilesArchive' => 'Arquivar arquivos da aplicação',
'iTopUpdate:UI:UploadArchive' => 'Escolha um pacote para enviar',
'iTopUpdate:UI:ServerFile' => 'Caminho para o pacote já no servidor',
'iTopUpdate:UI:WarningReadOnlyDuringUpdate' => 'Durante a atualização, a aplicação ficará em modo leitura.',
'iTopUpdate:UI:Status' => 'Status~~',
'iTopUpdate:UI:Action' => 'Update~~',
'iTopUpdate:UI:History' => 'Versions History~~',
'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~',
'iTopUpdate:UI:Status' => 'Status',
'iTopUpdate:UI:Action' => 'Atualizar',
'iTopUpdate:UI:History' => 'Versões anteriores',
'iTopUpdate:UI:Progress' => 'Progresso da atualização',
'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database~~',
'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~',
'iTopUpdate:UI:DoBackup:Label' => 'Backup de arquivos e base de dados',
'iTopUpdate:UI:DoBackup:Warning' => 'Backup não recomendado devido ao espaço em disco limitado',
'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space~~',
'iTopUpdate:UI:ItopDiskSpace' => 'iTop disk space~~',
'iTopUpdate:UI:DBDiskSpace' => 'Database disk space~~',
'iTopUpdate:UI:FileUploadMaxSize' => 'File upload max size~~',
'iTopUpdate:UI:DiskFreeSpace' => 'Espaço em disco disponível',
'iTopUpdate:UI:ItopDiskSpace' => 'Espaço em disco do iTop',
'iTopUpdate:UI:DBDiskSpace' => 'Espaço em disco da base de dados',
'iTopUpdate:UI:FileUploadMaxSize' => 'Tamanho máximo de envio de arquivos',
'iTopUpdate:UI:PostMaxSize' => 'PHP ini value post_max_size: %1$s~~',
'iTopUpdate:UI:UploadMaxFileSize' => 'PHP ini value upload_max_filesize: %1$s~~',
'iTopUpdate:UI:PostMaxSize' => 'PHP ini post_max_size: %1$s',
'iTopUpdate:UI:UploadMaxFileSize' => 'PHP ini upload_max_filesize: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Loading' => 'Checking filesystem~~',
'iTopUpdate:UI:CanCoreUpdate:Error' => 'Checking filesystem failed (%1$s)~~',
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => 'Checking filesystem failed (File not exist %1$s)~~',
'iTopUpdate:UI:CanCoreUpdate:Failed' => 'Checking filesystem failed~~',
'iTopUpdate:UI:CanCoreUpdate:Yes' => 'Application can be updated~~',
'iTopUpdate:UI:CanCoreUpdate:No' => 'Application cannot be updated: %1$s~~',
'iTopUpdate:UI:CanCoreUpdate:Warning' => 'Warning: application update can fail: %1$s~~',
'iTopUpdate:UI:CanCoreUpdate:Loading' => 'Verificando arquivos de sistema',
'iTopUpdate:UI:CanCoreUpdate:Error' => 'Falha ao verificar arquivos de sistema (%1$s)',
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => 'Falha ao verificar arquivos de sistema (arquivo não existe %1$s)',
'iTopUpdate:UI:CanCoreUpdate:Failed' => 'Falha ao verificar arquivos de sistema',
'iTopUpdate:UI:CanCoreUpdate:Yes' => 'Aplicação pode ser atualizada',
'iTopUpdate:UI:CanCoreUpdate:No' => 'Aplicação não pode ser atualizada: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Warning' => 'Atenção: a atualização da aplicação pode falhar: %1$s',
// Setup Messages
'iTopUpdate:UI:SetupMessage:Ready' => 'Ready to start~~',
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Entering maintenance mode~~',
'iTopUpdate:UI:SetupMessage:Backup' => 'Database backup~~',
'iTopUpdate:UI:SetupMessage:FilesArchive' => 'Archive application files~~',
'iTopUpdate:UI:SetupMessage:CopyFiles' => 'Copy new version files~~',
'iTopUpdate:UI:SetupMessage:CheckCompile' => 'Check application upgrade~~',
'iTopUpdate:UI:SetupMessage:Compile' => 'Upgrade application and database~~',
'iTopUpdate:UI:SetupMessage:UpdateDatabase' => 'Upgrade database~~',
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => 'Exiting maintenance mode~~',
'iTopUpdate:UI:SetupMessage:UpdateDone' => 'Upgrade completed~~',
'iTopUpdate:UI:SetupMessage:Ready' => 'Pronto para começar',
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Entrando em modo manutenção',
'iTopUpdate:UI:SetupMessage:Backup' => 'Backup da base de dados',
'iTopUpdate:UI:SetupMessage:FilesArchive' => 'Arquivar arquivos da aplicação',
'iTopUpdate:UI:SetupMessage:CopyFiles' => 'Copiar nova versão de arquivos',
'iTopUpdate:UI:SetupMessage:CheckCompile' => 'Verificar atualização da aplicação',
'iTopUpdate:UI:SetupMessage:Compile' => 'Atualizar aplicação e base de dados',
'iTopUpdate:UI:SetupMessage:UpdateDatabase' => 'Atualizar base de dados',
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => 'Saindo do modo manutenção',
'iTopUpdate:UI:SetupMessage:UpdateDone' => 'Atualização completa',
// Errors
'iTopUpdate:Error:MissingFunction' => 'Impossible to start upgrade, missing function~~',
'iTopUpdate:Error:MissingFile' => 'Missing file: %1$s~~',
'iTopUpdate:Error:CorruptedFile' => 'File %1$s is corrupted~~',
'iTopUpdate:Error:BadFileFormat' => 'Upgrade file is not a zip file~~',
'iTopUpdate:Error:BadFileContent' => 'Upgrade file is not an application archive~~',
'iTopUpdate:Error:BadItopProduct' => 'Upgrade file is not compatible with your application~~',
'iTopUpdate:Error:Copy' => 'Error, cannot copy \'%1$s\' to \'%2$s\'~~',
'iTopUpdate:Error:FileNotFound' => 'File not found~~',
'iTopUpdate:Error:NoFile' => 'No file provided~~',
'iTopUpdate:Error:InvalidToken' => 'Invalid token~~',
'iTopUpdate:Error:UpdateFailed' => 'Upgrade failed ~~',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => 'The upload max size seems too small for update. Please change the PHP configuration.~~',
'iTopUpdate:Error:MissingFunction' => 'Impossível começar a atualização, função ausente',
'iTopUpdate:Error:MissingFile' => 'Faltando arquivo: %1$s',
'iTopUpdate:Error:CorruptedFile' => 'Arquivo %1$s está corrompido',
'iTopUpdate:Error:BadFileFormat' => 'O arquivo de atualização não é um ZIP',
'iTopUpdate:Error:BadFileContent' => 'O arquivo de atualização não é um arquivo da aplicação',
'iTopUpdate:Error:BadItopProduct' => 'O arquivo de atualização não é compatível com a aplicação',
'iTopUpdate:Error:Copy' => 'Erro, falha ao copiar de \'%1$s\' para \'%2$s\'',
'iTopUpdate:Error:FileNotFound' => 'Arquivo não encontrado',
'iTopUpdate:Error:NoFile' => 'Nenhum arquivo fornecido',
'iTopUpdate:Error:InvalidToken' => 'Token inválido',
'iTopUpdate:Error:UpdateFailed' => 'Atualização falhou',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => 'O tamanho máximo de envio de arquivos me parece muito pequeno para a atualização. Favor alterar as configurações do PHP.',
'iTopUpdate:UI:RestoreArchive' => 'You can restore your application from the archive \'%1$s\'~~',
'iTopUpdate:UI:RestoreBackup' => 'You can restore the database from \'%1$s\'~~',
'iTopUpdate:UI:UpdateDone' => 'Upgrade successful~~',
'Menu:iTopUpdate' => 'Application Upgrade~~',
'Menu:iTopUpdate+' => 'Application Upgrade~~',
'iTopUpdate:UI:RestoreArchive' => 'Você pode restaurar sua aplicação com o arquivo \'%1$s\'',
'iTopUpdate:UI:RestoreBackup' => 'Você pode restaurar sua base de dados com \'%1$s\'',
'iTopUpdate:UI:UpdateDone' => 'Atualizado com sucesso',
'Menu:iTopUpdate' => 'Atualização da Aplicação',
'Menu:iTopUpdate+' => 'Atualização da Aplicação',
// Missing itop entries
'Class:ModuleInstallation/Attribute:installed' => 'Installed on~~',
'Class:ModuleInstallation/Attribute:name' => 'Name~~',
'Class:ModuleInstallation/Attribute:version' => 'Version~~',
'Class:ModuleInstallation/Attribute:comment' => 'Comment~~',
'Class:ModuleInstallation/Attribute:installed' => 'Instalado em',
'Class:ModuleInstallation/Attribute:name' => 'Noome',
'Class:ModuleInstallation/Attribute:version' => 'Versão',
'Class:ModuleInstallation/Attribute:comment' => 'Comentário',
));

View File

@@ -22,9 +22,9 @@
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
// Errors
'FilesInformation:Error:MissingFile' => 'Missing file: %1$s~~',
'FilesInformation:Error:CorruptedFile' => 'File %1$s is corrupted~~',
'FilesInformation:Error:CantWriteToFile' => 'Can not write to file %1$s~~',
'FilesInformation:Error:MissingFile' => 'Faltando arquivo: %1$s',
'FilesInformation:Error:CorruptedFile' => 'Arquivo %1$s está corrompido',
'FilesInformation:Error:CantWriteToFile' => 'Sem permissão de escrita no arquivo %1$s',
));

View File

@@ -182,218 +182,218 @@ try
switch ($sOperation)
{
case 'check_before_backup':
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$sDBBackupPath = APPROOT.'data/backups/manual';
$aChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath);
$bFailed = false;
foreach ($aChecks as $oCheckResult)
{
if ($oCheckResult->iSeverity==CheckResult::ERROR)
{
$bFailed = true;
ReportError($oCheckResult->sLabel, -2);
}
}
if (!$bFailed)
{
// Continue the checks
$fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath);
if ($fFreeSpace!==false)
{
$sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath));
ReportSuccess($sMessage);
}
else
{
ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
}
}
break;
case 'do_backup':
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
try
{
if (MetaModel::GetConfig()->Get('demo_mode')) throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
SetupPage::log_info('Backup starts...');
set_time_limit(0);
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
$iSuffix = 1;
$sSuffix = '';
// Generate a unique name...
do
{
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
$sSuffix = '-'.$iSuffix;
$iSuffix++ ;
}
while (file_exists($sBackupFile));
$oBackup = DoBackup($sBackupFile);
$aErrors = $oBackup->GetErrors();
if (count($aErrors)>0)
{
SetupPage::log_error('Backup failed.');
SetupPage::log_error(implode("\n", $aErrors));
ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
}
else
{
SetupPage::log_info('Backup successfully completed.');
ReportSuccess(Dict::S('iTopHub:BackupOk'));
}
}
catch (Exception $e)
{
SetupPage::log_error($e->getMessage());
ReportError($e->getMessage(), $e->getCode());
}
break;
case 'compile':
SetupPage::log_info('Deployment starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
{
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
// First step: prepare the datamodel, if it fails, roll-back
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', array());
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', array());
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
if ($oConfig->Get('demo_mode')) throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
$aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
// Everything seems Ok so far, commit in env-production!
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
$oRuntimeEnv->Commit();
// Report the success in a way that will be detected by the ajax caller
SetupPage::log_info('Compilation completed...');
ReportSuccess('Ok'); // No access to Dict::S here
break;
case 'move_to_production':
// Second step: update the schema and the data
// Everything happening below is based on env-production
$oRuntimeEnv = new RunTimeEnvironment('production', true);
try
{
SetupPage::log_info('Move to production starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
{
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
unlink(APPROOT.'data/hub/compile_authent');
// Load the "production" config file to clone & update it
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
SetupUtils::EnterReadOnlyMode($oConfig);
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$aSelectedModules = array();
foreach ($aAvailableModules as $sModuleId => $aModule)
$sDBBackupPath = APPROOT.'data/backups/manual';
$aChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath);
$bFailed = false;
foreach ($aChecks as $oCheckResult)
{
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE))
if ($oCheckResult->iSeverity==CheckResult::ERROR)
{
continue;
$bFailed = true;
ReportError($oCheckResult->sLabel, -2);
}
}
if (!$bFailed)
{
// Continue the checks
$fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath);
if ($fFreeSpace!==false)
{
$sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath));
ReportSuccess($sMessage);
}
else
{
$aSelectedModules[] = $sModuleId;
ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
}
}
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
break;
case 'do_backup':
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
// Record the installation so that the "about box" knows about the installed modules
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
$oExtensionsMap = new iTopExtensionsMap();
// Default choices = as before
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
try
{
// Plus all "remote" extensions
if ($oExtension->sSource==iTopExtension::SOURCE_REMOTE)
if (MetaModel::GetConfig()->Get('demo_mode')) throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
SetupLog::Info('Backup starts...');
set_time_limit(0);
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
$iSuffix = 1;
$sSuffix = '';
// Generate a unique name...
do
{
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
$sSuffix = '-'.$iSuffix;
$iSuffix++ ;
}
while (file_exists($sBackupFile));
$oBackup = DoBackup($sBackupFile);
$aErrors = $oBackup->GetErrors();
if (count($aErrors)>0)
{
SetupLog::Error('Backup failed.');
SetupLog::Error(implode("\n", $aErrors));
ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
}
else
{
SetupLog::Info('Backup successfully completed.');
ReportSuccess(Dict::S('iTopHub:BackupOk'));
}
}
$aSelectedExtensionCodes = array();
foreach ($oExtensionsMap->GetChoices() as $oExtension)
catch (Exception $e)
{
$aSelectedExtensionCodes[] = $oExtension->sCode;
SetupLog::Error($e->getMessage());
ReportError($e->getMessage(), $e->getCode());
}
$aSelectedExtensions = $oExtensionsMap->GetChoices();
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
break;
case 'compile':
SetupLog::Info('Deployment starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
{
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
// First step: prepare the datamodel, if it fails, roll-back
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', array());
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', array());
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
if ($oConfig->Get('demo_mode')) throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
$aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
// Everything seems Ok so far, commit in env-production!
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
$oRuntimeEnv->Commit();
// Report the success in a way that will be detected by the ajax caller
SetupPage::log_info('Deployment successfully completed.');
ReportSuccess(Dict::S('iTopHub:CompiledOK'));
}
catch (Exception $e)
{
if(file_exists(APPROOT.'data/hub/compile_authent'))
SetupLog::Info('Compilation completed...');
ReportSuccess('Ok'); // No access to Dict::S here
break;
case 'move_to_production':
// Second step: update the schema and the data
// Everything happening below is based on env-production
$oRuntimeEnv = new RunTimeEnvironment('production', true);
try
{
SetupLog::Info('Move to production starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
{
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
unlink(APPROOT.'data/hub/compile_authent');
// Load the "production" config file to clone & update it
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
SetupUtils::EnterReadOnlyMode($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$aSelectedModules = array();
foreach ($aAvailableModules as $sModuleId => $aModule)
{
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE))
{
continue;
}
else
{
$aSelectedModules[] = $sModuleId;
}
}
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
// Record the installation so that the "about box" knows about the installed modules
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
$oExtensionsMap = new iTopExtensionsMap();
// Default choices = as before
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
{
// Plus all "remote" extensions
if ($oExtension->sSource==iTopExtension::SOURCE_REMOTE)
{
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
}
}
$aSelectedExtensionCodes = array();
foreach ($oExtensionsMap->GetChoices() as $oExtension)
{
$aSelectedExtensionCodes[] = $oExtension->sCode;
}
$aSelectedExtensions = $oExtensionsMap->GetChoices();
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
// Report the success in a way that will be detected by the ajax caller
SetupLog::Info('Deployment successfully completed.');
ReportSuccess(Dict::S('iTopHub:CompiledOK'));
}
catch (Exception $e)
{
if(file_exists(APPROOT.'data/hub/compile_authent'))
{
unlink(APPROOT.'data/hub/compile_authent');
}
// Note: at this point, the dictionnary is not necessarily loaded
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
ReportError($e->getMessage(), $e->getCode());
}
finally
{
SetupUtils::ExitReadOnlyMode();
}
// Note: at this point, the dictionnary is not necessarily loaded
SetupPage::log_error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupPage::log_error('Debug trace: '.$e->getTraceAsString());
ReportError($e->getMessage(), $e->getCode());
}
finally
{
SetupUtils::ExitReadOnlyMode();
}
break;
default:
ReportError("Invalid operation: '$sOperation'", -1);
ReportError("Invalid operation: '$sOperation'", -1);
}
}
catch (Exception $e)
{
SetupPage::log_error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupPage::log_error('Debug trace: '.$e->getTraceAsString());
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
utils::PopArchiveMode();

View File

@@ -233,7 +233,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Incident/Stimulus:ev_reopen+' => '',
'Class:Incident/Error:CannotAssignParentIncidentIdToSelf' => 'Não é possível atribuir o incidente principal ao próprio incidente',
'Class:Incident/Method:ResolveChildTickets' => 'ResolveChildTickets~~',
'Class:Incident/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:Incident/Method:ResolveChildTickets+' => 'Conecte a resolução ao ticket filho (ev_autoresolve) e alinhe as seguintes características: service, team, agent, resolution info',
'Tickets:Related:OpenIncidents' => 'Incidentes abertos',
));

View File

@@ -61,7 +61,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Abrir</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'pt-br', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
'Portal:Form:Close:Warning' => 'Você deseja abandonar esta página? Os dados digitados podem ser perdidos.',
));
// UserProfile brick
@@ -111,7 +111,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Brick:Portal:Manage:All' => 'Todos',
'Brick:Portal:Manage:Group' => 'Group',
'Brick:Portal:Manage:fct:count' => 'Total',
'Brick:Portal:Manage:fct:sum' => 'Sum~~',
'Brick:Portal:Manage:fct:sum' => 'Soma',
'Brick:Portal:Manage:fct:avg' => 'Média',
'Brick:Portal:Manage:fct:min' => 'Min',
'Brick:Portal:Manage:fct:max' => 'Max',
@@ -125,12 +125,12 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Brick:Portal:Object:Form:View:Title' => '%1$s : %2$s',
'Brick:Portal:Object:Form:Stimulus:Title' => 'Por favor, preencha as seguintes informações:',
'Brick:Portal:Object:Form:Message:Saved' => 'Salvo',
'Brick:Portal:Object:Form:Message:ObjectSaved' => '%1$s salvo~~',
'Brick:Portal:Object:Form:Message:ObjectSaved' => '%1$s salvo',
'Brick:Portal:Object:Search:Regular:Title' => 'Selecionar %1$s (%2$s)',
'Brick:Portal:Object:Search:Hierarchy:Title' => 'Selecinar %1$s (%2$s)',
'Brick:Portal:Object:Copy:TextToCopy' => '%1$s: %2$s~~',
'Brick:Portal:Object:Copy:Tooltip' => 'Copy object link~~',
'Brick:Portal:Object:Copy:CopiedTooltip' => 'Copied~~'
'Brick:Portal:Object:Copy:TextToCopy' => '%1$s: %2$s',
'Brick:Portal:Object:Copy:Tooltip' => 'Copiar',
'Brick:Portal:Object:Copy:CopiedTooltip' => 'Copiado'
));
// CreateBrick brick

View File

@@ -1014,8 +1014,8 @@ table .group-actions {
/****************/
/* Filter brick */
/****************/
.tile.tile-filter-brick .tile_decoration .icon {
color: #da7014;
.tile.tile-filter-brick a.tile_decoration {
cursor: default;
}
.tile.tile-filter-brick .tile_filterbox .form-group:first-child {
width: 100%;

View File

@@ -1077,8 +1077,8 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
/****************/
/* Filter brick */
/****************/
.tile.tile-filter-brick .tile_decoration .icon {
color: $link-color;
.tile.tile-filter-brick a.tile_decoration {
cursor: default;
}
.tile.tile-filter-brick .tile_filterbox .form-group:first-child{

View File

@@ -18,7 +18,7 @@
function ExportStartExport() {
var oParams = {};
oParams.operation = 'export_build';
oParams.operation = 'export_build_portal';
oParams.format = sFormat;
oParams.token = sToken;
oParams.start = 1;
@@ -56,7 +56,7 @@ function ExportRun(data) {
$('#export-close').show();
}
else {
oParams.operation = 'export_build';
oParams.operation = 'export_build_portal';
}
$.post(GetAbsoluteUrlAppRoot() + 'pages/ajax.render.php', oParams, function (data) {

View File

@@ -84,8 +84,9 @@ class BrowseBrickController extends BrickController
$sDataLoading = ($sDataLoading !== null) ? $sDataLoading : $oRequestManipulator->ReadParam('sDataLoading',
$oBrick->GetDataLoading());
// Getting search value
$sSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
if (!empty($sSearchValue))
$sRawSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
$sSearchValue = html_entity_decode($sRawSearchValue);
if (strlen($sSearchValue) > 0)
{
$sDataLoading = AbstractBrick::ENUM_DATA_LOADING_LAZY;
}
@@ -167,13 +168,16 @@ class BrowseBrickController extends BrickController
// Adding search clause
// Note : For know the search is naive and looks only for the exact match. It doesn't search for words separately
if (!empty($sSearchValue))
if (strlen($sSearchValue) > 0)
{
// - Cleaning the search value by exploding and trimming spaces
$aSearchValues = explode(' ', $sSearchValue);
array_walk($aSearchValues, function (&$sSearchValue /*, $sKey*/) {
trim($sSearchValue);
});
$aExplodedSearchValues = explode(' ', $sSearchValue);
$aSearchValues = [];
foreach ($aExplodedSearchValues as $sValue) {
if (strlen($sValue) > 0) {
$aSearchValues[] = $sValue;
}
}
// - Retrieving fields to search
$aSearchFields = array($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['name_att']);
@@ -257,7 +261,7 @@ class BrowseBrickController extends BrickController
{
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->SetSelectedClasses($aLevelsClasses);
if (!empty($sSearchValue))
if (strlen($sSearchValue) > 0)
{
// Note : This could be way more simpler if we had a SetInternalParam($sParam, $value) verb
$aQueryParams = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetInternalParams();
@@ -452,7 +456,7 @@ class BrowseBrickController extends BrickController
'sBrickId' => $sBrickId,
'sBrowseMode' => $sBrowseMode,
'aBrowseButtons' => $aBrowseButtons,
'sSearchValue' => $sSearchValue,
'sSearchValue' => $sRawSearchValue,
'sDataLoading' => $sDataLoading,
'aItems' => json_encode($aItems),
'iItemsCount' => count($aItems),

View File

@@ -894,64 +894,50 @@ class ManageBrickController extends BrickController
$oRequestManipulator = $this->get('request_manipulator');
// Getting search value
$sSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
$sRawSearchValue = trim($oRequestManipulator->ReadParam('sSearchValue', ''));
$sSearchValue = html_entity_decode($sRawSearchValue);
// - Adding search clause if necessary
// Note : This is a very naive search at the moment
if (!empty($sSearchValue))
{
if (strlen($sSearchValue) > 0) {
// Putting only valid attributes as one can define attributes of leaf classes in the brick definition (<fields>), but at this stage we are working on the abstract class.
// Note: This won't fix everything as the search will not be looking in all fields.
$aSearchListItems = array();
foreach ($aColumnsAttrs as $sColumnAttr)
{
// Skip invalid attcodes
if (!MetaModel::IsValidAttCode($sClass, $sColumnAttr))
{
$aSearchListItems = [];
foreach ($aColumnsAttrs as $sColumnAttr) {
// Skip invalid attCodes
if (!MetaModel::IsValidAttCode($sClass, $sColumnAttr)) {
continue;
}
// For external key, force search on the friendlyname instead of the ID.
// This should be addressed more globally with the bigger issue, see N°1970
$oAttDef = MetaModel::GetAttributeDef($sClass, $sColumnAttr);
if($oAttDef instanceof AttributeExternalKey)
{
if ($oAttDef instanceof AttributeExternalKey) {
$sColumnAttr .= '_friendlyname';
}
$aSearchListItems[] = $sColumnAttr;
}
$oFullBinExpr = null;
foreach ($aSearchListItems as $sSearchItemAttr)
{
$oBinExpr = new BinaryExpression(new FieldExpression($sSearchItemAttr, $oQuery->GetClassAlias()),
'LIKE', new VariableExpression('search_value'));
// At each iteration we build the complete expression for the search like ( (field1 LIKE %search%) OR (field2 LIKE %search%) OR (field3 LIKE %search%) ...)
if (is_null($oFullBinExpr))
{
$oFullBinExpr = $oBinExpr;
}
else
{
$oFullBinExpr = new BinaryExpression($oFullBinExpr, 'OR', $oBinExpr);
if (preg_match('/^"(.*)"$/', $sSearchValue, $aMatches)) {
// The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
$aSearchNeedles = [$aMatches[1]];
} else {
// Split the text on the blanks and treat this as a search for <word1> AND <word2> AND <word3>
$aExplodedSearchNeedles = explode(' ', $sSearchValue);
$aSearchNeedles = [];
foreach ($aExplodedSearchNeedles as $sValue) {
if (strlen($sValue) > 0) {
$aSearchNeedles[] = $sValue;
}
}
}
// Then add the complete expression to the query
if (!is_null($oFullBinExpr))
{
// - Adding expression to the query
$oQuery->AddConditionExpression($oFullBinExpr);
// - Setting expression parameters
// Note : This could be way more simpler if we had a SetInternalParam($sParam, $value) verb
$aQueryParams = $oQuery->GetInternalParams();
$aQueryParams['search_value'] = '%'.$sSearchValue.'%';
$oQuery->SetInternalParams($aQueryParams);
foreach ($aSearchNeedles as $sSearchWord) {
$oQuery->AddCondition_FullTextOnAttributes($aSearchListItems, $sSearchWord);
}
}
$aData['sSearchValue'] = $sSearchValue;
$aData['sSearchValue'] = $sRawSearchValue;
}
/**

View File

@@ -25,7 +25,6 @@ use Exception;
/**
* Class ItopExtensionsExtraRoutes
*
* @deprecated Compatibility layer for migrating brick's routes to iTop 2.7+
* @package Combodo\iTop\Portal\Routing
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
@@ -39,8 +38,6 @@ class ItopExtensionsExtraRoutes
* @param array $extraRoutes
*
* @throws Exception
* @deprecated Since 2.7.0
*
*/
public static function AddRoutes($extraRoutes)
{

View File

@@ -44,140 +44,148 @@
"defaultContent": "",
"type": "html",
"data": oLevelsProperties[sKey].alias,
"render": function(data, type, row){
var cellElem;
var levelAltId = data.level_alias+'_'+data.id;
var levelActions;
var levelActionsKeys;
var drilldownActionIndex;
var levelPrimaryAction;
var url = '';
// Preparing actions on the cell
levelActions = oLevelsProperties[data.level_alias].actions;
// - Removing explicit (not default) drilldown action as it has no prupose on that browse mode
delete levelActions['{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}'];
// - Removing implciit (default) drilldown action
if( (levelActions['default'] !== undefined) && (levelActions['default'].type === '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}') )
{
delete levelActions['default'];
}
levelActionsKeys = Object.keys(levelActions);
// Preparing the cell data
cellElem = (levelActionsKeys.length > 0) ? $('<a></a>') : $('<span></span>');
cellElem.attr('data-item-id', data.id).attr('data-level-alias', data.level_alias);
"render":
{_: function(data, type, row){
var cellElem;
var levelAltId = data.level_alias+'_'+data.id;
var levelActions;
var levelActionsKeys;
var drilldownActionIndex;
var levelPrimaryAction;
var url = '';
// Building metadata
for(var sPropName in data.metadata)
{
var propValue = data.metadata[sPropName];
cellElem.attr('data-'+sPropName.replace('_', '-'), propValue);
}
// Building tooltip for the node
// We have to concatenate the HTML as we return the raw HTML of the cell. If we did a jQuery.insertAfter, the tooltip would not be returned.
// For the same reason, tooltip widget is created in "drawCallback" instead of here.
if( (data.tooltip !== undefined) && (data.tooltip !== ''))
{
cellElem.html( $('<span></span>').attr('title', data.tooltip).attr('data-toggle', 'tooltip').html(data.name).prop('outerHTML') );
}
else
{
cellElem.html(data.name);
}
// Building actions
if(levelActionsKeys.length > 0)
{
// - Primary action (click on item)
levelPrimaryAction = levelActions[levelActionsKeys[0]];
switch(levelPrimaryAction.type)
// Preparing actions on the cell
levelActions = oLevelsProperties[data.level_alias].actions;
// - Removing explicit (not default) drilldown action as it has no prupose on that browse mode
delete levelActions['{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}'];
// - Removing implciit (default) drilldown action
if( (levelActions['default'] !== undefined) && (levelActions['default'].type === '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}') )
{
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = levelPrimaryAction.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[levelPrimaryAction.type]);
break;
default:
url = '#';
//console.log('Action "'+levelPrimaryAction.type+'" not implemented');
break;
delete levelActions['default'];
}
SetActionUrl(cellElem, url);
SetActionOpeningTarget(cellElem, levelPrimaryAction.opening_target);
levelActionsKeys = Object.keys(levelActions);
// - Secondary actions
if(levelActionsKeys.length > 1)
// Preparing the cell data
cellElem = (levelActionsKeys.length > 0) ? $('<a></a>') : $('<span></span>');
cellElem.attr('data-item-id', data.id).attr('data-level-alias', data.level_alias);
// Building metadata
for(var sPropName in data.metadata)
{
// Retrieving secondary action (Now we also display primary action)
var actionsButtons = {};
for(j = 0; j < levelActionsKeys.length; j++)
{
actionsButtons[levelActionsKeys[j]] = levelActions[levelActionsKeys[j]];
}
// Preparing secondary actions container
var actionsElem = $('<div></div>').addClass('pull-right group-actions');
cellElem.append(actionsElem);
// Preparing secondary actions
var actionsSSTogglerElem = $('<a class="glyphicon glyphicon-menu-hamburger" data-toggle="collapse" data-target="#item-actions-menu-'+levelAltId+'"></a>');
var actionsSSMenuElem = $('<div id="item-actions-menu-'+levelAltId+'" class="item-action-wrapper panel panel-default"></div>');
var actionsSSMenuContainerElem = $('<div class="panel-body"></div>');
actionsSSMenuElem.append(actionsSSMenuContainerElem);
actionsElem.append(actionsSSTogglerElem);
actionsElem.append(actionsSSMenuElem);
var propValue = data.metadata[sPropName];
cellElem.attr('data-'+sPropName.replace('_', '-'), propValue);
}
// Adding secondary actions
for(j in actionsButtons)
// Building tooltip for the node
// We have to concatenate the HTML as we return the raw HTML of the cell. If we did a jQuery.insertAfter, the tooltip would not be returned.
// For the same reason, tooltip widget is created in "drawCallback" instead of here.
if( (data.tooltip !== undefined) && (data.tooltip !== ''))
{
cellElem.html( $('<span></span>').attr('title', data.tooltip).attr('data-toggle', 'tooltip').html(data.name).prop('outerHTML') );
}
else
{
cellElem.html(data.name);
}
// Building actions
if(levelActionsKeys.length > 0)
{
// - Primary action (click on item)
levelPrimaryAction = levelActions[levelActionsKeys[0]];
switch(levelPrimaryAction.type)
{
var action = actionsButtons[j];
var actionElem = $('<a></a>');
var actionIconElem = $('<span></span>').appendTo(actionElem);
switch(action.type)
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = levelPrimaryAction.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[levelPrimaryAction.type]);
break;
default:
url = '#';
//console.log('Action "'+levelPrimaryAction.type+'" not implemented');
break;
}
SetActionUrl(cellElem, url);
SetActionOpeningTarget(cellElem, levelPrimaryAction.opening_target);
// - Secondary actions
if(levelActionsKeys.length > 1)
{
// Retrieving secondary action (Now we also display primary action)
var actionsButtons = {};
for(j = 0; j < levelActionsKeys.length; j++)
{
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = action.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[action.type]);
break;
default:
url = '#';
//console.log('Action "'+action.type+'" not implemented for secondary action');
break;
actionsButtons[levelActionsKeys[j]] = levelActions[levelActionsKeys[j]];
}
SetActionUrl(actionElem, url);
SetActionOpeningTarget(actionElem, action.opening_target);
// Adding title if present
if(action.title !== undefined)
// Preparing secondary actions container
var actionsElem = $('<div></div>').addClass('pull-right group-actions');
cellElem.append(actionsElem);
// Preparing secondary actions
var actionsSSTogglerElem = $('<a class="glyphicon glyphicon-menu-hamburger" data-toggle="collapse" data-target="#item-actions-menu-'+levelAltId+'"></a>');
var actionsSSMenuElem = $('<div id="item-actions-menu-'+levelAltId+'" class="item-action-wrapper panel panel-default"></div>');
var actionsSSMenuContainerElem = $('<div class="panel-body"></div>');
actionsSSMenuElem.append(actionsSSMenuContainerElem);
actionsElem.append(actionsSSTogglerElem);
actionsElem.append(actionsSSMenuElem);
// Adding secondary actions
for(j in actionsButtons)
{
actionElem.attr('title', action.title);
var action = actionsButtons[j];
var actionElem = $('<a></a>');
var actionIconElem = $('<span></span>').appendTo(actionElem);
switch(action.type)
{
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = action.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[action.type]);
break;
default:
url = '#';
//console.log('Action "'+action.type+'" not implemented for secondary action');
break;
}
SetActionUrl(actionElem, url);
SetActionOpeningTarget(actionElem, action.opening_target);
// Adding title if present
if(action.title !== undefined)
{
actionElem.attr('title', action.title);
}
// Adding icon class if present
if(action.icon_class !== undefined)
{
actionIconElem.addClass(action.icon_class);
}
actionElem.append(action.title);
actionsSSMenuContainerElem.append( $('<p></p>').append(actionElem) );
}
// Adding icon class if present
if(action.icon_class !== undefined)
{
actionIconElem.addClass(action.icon_class);
}
actionElem.append(action.title);
actionsSSMenuContainerElem.append( $('<p></p>').append(actionElem) );
}
}
}
return cellElem.prop('outerHTML');
return cellElem.prop('outerHTML');
},
filter:function (data, type, row) {
return $.text($.parseHTML(data.name));
},
sort:function (data, type, row) {
return $.text($.parseHTML(data.name));
},
},
});
@@ -195,25 +203,29 @@
"defaultContent": "",
"type": "html",
"data": oLevelsProperties[sKey].alias+".fields."+oLevelsProperties[sKey].fields[i].code,
"render": function(data, type, row){
var cellElem = $('<span></span>');
// Building value and metadata
for(var sPropName in data)
"render":
{
var sPropValue = data[sPropName];
if(sPropName === 'value_html')
{
cellElem.html(sPropValue);
}
else
{
cellElem.attr('data-'+sPropName.replace('_', '-'), sPropValue);
}
}
_: function (data, type, row) {
var cellElem = $('<span></span>');
return cellElem.prop('outerHTML');
},
// Building value and metadata
for (var sPropName in data) {
var sPropValue = data[sPropName];
if (sPropName === 'value_html') {
cellElem.html(sPropValue);
} else {
cellElem.attr('data-' + sPropName.replace('_', '-'), sPropValue);
}
}
return cellElem.prop('outerHTML');
},
sort: function (data, type, row) {
return $.text($.parseHTML(data['value_html']));
},
filter: function (data, type, row) {
return $.text($.parseHTML(data['value_html']));
},
},
});
}
}

View File

@@ -10,10 +10,9 @@
<div class="col-xs-12 col-sm-{{ brick.GetWidth }}">
{% block pTileWrapper %}
<div class="tile tile-filter-brick" id="brick-{{ brick.GetId }}" data-brick-id="{{ brick.GetId }}">
<div class="tile_decoration">
<a href="#" onclick="return false;" class="tile_decoration">
<span class="icon {{ brick.GetDecorationClassHome }}"></span>
</div>
</a>
<div class="tile_body">
<div class="tile_title">{{ brick.GetTitleHome|dict_s }}</div>
{% if brick.HasDescription %}

View File

@@ -158,8 +158,11 @@
return cellElem.prop('outerHTML');
},
sort: function (attribute_code, type, row) {
return row.attributes[attribute_code].sort_value;
return row.attributes[attribute_code].sort_value;
},
filter: function (attribute_code, type, row) {
return $.text($.parseHTML(row.attributes[attribute_code]['value_html']));
},
},
});
}

View File

@@ -87,7 +87,7 @@
{% else %}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery-migrate.prod.min.js'|add_itop_version }}"></script>
{% endif %}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery-ui-1.11.4.custom.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery-ui.custom.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.magnific-popup.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.iframe-transport.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.fileupload.js'|add_itop_version }}"></script>

View File

@@ -259,7 +259,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserRequest/Stimulus:ev_wait_for_approval+' => '',
'Class:UserRequest/Error:CannotAssignParentRequestIdToSelf' => 'Não é possível atribuir a solicitação principal para a própria solicitação',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets~~',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:UserRequest/Method:ResolveChildTickets+' => 'Conecte a resolução a pedidos filhos (ev_autoresolve) e alinhe as seguintes características da requisição: serviço, equipe, agente, info de resolução',
));

View File

@@ -287,7 +287,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Portal:LanguageChangedTo_Lang' => 'Linguagem alterada para',
'Portal:ChooseYourFavoriteLanguage' => 'Escolha sua linguagem favorita',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets~~',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:UserRequest/Method:ResolveChildTickets+' => 'Conecte a resolução a pedidos filhos (ev_autoresolve) e alinhe as seguintes características da requisição: serviço, equipe, agente, info de resolução',
));

View File

@@ -345,8 +345,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:ServiceSubcategory/Attribute:request_type/Value:incident+' => 'Incidente',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request' => 'Solicitação serviço',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request+' => 'Solicitação serviço',
'Class:ServiceSubcategory/Attribute:service_provider' => 'Provider Name~~',
'Class:ServiceSubcategory/Attribute:service_org_id' => 'Provider~~',
'Class:ServiceSubcategory/Attribute:service_provider' => 'Nome do provedor',
'Class:ServiceSubcategory/Attribute:service_org_id' => 'Provedor',
));
//
@@ -427,16 +427,16 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:lnkSLAToSLT/Attribute:slt_id+' => '',
'Class:lnkSLAToSLT/Attribute:slt_name' => 'Nome SLT',
'Class:lnkSLAToSLT/Attribute:slt_name+' => '',
'Class:lnkSLAToSLT/Attribute:slt_metric' => 'SLT metric~~',
'Class:lnkSLAToSLT/Attribute:slt_metric+' => '~~',
'Class:lnkSLAToSLT/Attribute:slt_request_type' => 'SLT request type~~',
'Class:lnkSLAToSLT/Attribute:slt_request_type+' => '~~',
'Class:lnkSLAToSLT/Attribute:slt_ticket_priority' => 'SLT ticket priority~~',
'Class:lnkSLAToSLT/Attribute:slt_ticket_priority+' => '~~',
'Class:lnkSLAToSLT/Attribute:slt_value' => 'SLT value~~',
'Class:lnkSLAToSLT/Attribute:slt_value+' => '~~',
'Class:lnkSLAToSLT/Attribute:slt_value_unit' => 'SLT value unit~~',
'Class:lnkSLAToSLT/Attribute:slt_value_unit+' => '~~',
'Class:lnkSLAToSLT/Attribute:slt_metric' => 'Métrica SLT',
'Class:lnkSLAToSLT/Attribute:slt_metric+' => '',
'Class:lnkSLAToSLT/Attribute:slt_request_type' => 'Tipo de requisição SLT',
'Class:lnkSLAToSLT/Attribute:slt_request_type+' => '',
'Class:lnkSLAToSLT/Attribute:slt_ticket_priority' => 'Prioridade do ticket SLT',
'Class:lnkSLAToSLT/Attribute:slt_ticket_priority+' => '',
'Class:lnkSLAToSLT/Attribute:slt_value' => 'Valor do SLT',
'Class:lnkSLAToSLT/Attribute:slt_value+' => '',
'Class:lnkSLAToSLT/Attribute:slt_value_unit' => 'Unidade de valor do SLT',
'Class:lnkSLAToSLT/Attribute:slt_value_unit+' => '',
));
//

View File

@@ -84,7 +84,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Ticket/Attribute:operational_status/Value:resolved+' => '',
'Class:Ticket/Attribute:operational_status/Value:closed' => 'Fechado',
'Class:Ticket/Attribute:operational_status/Value:closed+' => '',
'Ticket:ImpactAnalysis' => 'Análise de Impacto~~',
'Ticket:ImpactAnalysis' => 'Análise de Impacto',
));
@@ -194,27 +194,27 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'WorkOrder:Moreinfo' => 'Mais informações',
'Tickets:ResolvedFrom' => 'Resolvido automaticamente de %1$s',
'Class:cmdbAbstractObject/Method:Set' => 'Set~~',
'Class:cmdbAbstractObject/Method:Set' => 'Set',
'Class:cmdbAbstractObject/Method:Set+' => 'Defina um campo com um valor estático',
'Class:cmdbAbstractObject/Method:Set/Param:1' => 'Target Field',
'Class:cmdbAbstractObject/Method:Set/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:Set/Param:1+' => 'O campo para definir, no objeto atual',
'Class:cmdbAbstractObject/Method:Set/Param:2' => 'Valor',
'Class:cmdbAbstractObject/Method:Set/Param:2+' => 'O valor para definir',
'Class:cmdbAbstractObject/Method:SetCurrentDate' => 'SetCurrentDate',
'Class:cmdbAbstractObject/Method:SetCurrentDate+' => 'Defina um campo com a data e hora atual',
'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1' => 'Target Field',
'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1+' => 'O campo para definir, no objeto atual',
'Class:cmdbAbstractObject/Method:SetCurrentUser' => 'SetCurrentUser',
'Class:cmdbAbstractObject/Method:SetCurrentUser+' => 'Defina um campo com o usuário atualmente logado',
'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1' => 'Target Field',
'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1+' => 'O campo para definir, no objeto atual. Se o campo for uma string, o nome amigável será usado, caso contrário, o identificador será usado. Esse nome amigável é o nome da pessoa, se houver alguma anexada ao usuário, caso contrário, é o login.',
'Class:cmdbAbstractObject/Method:SetCurrentPerson' => 'SetCurrentPerson~~',
'Class:cmdbAbstractObject/Method:SetCurrentPerson' => 'SetCurrentPerson',
'Class:cmdbAbstractObject/Method:SetCurrentPerson+' => 'Defina um campo com a pessoa atualmente logada (a \\"pessoa\\" anexada ao \\"usuário\\").',
'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1' => 'Target Field~~',
'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1+' => 'O campo para definir, no objeto atual. Se o campo for uma string, o nome amigável será usado, caso contrário, o identificador será usado. ',
'Class:cmdbAbstractObject/Method:SetElapsedTime' => 'SetElapsedTime~~',
'Class:cmdbAbstractObject/Method:SetElapsedTime' => 'SetElapsedTime',
'Class:cmdbAbstractObject/Method:SetElapsedTime+' => 'Defina um campo com o tempo (segundos) decorrido desde a data dada por outro campo',
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1' => 'Target Field~~',
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1+' => 'O campo para definir, no objeto atual',
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2' => 'Campo de Referência',
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2+' => 'O campo do qual obter a data de referência',
@@ -222,24 +222,24 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:3+' => 'Deixe em branco para confiar no esquema padrão de horas de trabalho, ou configure para \\"DefaultWorkingTimeComputer\\" para forçar um esquema de 24x7',
'Class:cmdbAbstractObject/Method:Reset' => 'Reset',
'Class:cmdbAbstractObject/Method:Reset+' => 'Redefinir um campo para seu valor padrão',
'Class:cmdbAbstractObject/Method:Reset/Param:1' => 'Target Field~~',
'Class:cmdbAbstractObject/Method:Reset/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:Reset/Param:1+' => 'O campo para redefinir, no objeto atual',
'Class:cmdbAbstractObject/Method:Copy' => 'Copy~~',
'Class:cmdbAbstractObject/Method:Copy' => 'Cop',
'Class:cmdbAbstractObject/Method:Copy+' => 'Copie o valor de um campo para outro campo',
'Class:cmdbAbstractObject/Method:Copy/Param:1' => 'Target Field~~',
'Class:cmdbAbstractObject/Method:Copy/Param:1' => 'Campo alvo',
'Class:cmdbAbstractObject/Method:Copy/Param:1+' => 'O campo para definir, no objeto atual',
'Class:cmdbAbstractObject/Method:Copy/Param:2' => 'Source Field~~',
'Class:cmdbAbstractObject/Method:Copy/Param:2' => 'Campo de origem',
'Class:cmdbAbstractObject/Method:Copy/Param:2+' => 'O campo para obter o valor de, no objeto atual',
'Class:cmdbAbstractObject/Method:ApplyStimulus' => 'ApplyStimulus~~',
'Class:cmdbAbstractObject/Method:ApplyStimulus' => 'ApplyStimulus',
'Class:cmdbAbstractObject/Method:ApplyStimulus+' => 'Aplique o estímulo especificado ao objeto atual',
'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1' => 'Código de estímulo',
'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1+' => 'Um código de estímulo válido para a classe atual',
'Class:ResponseTicketTTO/Interface:iMetricComputer' => 'Time To Own~~',
'Class:ResponseTicketTTO/Interface:iMetricComputer' => 'Time To Own',
'Class:ResponseTicketTTO/Interface:iMetricComputer+' => 'Objetivo baseado em um SLT do tipo TTO',
'Class:ResponseTicketTTR/Interface:iMetricComputer' => 'Time To Resolve~~',
'Class:ResponseTicketTTR/Interface:iMetricComputer' => 'Time To Resolve',
'Class:ResponseTicketTTR/Interface:iMetricComputer+' => 'Objetivo baseado em um SLT do tipo TTR',
'portal:itop-portal' => 'Standard portal~~', // This is the portal name that will be displayed in portal dispatcher (eg. URL in menus)
'portal:itop-portal' => 'Portal do usuário', // This is the portal name that will be displayed in portal dispatcher (eg. URL in menus)
'Page:DefaultTitle' => 'iTop - Portal do Usuário',
'Brick:Portal:UserProfile:Title' => 'Meu Perfil',
'Brick:Portal:NewRequest:Title' => 'Nova Solicitação',
@@ -248,5 +248,5 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Brick:Portal:OngoingRequests:Title+' => '<p>Acompanhar suas solicitações em andamento, adicionar comentários, anexar documentos e confirmar a solução.</p>',
'Brick:Portal:OngoingRequests:Tab:OnGoing' => 'Abrir',
'Brick:Portal:OngoingRequests:Tab:Resolved' => 'Resolvido',
'Brick:Portal:ClosedRequests:Title' => 'Fechar solicitações',
'Brick:Portal:ClosedRequests:Title' => 'Solicitações Fechadas',
));