Compare commits

...

32 Commits
dist ... master

Author SHA1 Message Date
FreeScout
863ad60308 Show latest laravel-YYYY-MM-DD.log file by default in App Logs 2026-10-06 06:37:05 -07:00
FreeScout
23b371c4f0 Take into account archived mailboxes in User::mailboxesIdsCanView() 2026-10-06 01:11:29 -07:00
FreeScout
164303763d Merge pull request #5708 from il2020/fix-tables
Tables in emails: don't break words
2026-10-06 10:24:39 +03:00
il2020
b1e9249cd2 Tables in emails: don't break words 2026-10-06 10:44:23 +04:00
FreeScout
17f060ee9a Merge pull request #5706 from il2020/fix-closing-block
Fix sidebar blocks flicker on mobile when opened/closed
2026-10-06 09:04:32 +03:00
FreeScout
7fe68073f4 Merge pull request #5705 from seansch/fix/mobile-table-width
Fix mobile table width to avoid unnecessary scrolling
2026-10-06 09:00:33 +03:00
FreeScout
d772126165 Merge pull request #5704 from il2020/fix-long-tap
Select conversation on native long press so selection matches haptic feedback
2026-10-06 08:55:52 +03:00
FreeScout
4bf6a84223 Update SECURITY.md 2026-10-05 22:45:19 -07:00
FreeScout
67f23e88a2 Mask DB credentials in logs 2026-10-05 22:25:53 -07:00
FreeScout
cd450e819d Mask DB credentials in logs 2026-10-05 21:39:34 -07:00
FreeScout
b753c63924 Avoid reading user from DB when logging errors - closes #5707 2026-10-05 10:33:03 -07:00
il2020
773981de78 Fix sidebar blocks flicker on mobile when opened/closed 2026-10-05 15:09:09 +04:00
FreeScout
b4332f105f Update Readme 2026-10-04 10:34:28 -07:00
Sean Schoonover
ffd758438d Fix mobile table width to avoid unnecessary scrolling 2026-10-04 12:35:19 -04:00
il2020
a6bb63c9fe Select conversation on native long press so selection matches haptic feedback 2026-10-04 18:00:32 +04:00
FreeScout
bff838fa0e Merge pull request #5703 from il2020/master
Conversations list (mobile): remove the leftover 250px width of the customer line
2026-10-04 16:18:28 +03:00
il2020
7ec40b691a fix 2026-10-04 15:50:57 +04:00
FreeScout
041d7e09b2 Merge pull request #5702 from il2020/fix-height
Mobile conversation list: subject fader covers the row's bottom borde…
2026-10-04 14:08:43 +03:00
FreeScout
a8290b421d Merge pull request #5701 from il2020/fix-border
Fix thick bottom border of the customer block in conversation on mobile
2026-10-04 13:23:15 +03:00
il2020
8788b4a8e6 Mobile conversation list: subject fader covers the row's bottom border when the mailbox name is shown 2026-10-04 14:19:11 +04:00
il2020
f14358c5fe Fix thick bottom border of the customer block in conversation on mobile 2026-10-04 14:15:46 +04:00
FreeScout
f1b35d0d5f Merge pull request #5700 from il2020/master
Conversations list (mobile): fix the first line of a conversation row
2026-10-04 13:13:09 +03:00
il2020
649d868c62 Conversations list (mobile): fix the first line of a conversation row 2026-10-04 11:38:24 +04:00
FreeScout
8fe96f83a7 Fix conversations list Assignee column width - closes #5695 2026-10-03 22:03:47 -07:00
FreeScout
cf951ea20b Merge pull request #5699 from il2020/master
Conversations list: keep the thread counter visible when the customer name is long
2026-10-04 07:55:07 +03:00
il2020
4de254f7cd Conversations list: keep the thread counter visible when the customer name is long 2026-10-04 00:13:30 +04:00
FreeScout
a1e876f82d Merge pull request #5698 from il2020/master
Allow pinch zoom on Android: add maximum-scale=1 to the viewport meta tag only for non-Android devices
2026-10-03 20:09:20 +03:00
il2020
48c4fac6b4 Allow pinch zoom on Android: add maximum-scale=1 to the viewport meta tag only for non-Android devices 2026-10-03 19:11:49 +04:00
FreeScout
eec09ff173 Merge pull request #5697 from il2020/master
Keep aspect ratio of shrunk images with inline height in conversation view
2026-10-03 17:33:16 +03:00
FreeScout
63546323af Update German translation 2026-10-03 06:50:00 -07:00
il2020
4a8bd527e3 Keep aspect ratio of shrunk images with inline height in conversation view 2026-10-03 16:45:02 +04:00
FreeScout
4de16c62b8 Add __safe_raw_html() to translation manager config 2026-10-03 05:36:18 -07:00
13 changed files with 333 additions and 37 deletions

