Merge pull request #53850 from nextcloud/feat/noid/add-busy-status

This commit is contained in:
Maksim Sukharev 2025-08-01 09:09:44 +02:00 committed by GitHub
commit 1675aa4f45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 103 additions and 55 deletions

View file

@ -141,7 +141,7 @@ class StatusService {
$this->logger->debug("Found $count applicable event(s), changing user status", ['user' => $userId]);
$this->userStatusService->setUserStatus(
$userId,
IUserStatus::AWAY,
IUserStatus::BUSY,
IUserStatus::MESSAGE_CALENDAR_BUSY,
true
);

View file

@ -20,6 +20,7 @@ use OCP\UserStatus\IUserStatus;
* @package OCA\UserStatus\Service
*/
class PredefinedStatusService {
private const BE_RIGHT_BACK = 'be-right-back';
private const MEETING = 'meeting';
private const COMMUTING = 'commuting';
private const SICK_LEAVE = 'sick-leave';
@ -64,6 +65,15 @@ class PredefinedStatusService {
'time' => 1800,
],
],
[
'id' => self::BE_RIGHT_BACK,
'icon' => '⏳',
'message' => $this->getTranslatedStatusForId(self::BE_RIGHT_BACK),
'clearAt' => [
'type' => 'period',
'time' => 900,
],
],
[
'id' => self::REMOTE_WORK,
'icon' => '🏡',
@ -143,6 +153,9 @@ class PredefinedStatusService {
case self::REMOTE_WORK:
return '🏡';
case self::BE_RIGHT_BACK:
return '⏳';
case self::CALL:
return '💬';
@ -179,6 +192,9 @@ class PredefinedStatusService {
case self::CALL:
return $this->l10n->t('In a call');
case self::BE_RIGHT_BACK:
return $this->l10n->t('Be right back');
default:
return null;
}
@ -195,6 +211,7 @@ class PredefinedStatusService {
self::SICK_LEAVE,
self::VACATIONING,
self::OUT_OF_OFFICE,
self::BE_RIGHT_BACK,
self::REMOTE_WORK,
IUserStatus::MESSAGE_CALL,
IUserStatus::MESSAGE_AVAILABILITY,

View file

@ -14,6 +14,7 @@
:value="option"
:clearable="false"
placement="top"
label-outside
@option:selected="select" />
</div>
</template>
@ -72,12 +73,9 @@ export default {
<style lang="scss" scoped>
.clear-at-select {
display: flex;
margin-bottom: 10px;
gap: calc(2 * var(--default-grid-baseline));
align-items: center;
&__label {
margin-inline-end: 12px;
}
margin-block: 0 calc(2 * var(--default-grid-baseline));
&__select {
flex-grow: 1;

View file

@ -11,9 +11,10 @@
name="user-status-online"
@change="onChange">
<label :for="id" class="user-status-online-select__label">
{{ label }}
<NcUserStatusIcon :status="type"
class="user-status-online-select__icon"
aria-hidden="true" />
{{ label }}
<em class="user-status-online-select__subline">{{ subline }}</em>
</label>
</div>
@ -63,45 +64,42 @@ export default {
</script>
<style lang="scss" scoped>
@use 'sass:math';
$icon-size: 24px;
$label-padding: 8px;
.user-status-online-select {
&__label {
position: relative;
display: block;
margin: $label-padding;
padding: $label-padding;
padding-inline-start: $icon-size + $label-padding * 2;
border: 2px solid var(--color-main-background);
box-sizing: inherit;
display: grid;
grid-template-columns: var(--default-clickable-area) 1fr 2fr;
align-items: center;
gap: var(--default-grid-baseline);
min-height: var(--default-clickable-area);
padding: var(--default-grid-baseline);
border-radius: var(--border-radius-large);
background-color: var(--color-background-hover);
background-position: $label-padding center;
background-size: $icon-size;
span,
& {
&, & * {
cursor: pointer;
}
span {
position: absolute;
top: calc(50% - 10px);
inset-inline-start: 10px;
display: block;
width: $icon-size;
height: $icon-size;
&:hover {
background-color: var(--color-background-dark);
}
}
&__icon {
flex-shrink: 0;
max-width: 34px;
max-height: 100%;
}
&__input:checked + &__label {
outline: 2px solid var(--color-main-text);
background-color: var(--color-background-dark);
box-shadow: 0 0 0 4px var(--color-main-background);
}
&__input:focus-visible + &__label {
outline: 2px solid var(--color-primary-element) !important;
background-color: var(--color-background-dark);
}
&__subline {

View file

@ -81,10 +81,19 @@ export default {
flex-basis: 100%;
border-radius: var(--border-radius);
align-items: center;
min-height: 44px;
min-height: var(--default-clickable-area);
padding-inline: var(--default-grid-baseline);
&, & * {
cursor: pointer;
}
&:hover {
background-color: var(--color-background-dark);
}
&--icon {
flex-basis: 40px;
flex-basis: var(--default-clickable-area);
text-align: center;
}
@ -106,11 +115,13 @@ export default {
&__label:active {
outline: 2px solid var(--color-main-text);
box-shadow: 0 0 0 4px var(--color-main-background);
background-color: var(--color-background-dark);
border-radius: var(--border-radius-large);
}
&__input:focus-visible + &__label {
outline: 2px solid var(--color-primary-element) !important;
background-color: var(--color-background-dark);
border-radius: var(--border-radius-large);
}
}

View file

@ -78,6 +78,7 @@ export default {
.predefined-statuses-list {
display: flex;
flex-direction: column;
margin-bottom: 10px;
gap: var(--default-grid-baseline);
margin-block: 0 calc(2 * var(--default-grid-baseline));
}
</style>

View file

@ -65,7 +65,8 @@ export default {
flex-basis: 100%;
border-radius: var(--border-radius);
align-items: center;
min-height: 44px;
min-height: var(--default-clickable-area);
padding-inline: var(--default-grid-baseline);
&:hover,
&:focus {
@ -77,7 +78,7 @@ export default {
}
&__icon {
flex-basis: 40px;
flex-basis: var(--default-clickable-area);
text-align: center;
}

View file

@ -5,8 +5,8 @@
<template>
<NcModal size="normal"
:name="$t('user_status', 'Set status')"
aria-labelledby="user_status-set-dialog"
label-id="user_status-set-dialog"
dark
:set-return-focus="setReturnFocus"
@close="closeModal">
<div class="set-status-modal">
@ -336,6 +336,10 @@ export default {
.set-status-modal {
padding: 8px 20px 20px 20px;
&, & * {
box-sizing: border-box;
}
&__header {
font-size: 21px;
text-align: center;
@ -343,12 +347,14 @@ export default {
min-height: var(--default-clickable-area);
line-height: var(--default-clickable-area);
overflow-wrap: break-word;
margin-block: 0 12px;
margin-block: 0 calc(2 * var(--default-grid-baseline));
}
&__online-status {
display: grid;
grid-template-columns: 1fr 1fr;
display: flex;
flex-direction: column;
gap: calc(2 * var(--default-grid-baseline));
margin-block: 0 calc(2 * var(--default-grid-baseline));
}
&__custom-input {
@ -357,13 +363,14 @@ export default {
align-items: center;
gap: var(--default-grid-baseline);
width: 100%;
margin-bottom: 10px;
padding-inline-start: var(--default-grid-baseline);
margin-block: 0 calc(2 * var(--default-grid-baseline));
}
&__automation-hint {
display: flex;
width: 100%;
margin-bottom: 10px;
margin-block: 0 calc(2 * var(--default-grid-baseline));
color: var(--color-text-maxcontrast);
}

View file

@ -17,6 +17,9 @@ const getAllStatusOptions = () => {
}, {
type: 'away',
label: t('user_status', 'Away'),
}, {
type: 'busy',
label: t('user_status', 'Busy'),
}, {
type: 'dnd',
label: t('user_status', 'Do not disturb'),

View file

@ -136,7 +136,7 @@ class StatusServiceIntegrationTest extends TestCase {
);
$this->service->setUserStatus(
'test123',
IUserStatus::AWAY,
IUserStatus::BUSY,
IUserStatus::MESSAGE_CALENDAR_BUSY,
true,
);
@ -147,12 +147,12 @@ class StatusServiceIntegrationTest extends TestCase {
$this->service->setUserStatus(
'test123',
IUserStatus::AWAY,
IUserStatus::BUSY,
IUserStatus::MESSAGE_CALL,
true,
);
self::assertSame(
IUserStatus::AWAY,
IUserStatus::BUSY,
$this->service->findByUserId('test123')->getStatus(),
);
@ -182,7 +182,7 @@ class StatusServiceIntegrationTest extends TestCase {
$nostatus = $this->service->setUserStatus(
'test123',
IUserStatus::AWAY,
IUserStatus::BUSY,
IUserStatus::MESSAGE_CALENDAR_BUSY,
true,
);

View file

@ -26,7 +26,7 @@ class PredefinedStatusServiceTest extends TestCase {
}
public function testGetDefaultStatuses(): void {
$this->l10n->expects($this->exactly(7))
$this->l10n->expects($this->exactly(8))
->method('t')
->willReturnCallback(function ($text, $parameters = []) {
return vsprintf($text, $parameters);
@ -52,6 +52,15 @@ class PredefinedStatusServiceTest extends TestCase {
'time' => 1800,
],
],
[
'id' => 'be-right-back',
'icon' => '⏳',
'message' => 'Be right back',
'clearAt' => [
'type' => 'period',
'time' => 900,
],
],
[
'id' => 'remote-work',
'icon' => '🏡',
@ -106,6 +115,7 @@ class PredefinedStatusServiceTest extends TestCase {
['sick-leave', '🤒'],
['vacationing', '🌴'],
['remote-work', '🏡'],
['be-right-back', '⏳'],
['call', '💬'],
['unknown-id', null],
];
@ -127,6 +137,7 @@ class PredefinedStatusServiceTest extends TestCase {
['sick-leave', 'Out sick'],
['vacationing', 'Vacationing'],
['remote-work', 'Working remotely'],
['be-right-back', 'Be right back'],
['call', 'In a call'],
['unknown-id', null],
];
@ -145,13 +156,14 @@ class PredefinedStatusServiceTest extends TestCase {
['sick-leave', true],
['vacationing', true],
['remote-work', true],
['be-right-back', true],
['call', true],
['unknown-id', false],
];
}
public function testGetDefaultStatusById(): void {
$this->l10n->expects($this->exactly(7))
$this->l10n->expects($this->exactly(8))
->method('t')
->willReturnCallback(function ($text, $parameters = []) {
return vsprintf($text, $parameters);

4
dist/core-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long