View File

@@ -39,6 +39,7 @@ If you want to support the project feel free to **star this repository**. It hel
* Multilingual (translated into 33 languages).
* Seamless email integration (via SMTP, IMAP, POP3, etc).
* Modern OAuth authentication for Microsoft Office 365 and Google Workspace.
* [Progressive Web App](https://freescout.net/progressive-app/) for phones and desktops (installable from browser and sending Web Push notifications).
* Native [S3 storage](https://github.com/freescout-help-desk/S3Storage) support.
* Fully supports screen readers (for visually impaired).
* Web installer & updater.
@@ -67,7 +68,7 @@ Mobile apps support the same functionality and modules as the web version of you
<a href="https://freescout.net/android-app/" target="_blank" rel="nofollow"><img alt="Android App" src="https://freescout-helpdesk.github.io/img/apps/android.png" width="200px" /></a> <a href="https://freescout.net/ios-app/" target="_blank" rel="nofollow"><img alt="iOS App" src="https://freescout-helpdesk.github.io/img/apps/ios.png?v=1" width="200px" /></a>
[MacOS Menu Bar App](https://github.com/jonalaniz/scouter)
[Progressive Web App for phones and desktops](https://freescout.net/progressive-app/) | [MacOS Menu Bar App](https://github.com/jonalaniz/scouter)
## Requirements

View File

@@ -11,7 +11,7 @@ Read about **[FreeScout's Security](https://freescout.net/security/)**.
* One issue per Advisory — do not put several issues into one Advisory, as GitHub will not assign a CVE to such an Advisory.
* CVEs are requested after the fix for the vulnerability is released.
* If you found an issue related to the `APP_LIMIT_USER_CUSTOMER_VISIBILITY=true` mode, make sure to read the [FAQ](https://github.com/freescout-help-desk/freescout/wiki/FAQ#is-it-possible-to-have-separate-contactscustomers-per-mailbox).
* If you found an issue related to the "Manage » Settings » Customer Visibility" option (`APP_LIMIT_USER_CUSTOMER_VISIBILITY=true`), make sure to read the [FAQ](https://github.com/freescout-help-desk/freescout/wiki/FAQ#is-it-possible-to-have-separate-contactscustomers-per-mailbox).
* Support agents are allowed to move conversations to any mailbox, even to ones they don't have access to.
* Drafts are viewable/discardable by any member of the mailbox where they are created.
* FreeScout loads external images in received emails, and there is a Module allowing to disable loading external images: https://freescout.net/module/block-external-images/.

View File

@@ -4,6 +4,8 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Support\Facades\Auth;
use Throwable;
class Handler extends ExceptionHandler
{
@@ -26,6 +28,26 @@ class Handler extends ExceptionHandler
'password_confirmation',
];
/**
* True while an exception is being reported. Protects against
* recursive reporting (an exception thrown while reporting another one).
*
* @var bool
*/
protected $is_reporting = false;
/**
* Classes/namespaces whose stack frame arguments may contain DB credentials
* (host, username and password are passed as arguments when connecting).
*
* @var array
*/
protected static $sensitive_frame_prefixes = [
'Illuminate\Database\Connectors\\',
'Doctrine\DBAL\Driver\\',
'PDO',
];
/**
* Report or log an exception.
*
@@ -37,7 +59,123 @@ class Handler extends ExceptionHandler
*/
public function report(Exception $exception)
{
parent::report($exception);
// If an exception occurs while another one is being reported
// (for example the database is down and something in the reporting
// chain queries it), do not report it again to avoid an infinite
// loop and gigantic log files.
if ($this->is_reporting) {
return;
}
$this->is_reporting = true;
try {
// Do not write DB credentials from the stack trace to the logs.
$this->maskSensitiveTraceArgs($exception);
parent::report($exception);
} finally {
$this->is_reporting = false;
}
}
/**
* Replace string arguments (which may contain DB host, username and
* password) of the sensitive stack frames with asterisks (the first
* 2 symbols are left untouched), so that they
* are not written to the logs. Applies to the whole chain of previous
* exceptions.
*
* @param \Exception $exception
*
* @return void
*/
protected function maskSensitiveTraceArgs($exception)
{
try {
$property = new \ReflectionProperty(\Exception::class, 'trace');
// Has no effect since PHP 8.1 and is deprecated since PHP 8.5.
if (PHP_VERSION_ID < 80100) {
$property->setAccessible(true);
}
$depth = 0;
while ($exception && $depth < 20) {
$trace = $property->getValue($exception);
if (is_array($trace)) {
$changed = false;
foreach ($trace as $i => $frame) {
if (empty($frame['args']) || !is_array($frame['args'])) {
continue;
}
$class = isset($frame['class']) ? $frame['class'] : '';
foreach (self::$sensitive_frame_prefixes as $prefix) {
if ($class !== '' && strpos($class, $prefix) === 0) {
foreach ($frame['args'] as $arg_index => $arg) {
if (is_string($arg)) {
$trace[$i]['args'][$arg_index] = $this->maskString($arg);
}
}
$changed = true;
break;
}
}
}
if ($changed) {
$property->setValue($exception, $trace);
}
}
$exception = $exception->getPrevious();
$depth++;
}
} catch (Throwable $e) {
// Do nothing.
}
}
/**
* Mask a string: keep the first 2 symbols and replace the rest with asterisks.
* Strings of 2 symbols or less are masked completely.
*
* @param string $string
*
* @return string
*/
protected function maskString($string)
{
if (mb_strlen($string) <= 2) {
return '***';
}
return mb_substr($string, 0, 2).'***';
}
/**
* Get the default context variables for logging.
*
* Same as in Laravel 5.8+: only the user ID is added (no email).
*
* @return array
*/
protected function context()
{
// Try to avoid reading user from DB.
// https://github.com/freescout-help-desk/freescout/issues/5707
$guard = Auth::guard();
$user_id = $guard->getSession()->get($guard->getName());
/*if (!$user_id) {
$user_id = Auth::id();
}*/
try {
return array_filter([
'userId' => $user_id,
]);
} catch (Throwable $e) {
return [];
}
}
/**

View File

@@ -139,6 +139,8 @@ class Mailbox extends Model
const DEFAULT_SIGNATURE = '<br><span style="color:#808080;">--<br>
{%mailbox.name%}</span>';
const META_STATE = 'st';
/**
* Default values.
*/
@@ -229,7 +231,7 @@ class Mailbox extends Model
*/
public function getStateAttribute()
{
return $this->getMeta('st', self::STATE_ACTIVE);
return $this->getMeta(self::META_STATE, self::STATE_ACTIVE);
}
public function setStateAttribute($value)
@@ -238,7 +240,7 @@ class Mailbox extends Model
if (!in_array($value, [self::STATE_ACTIVE, self::STATE_ARCHIVED])) {
$value = self::STATE_ACTIVE;
}
$this->setMeta('st', $value);
$this->setMeta(self::META_STATE, $value);
}
/**

View File

@@ -1805,6 +1805,14 @@ class Helper
return (int)$request->cookie('in_app');
}
public static function isAndroid($request = null)
{
if (!$request) {
$request = app('request');
}
return stripos($request->server('HTTP_USER_AGENT') ?? '', 'Android') !== false;
}
/**
* Customers list view mode: cards (default) or table.
* The cookie is set from JS (see setCustomersView() in main.js).

View File

@@ -335,12 +335,23 @@ class User extends Authenticatable
if ($this->isAdmin()) {
return Mailbox::pluck('id')->toArray();
} else {
return $this->mailboxes()->pluck('mailboxes.id')->toArray();
$mailboxes = $this->mailboxes()->pluck('mailboxes.meta', 'mailboxes.id');
// Exclude archived mailboxes.
return $mailboxes->filter(function ($meta) {
$meta = json_decode($meta, true);
if (!isset($meta[Mailbox::META_STATE])) {
return true;
}
return $meta[Mailbox::META_STATE] == Mailbox::STATE_ACTIVE;
})->keys()->toArray();
}
}
public function hasAccessToMailbox($mailbox_id)
{
if ($this->isAdmin()) {
return true;
}
$ids = $this->mailboxesIdsCanView();
return in_array($mailbox_id, $ids);
}

View File

@@ -84,6 +84,7 @@ return [
'__',
'__j',
'__h',
'__safe_raw_html',
'$trans.get',
],

View File

@@ -156,6 +156,38 @@ class LaravelLogViewer
return basename($this->file ?? '');
}
/**
* Select the log file to display by default: the latest "laravel-*" file
* (by date in the file name), otherwise the most recently modified file.
*
* @param array $files Full paths of log files.
* @return string
*/
protected function getLatestLogFile(array $files)
{
$laravel_files = [];
foreach ($files as $file) {
if (preg_match('/^laravel-.*\.log$/', basename($file))) {
$laravel_files[] = $file;
}
}
if (count($laravel_files)) {
// laravel-YYYY-MM-DD.log names sort chronologically.
usort($laravel_files, function ($a, $b) {
return strcmp(basename($b), basename($a));
});
return $laravel_files[0];
}
usort($files, function ($a, $b) {
return @filemtime($b) <=> @filemtime($a);
});
return $files[0];
}
/**
* @return array
*/
@@ -168,7 +200,7 @@ class LaravelLogViewer
if (!count($log_file)) {
return [];
}
$this->file = $log_file[0];
$this->file = $this->getLatestLogFile($log_file);
}
$max_file_size = function_exists('config') ? config('logviewer.max_file_size', self::MAX_FILE_SIZE) : self::MAX_FILE_SIZE;

100
public/css/style.css vendored
View File

@@ -1535,6 +1535,22 @@ table.table-conversations td.conv-attachment {
.table-conversations .conv-customer {
width: 150px;
}
/* Only the name is truncated, so the counter always stays visible */
.conv-customer-line {
display: flex;
align-items: baseline;
}
.conv-customer-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
.conv-customer-line .conv-counter {
flex-shrink: 0;
/* As with inline padding, the padding must not make the line taller */
margin-top: -1px;
margin-bottom: -1px;
}
.table-conversations .conv-spam .conv-customer a {
color: #93a1af;
}
@@ -1574,7 +1590,7 @@ table.table-conversations td.conv-attachment {
.conv-counter {
background: #97a3ad;
color: #fff;
line-height: 17px;
line-height: 14px;
position: relative;
padding: 1px 5px;
margin-left: 2px;
@@ -1590,6 +1606,14 @@ table.table-conversations td.conv-attachment {
margin-top: 2px;
padding-bottom: 8px;
}
.table-conversations .conv-owner {
width: 160px;
}
.table-conversations td.conv-owner a {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.table-conversations .conv-number {
width: 86px;
}
@@ -1725,8 +1749,10 @@ button.conv-checkbox-clear {
height: 80px;
border-bottom: 1px solid #e3e8eb;
}
/* The mailbox name adds a line (20.1px) to the preview. With 97px the subject's link
ended below the row, and its fader whitened the row's bottom border */
.table.table-conversations.show-mailbox tbody tr {
height: 97px;
height: 100px;
}
.table-conversations .conv-attachment-mobile
@@ -1763,8 +1789,13 @@ button.conv-checkbox-clear {
top: 0;
margin-left: 10px!important;
}
/* Stretch to the date, leaving room for it */
.table.table-conversations td.conv-customer {
width: auto;
inset-inline-start: 0;
inset-inline-end: 110px;
}
.conv-customer a {
width: 350px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -1783,6 +1814,27 @@ button.conv-checkbox-clear {
background-color: transparent!important;
font-weight: normal;
}
/* The link's ellipsis truncates the assignee, so it gets the assignee's style */
.table-conversations td.conv-customer a {
color: #93a1af;
font-weight: normal;
}
.conv-customer-line {
display: inline;
color: #2a3b47;
}
.conv-active .conv-customer-line {
font-weight: bold;
}
.conv-spam .conv-customer-line {
color: #93a1af;
}
/* Leave room for the counter and the assignee */
.conv-customer-name {
display: inline-block;
max-width: 60%;
vertical-align: top;
}
.conv-counter {
top: -1px;
font-size: 10px;
@@ -1845,11 +1897,6 @@ button.conv-checkbox-clear {
display: block;
}
}
@media (max-width:700px) {
.conv-customer a {
width: 250px;
}
}
/**
* Conversation
@@ -2458,33 +2505,31 @@ button.conv-checkbox-clear {
.thread-content img {
max-width: 100%;
}
/* Keep aspect ratio when max-width shrinks an image with width/height attributes */
/* Keep aspect ratio when max-width shrinks an image with width/height attributes.
!important overrides inline height set by Outlook (style="width:13.3in;height:6.6in"). */
.thread-content img[width] {
height: auto;
height: auto !important;
}
/* Fit wide tables (e.g. from Outlook) into the thread instead of scrolling it horizontally.
overflow-wrap: anywhere lets columns shrink below the longest word when there is no room.
Words are not broken: a table that is still wider than the thread because of its longest words
(like a long link) scrolls the thread. overflow-wrap: anywhere broke words even when there was room,
e.g. in a one-column table of IDs a bit wider than the width set by Outlook.
Cell widths are reset as Outlook sets arbitrary percentages (like 1.7% for a column with long text),
which would squeeze such columns to one letter per line. */
which would squeeze such columns to one word per line. */
.thread-content table {
max-width: 100%;
}
.thread-content td,
.thread-content th {
overflow-wrap: anywhere;
width: auto !important;
}
/* On phones there is no room to fit a table without breaking every word,
/* On phones a fitted table would have one word per line,
so the table is scrolled horizontally on its own instead of the whole thread. */
@media (max-width:700px) {
.thread-content table {
display: block;
overflow-x: auto;
width: max-content !important;
}
.thread-content td,
.thread-content th {
overflow-wrap: normal;
width: auto !important;
}
}
.conv-new #conv-toolbar {
@@ -2966,6 +3011,12 @@ ul.sidebar-block-list {
.conv-sidebar-block .panel {
background-color: #fff;
}
/* Overrides the border and shadow of .panel-group .panel: the collapsed panel is empty
and its border made the bottom border of the customer block 3px thick */
.conv-sidebar-block .panel-group .panel {
border: 0;
box-shadow: none;
}
.conv-sidebar-block .panel-group {
margin: 0;
}
@@ -2985,6 +3036,17 @@ ul.sidebar-block-list {
display: none!important;
height: 0!important;
}
/* While animating, Bootstrap replaces .collapse with .collapsing, the rules above don't apply
and the block was animated the opposite way: on "close" it grew and only then disappeared,
on open it appeared after a delay. Show the final state at once instead:
aria-expanded is the state Bootstrap is switching to */
.conv-sidebar-block .collapsing[aria-expanded="true"] {
display: none!important;
}
.conv-sidebar-block .collapsing[aria-expanded="false"] {
display: block!important;
height: auto!important;
}
.customer-social-profiles {
white-space: normal;
max-width: none;

36
public/js/main.js vendored
View File

@@ -5189,17 +5189,39 @@ function conversationsTableInit()
// if ("ontouchstart" in window)
// {
$(document).ready(function() {
$('.conv-row').on('contextmenu', function(event) {
event.preventDefault();
event.stopPropagation();
});
// Toggle the row only once per press: on touch devices
// both contextmenu and taphold may fire for the same press.
var toggleRow = function(row) {
if ($(row).data('conv_toggled')) {
return;
}
$(row).data('conv_toggled', true);
$('.conv-row').on('taphold', {duration: 700}, function(event) {
var row = $(event.target).parents('.conv-row');
var checkbox = $(row).find('input.conv-checkbox');
$(checkbox).prop('checked', !checkbox.prop('checked'));
$(checkbox).trigger('change');
$(row).toggleClass('selected');
};
$('.conv-row').on('touchstart mousedown', function(event) {
$(this).data('conv_touch', event.type == 'touchstart');
$(this).data('conv_toggled', false);
});
$('.conv-row').on('contextmenu', function(event) {
event.preventDefault();
event.stopPropagation();
// The browser fires contextmenu after its native long press
// (with haptic feedback on Android), on press or on release,
// which may happen before taphold.
if ($(this).data('conv_touch')) {
toggleRow(this);
}
});
$('.conv-row').on('taphold', {duration: 700}, function(event) {
toggleRow(this);
});
});
//}
@@ -6222,4 +6244,4 @@ function initMergeCustomers()
}
});
});
}
}

View File

@@ -47,7 +47,6 @@
":person started the conversation": ":person hat das Gespräch gestartet",
":user is replying": ":user antwortet",
":user is viewing": ":user betrachtet",
"Receiving emails need to be configured for the mailbox in order to fetch emails from your support email address": "Der E-Mail Empfang muss für dieses Postfach konfiguriert werden",
"<strong>Administrators<\/strong> can create new users and have access to all mailboxes and settings": "<strong>Administratoren<\/strong> können neue Benutzer erstellen und haben Zugriff auf alle Postfächer und Einstellungen",
"<strong>Users<\/strong> have access to the mailbox(es) specified in their permissions": "<strong>Benutzer<\/strong> haben Zugriff auf die Postfächer, die in ihren Berechtigungen festgelegt wurden",
"A conversation :person is following is updated": "Ein Gespräch dem :person folgt wurde aktualisiert",
@@ -55,6 +54,8 @@
"A conversation is assigned to :person": "Ein Gespräch wurde :person zugewiesen",
"A conversation is assigned to me": "Ein Gespräch wurde mir zugewiesen",
"A conversation is assigned to someone else": "Ein Gespräch wurde jemand anderem zugewiesen",
"A new internal conversation is created and the user is connected to it": "Eine neue interne Unterhaltung wird erstellt und der Benutzer damit verbunden.",
"A new reply is added to an internal conversation and the user is connected to it": "Eine neue Antwort wird einer internen Unterhaltung hinzugefügt und der Benutzer wird damit verbunden.",
"A new version is available": "Eine neue Version ist verfügbar",
"Accept Chat": "Chat akzeptieren",
"Accepted for delivery": "Akzeptiert zur Zustellung",
@@ -88,6 +89,7 @@
"Aliases": "Aliasse",
"Aliases are other email addresses that also forward to your mailbox address. Separate each email with a comma.": "Aliase sind E-Mail-Adressen die zu diesem Postfach weitergeleitet werden. Trennen Sie jede E-Mail-Adresse mit einem Komma.",
"All": "Alle",
"All customers": "Alle Kunden",
"All from current mailbox": "Alle aus dem aktuellen Postfach",
"Allow to reply from aliases": "Antworten von Alias Adressen erlauben",
"Alternate Emails": "Alternative E-Mail-Adressen",
@@ -115,6 +117,7 @@
"Auto Reply status saved": "Automatische Antwort gespeichert",
"Auto replies don't include your mailbox signature, so be sure to add your contact information if necessary.": "Automatische Antworten beinhalten nicht die Postfach-Signatur. Fügen Sie Ihre Kontaktinformationen hinzu wenn benötigt.",
"Auto reply to customer": "Automatische Antwort an den Kunden",
"Autoplay is disabled in your browser. Click anywhere on this page to enable notification sounds, or allow Autoplay in your browser settings.": "Die automatische Wiedergabe ist in Ihrem Browser deaktiviert. Klicken Sie an eine beliebige Stelle auf dieser Seite, um Benachrichtigungstöne zu aktivieren, oder erlauben Sie die automatische Wiedergabe in Ihren Browsereinstellungen.",
"Back": "Zurück",
"Back to folder": "Zurück zum Ordner",
"Background Jobs": "Hintergrundaufgaben",
@@ -124,6 +127,7 @@
"Browser": "Browser",
"Cancel": "Abbrechen",
"Cannot merge the same customer": "Die Zusammenführung derselben Kundendaten ist nicht möglich.",
"Cards View": "Kartenansicht",
"Cc": "CC",
"Change": "Ändern",
"Change Customer": "Kunde ändern",
@@ -202,6 +206,7 @@
"Customer": "Kunde",
"Customer Name": "Kundenname",
"Customer Profile": "Kundenprofil",
"Customer Visibility": "Kundensichtbarkeit",
"Customer changed": "Kunde geändert",
"Customer saved successfully.": "Kunde erfolgreich gespeichert.",
"Customer viewed :when": "Kunde betrachtete :when",
@@ -426,11 +431,13 @@
"Make sure to :%link_start%enable less secure apps:%link_end% in your Google account to send emails from Gmail.": "Sicherstellen, dass :%link_start%enable less secure apps:%link_end% in Ihrem Google-Konto zum Senden der E-Mails aktiviert ist.",
"Make sure to save settings before checking connection.": "Zum Ausführen eines Verbindungstests müssen die Einstellungen zuvor gespeichert werden.",
"Make sure to save settings before testing.": "Sicherstellen, dass die Einstellungen vor dem Testen gespeichert werden.",
"Make this conversation visible to all users with mailbox access": "Diese Unterhaltung für alle Benutzer mit Postfachzugriff sichtbar machen",
"Male": "männlich",
"Manage": "Verwalten",
"Manage Mailboxes": "Postfächer verwalten",
"Manage Users": "Benutzer verwalten",
"Mark all as read": "Alle als gelesen markieren",
"Marketplace": "Marktplatz",
"Max. Message Size": "maximale Nachrichtengröße",
"Me": "Mich",
"Merge": "Zusammenführen",
@@ -503,6 +510,7 @@
"Off": "Aus",
"Older": "Älter",
"On": "Ein",
"Only customers from accessible mailboxes": "Nur Kunden mit zugänglichen Postfächern",
"Only visible in :app_name.": "Nur in :app_name sichtbar.",
"Open": "Offen",
"Open Conversation": "Gespräch öffnen",
@@ -523,6 +531,7 @@
"Password changed notification": "Benachrichtigung über die Änderung des Passworts",
"Password reset email has been sent": "E-Mail zum zurücksetzen des Passworts wurde gesendet",
"Password saved successfully!": "Passwort erfolgreich gespeichert!",
"Paste as Plain Text": "Als unformatierten Text einfügen",
"Pending": "Ausstehend",
"Permissions": "Berechtigungen",
"Permissions saved successfully": "Berechtigungen erfolgreich gespeichert",
@@ -552,12 +561,14 @@
"Profile Photo (URL)": "Profilfoto (URL)",
"Profile saved successfully": "Profil erfolgreich gespeichert",
"Protocol": "Protokoll",
"Public conversation": "Öffentliches Gespräch",
"Published": "Veröffentlicht",
"Queue": "Warteschlange",
"Queued Jobs": "Aufgaben in der Warteschlange",
"Queued and failed jobs are cleaned automatically once in a while. No need to worry or delete them manually.": "In die Warteschlange gestellte und fehlgeschlagene Jobs werden von Zeit zu Zeit automatisch bereinigt. Sie müssen sich keine Sorgen machen oder sie manuell löschen.",
"Re-send invite email": "Einladungs-E-Mail erneut senden",
"Received a new conversation": "Neues Gespräch empfangen",
"Receiving emails need to be configured for the mailbox in order to fetch emails from your support email address": "Der E-Mail Empfang muss für dieses Postfach konfiguriert werden",
"Recent": "Neueste",
"Recipient clicked a link in the message": "Der Empfänger hat auf einen Link in der Nachricht geklickt",
"Recipient complained": "Der Empfänger hat sich beschwert",
@@ -672,8 +683,10 @@
"System Emails": "System E-Mails",
"System Status": "System Status",
"System error": "System Fehler",
"Table View": "Tabellenansicht",
"Test email": "Test-E-Mail",
"The :module_name module has been deactivated due to an error: :error_message": "Das :module_name Modul wurde auf Grund des folgenden Fehlers deaktiviert : :error_message",
"The conversation you replied to could not be found.": "Die Unterhaltung, auf die Sie geantwortet haben, konnte nicht gefunden werden.",
"The following modules have to be installed and activated: :modules": "Die folgenden Module müssen installiert und aktiviert sein: :modules",
"The new password is the same as the old password.": "Das neue Passwort ist das gleiche wie das alte.",
"The original message could not be loaded from mail server, below is the latest truncated copy stored in database.": "Die original Nachricht kann nicht vom Server geladen werden, nachfolgend finden Sie die letzte - in der Datenbank gespeicherte Kopie.",
@@ -688,9 +701,9 @@
"These folders must be writable by web server user (:user).": "Der Webserver Benutzer (:user) muss für diese Ordner Schreibrechte besitzen.",
"These settings are used to send system emails (alerts to admin and invitation emails to users).": "Diese Einstellungen werden verwendet um System-E-Mails zu versenden (Warnungen an Admins und Einladungen an Benutzer).",
"Third-Party": "Drittanbieter",
"Third-Party Modules": "Drittanbietermodule",
"This is a bounce message.": "Dies ist eine Rückantwort.",
"This is a forwarded conversation.": "Dies ist ein weitergeleitetes Gespräch.",
"This is a public conversation visible to all users with mailbox access": "Dies ist eine öffentliche Unterhaltung, die für alle Benutzer mit Postfachzugriff sichtbar ist.",
"This is a quick note to let you know that your :company_name password has been successfully updated. If you didn't request this change, please contact the administrator.": "Dies ist eine kurze Benachrichtigung um Sie zu informieren, dass das Passwort von :company_name erfolgreich aktualisiert wurde.",
"This is a test mail sent by :app_name. It means that outgoing email settings of your :mailbox mailbox are fine.": "Dies ist eine Test-E-Mail gesendet von :app_name. Das bedeutet, dass die Einstellungen für ausgehende E-Mails des Postfaches :mailbox korrekt sind.",
"This is a test system mail sent by :app_name. It means that mail settings are fine.": "Dies ist eine Test-E-Mail gesendet von :app_name. Das bedeutet, dass die E-Mail-Einstellungen korrekt sind.",
@@ -752,6 +765,8 @@
"User's Name": "Name des Benutzers",
"Username": "Benutzername",
"Users": "Benutzer",
"Users and teams": "Benutzer und Teams",
"Users and teams with access": "Benutzer und Teams mit Zugriff",
"Users are allowed to delete conversations": "Benutzer sind berechtigt Gespräche zu löschen",
"Users are allowed to edit own notes\/replies": "Benutzer sind dazu berechtigt Notizen\/Antworten zu ändern",
"Users are allowed to edit\/delete saved replies": "Benutzer sind dazu berechtigt gespeicherte Antworten zu bearbeiten\/löschen",
@@ -780,6 +795,8 @@
"Welcome to :company_name, :first_name!": "Willkommen bei :company_name, :first_name!",
"Welcome to the team!": "Willkommen im Team!",
"When a customer emails this mailbox, application can send an auto reply to the customer immediately.<br\/><br\/>Only one auto reply is sent per new conversation.": "Wenn ein Kunde an dieses Postfach schreibt, kann die Anwendung automatisch antworten.<br\/><br\/>Es wird nur eine automatische Antwort pro neuem Gespräch gesendet.",
"When enabled, all users with mailbox access can view this conversation": "Wenn diese Option aktiviert ist, können alle Benutzer mit Postfachzugriff diese Unterhaltung sehen.",
"Which customers non-admin users can see.": "Welche Kunden Nicht-Administratoren sehen können.",
"Which mailboxes will user use?": "Welches E-Mail-Postfach wird der Benutzer nutzen?",
"Who Else Will Use This Mailbox": "Wer wird dieses Postfach noch benutzen?",
"Work": "Arbeit",
@@ -792,6 +809,7 @@
"You can read more about sending emails :%a_begin%here:%a_end%.": "Sie können :%a_begin%here:%a_end% mehr über den Versand von E-Mails lesen.",
"You have the latest version installed": "Die aktuellste Version ist installiert",
"You have to activate each bundle's module separately": "Jedes Modul im Paket muss separat aktiviert werden",
"You no longer have access to the conversation you replied to. Please contact your administrator.": "Sie haben keinen Zugriff mehr auf die Unterhaltung, auf die Sie geantwortet haben. Bitte wenden Sie sich an Ihren Administrator.",
"You've already sent this message just recently.": "Die Nachricht wurde grade eben bereits gesendet.",
"Your Email": "Ihre Email",
"Your Profile": "Ihr Profil",

View File

@@ -146,7 +146,7 @@
@if (empty($no_customer))
<td class="conv-customer">
<a href="{{ $conversation->url() }}" @if (!empty($params['target_blank'])) target="_blank" @endif title="{{ $conversation->customer_email }}">
@if ($conversation->customer_id && $conversation->customer){{ $conversation->customer->getFullName(true)}}@endif&nbsp;@if ($conversation->threads_count > 1)<span class="conv-counter">{{ $conversation->threads_count }}</span>@endif
<span class="conv-customer-line"><span class="conv-customer-name">@if ($conversation->customer_id && $conversation->customer){{ $conversation->customer->getFullName(true)}}@endif&nbsp;</span>@if ($conversation->threads_count > 1)<span class="conv-counter">{{ $conversation->threads_count }}</span>@endif</span>
@if ($conversation->user_id)
<small class="conv-owner-mobile text-help">
{{ ($assignee = $conversation->user) ? $assignee->getFullName() : '' }} <small class="glyphicon glyphicon-user"></small>

View File

@@ -3,7 +3,8 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
{{-- maximum-scale=1 prevents iOS from zooming in on focusing a field (#4698). Android does not zoom in on focus, but disables pinch zoom with maximum-scale. --}}
<meta name="viewport" content="width=device-width, initial-scale=1{{ \Helper::isAndroid() ? '' : ', maximum-scale=1' }}">
<meta name="robots" content="noindex,nofollow">
<!-- CSRF Token -->