You've already forked element-web
mirror of
https://github.com/element-hq/element-web.git
synced 2026-10-23 11:09:01 +03:00
* Say why the homeserver refused an invite instead of blaming permissions Every M_FORBIDDEN from an invite was reported as "You do not have permission to invite people to this room", and the rest of the batch was abandoned on the spot. That is only one of the reasons a server has for refusing: the invitee may have invites switched off, or their homeserver may not accept ours. Someone who did have the power to invite was told they did not, and given nothing to act on. The claim is now checked before it is made. If the room says we cannot invite, the message and the abandoned batch are exactly as they were, because that will hold for everyone in the batch. If we can invite, the server's own reason is shown instead and the remaining invites are still attempted, since a refusal aimed at one person says nothing about the next. The unfederated case comes out of the same branch unchanged. It was reached through a nested conditional that had to spell itself out twice, once for rooms and once for spaces, and reads better checked first. Tests: a refusal we are allowed to send through now surfaces the server's text and lets the batch continue, while a genuine lack of power still gives the permission message and stops. * Drop the homeserver's own wording from the invite refusal message The reason a server gives for an M_FORBIDDEN comes back in English whatever language the client is running in, so showing it leaves the user reading a sentence they may not understand inside an otherwise translated dialog. Nothing else in the app passes server text through to the UI. The message now says only that the invite was refused, which is fully translatable. The reason is not lost: the catch block already logs the whole error, so it stays in the console and in a rageshake, where an untranslated string does no harm and is where anyone diagnosing the refusal would look anyway. The rest of the change stands. Permissions are blamed only when the room says we genuinely cannot invite, and a refusal aimed at one invitee no longer abandons the rest of the batch. * Reword the dialog that lists the invites a batch could not send The dialog headed "Some invites couldn't be sent" goes on to say "We sent the others, but the below people couldn't be invited to <room>". "Some" reads as more than one, though a batch of two can fail on exactly one; "below" names the list by where it sits on the screen rather than by what it is; and the room name is repeated back from the very room the user opened the invite dialog in. The heading now reports what happened rather than what was possible, the list is introduced as the following people, and the contractions are spelled out. The room name goes with them: nothing reaches this dialog except invites the user has just sent into a room they are already looking at. Dropping the name drops the RoomName substitution too, which is why the key is renamed rather than reworded in place. The forty translations still carry the tag, and under the unchanged key they would render it as literal text until each language is retranslated. * Report a refused invite in place of the invite dialog, not on top of it Design review asked for the failure report to take the invite dialog's place: once the batch has run there is nothing left to go back to, because everyone who could be invited already has been. The dialog now finishes before the report opens, which also lets showAnyInviteErrors stop doubling as the decision about whether to close it. The reason line now reads as the reason rather than as a report of machinery. The client cannot tell a person's own invite filter apart from a server that refuses invites wholesale — both come back as a bare M_FORBIDDEN with nothing to key off — so the wording states the effect, which is the same either way, rather than guessing at a cause the way the permission message used to. The report is capped at 600px, and each reason starts at the avatar's left edge with a space above it, so it reads as a note about the person rather than as a third line of their name. * Keep the refusal report's own button inside its 600px box BaseDialog puts the fixed-width class on the focus lock inside .mx_Dialog rather than on .mx_Dialog itself, so capping the outer box alone left the body at its old 704px and hung the OK button 144px past the right edge — measured in the browser, not guessed. Pinning the outer box and letting the body size to it puts them back together, and the viewport cap keeps a narrow window from overflowing. * Stop the refusal line from pushing a name away from its avatar Spanning the reason across both columns made it a grid item of the avatar track, and that track was sized max-content, so the longest reason set the avatar column's width and left a 158px hole between each avatar and its name. Sizing the track from the avatar itself takes the reason out of that calculation; the gap is back to the grid's own 12px and the reason still starts at the avatar's left edge. The avatar size now has one definition instead of being repeated as the track width. * State each refusal once, under the people it applies to Repeating an identical sentence under every name read as three failures with three causes rather than one cause with three people behind it, and the eye had to compare the lines to find out which. The failures are now grouped by the text they would have printed, in the order the batch hit them, and each group says its reason once beneath its own list. Grouping also takes the reason out of the tile, which undoes the layout work the earlier rounds needed: the tile is back to upstream's avatar-and-name grid, so the spanning item that was inflating the max-content avatar column is gone along with the track override that compensated for it. Spacing now comes from the group — 8px between people, 16px above the reason — instead of a margin on every tile. * Play down the reason an invite could not be sent The reason sat under the people it applies to in alert red, at the size of their names, which reads as something gone wrong that the reader must act on. It is neither: nobody can do anything about a homeserver turning an invite down, and the invites that did go out are unaffected. It now takes the size and colour of the tertiary lines around it, so it explains without competing with the names above it. The reasons themselves repeated a subject the list had already given. Each one sits directly under the person it describes, so "User is already in the room" said "user" twice over; the already-invited and space wordings carried the same redundancy and lose it too. "They are not accepting invitations" becomes "Not accepting invites", in the terser register the app already uses for a state the reader cannot change. * Keep the refusal reason in alert red The reason was toned down to tertiary size and colour on the assumption that a homeserver turning an invite down is informational. Review settled the opposite: the layout americanrefugee approved states the reason once beneath the people it applies to, and at that position it is the only thing telling the reader those invites did not happen. Tertiary grey at 12px reads as a caption on the list above it rather than as the outcome, so it goes back to the alert red and the size of the names it explains. The wording simplifications stay. Dropping the redundant subject was a separate ask and does not depend on how the line is styled. * Put the refusal reason above the people it applies to The reason trailed the list it explains, so a reader met the names first and had to look back up once the explanation arrived. Leading with it makes the line a heading for its group, and the 8px that had held it clear of the names above now holds it clear of the names below. A heading takes a colon rather than a full stop, but the reason is a translated string that the single-invite failure dialog, the /invite command and the user-info invite button each show on its own, where a trailing colon would dangle. The colon is appended where the report renders it instead, which in turn means every reason has to arrive without a terminal stop: leave one on the wordier reasons this branch did not introduce and they read ".:" as soon as two differently-caused failures land in the same report. The four "already in the room" reasons line up with their existing translations again by losing it, since upstream's English never carried one. The longer sentences will show ".:" in the locales that have already translated them until Localazy picks the change up, which is the cheaper blemish; renaming those keys to dodge it would throw away thirty-six translations apiece. The alert red stays. TemoCrevlis read the line as informational and asked for tertiary grey; review settled it the other way, on the grounds that it is the only thing on screen saying why those invites did not happen, and red is the likelier to be read. * Style the invite error dialog with Compound tokens The refusal reason and the summary heading above it were still reaching for the legacy $font-15px, $alert and $secondary-content Sass variables. Each of those resolves to a Compound token one-for-one in every theme, so naming the token directly costs nothing at render time and stops the dialog depending on the compatibility layer. The heading collapses into the --cpd-font-body-md-regular shorthand, which already carries the regular weight and Compound's 1.5 line height. That trades the hand-written 24px leading for 22.5px, the value Compound intends for body-md text, rather than keeping a legacy variable alive just to preserve a leading nobody chose deliberately.
329 lines
7.3 KiB
Plaintext
329 lines
7.3 KiB
Plaintext
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
.mx_InviteDialog_flexWrapper .mx_Dialog {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.mx_InviteDialog_transferWrapper .mx_Dialog {
|
|
padding-bottom: var(--cpd-space-4x);
|
|
}
|
|
|
|
.mx_InviteDialog_addressBar {
|
|
display: flex;
|
|
flex-direction: row;
|
|
/* Right margin for the design. We could apply this to the whole dialog, but then the scrollbar */
|
|
/* for the user section gets weird. */
|
|
margin: var(--cpd-space-2x) 45px 0 0;
|
|
|
|
.mx_InviteDialog_editor {
|
|
flex: 1;
|
|
margin-left: var(--cpd-space-0-5x);
|
|
}
|
|
|
|
.mx_InviteDialog_goButton {
|
|
min-width: 86px;
|
|
margin-inline-start: 10px;
|
|
height: 41px;
|
|
line-height: $font-25px;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_section {
|
|
padding-bottom: var(--cpd-space-1x);
|
|
|
|
.mx_InviteDialog_section_showMore {
|
|
margin: 7px 18px;
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_section_hidden_suggestions_disclaimer {
|
|
padding: var(--cpd-space-2x) 0 var(--cpd-space-4x) 0;
|
|
font: var(--cpd-font-body-md-regular);
|
|
|
|
> span {
|
|
color: $primary-content;
|
|
font-weight: var(--cpd-font-weight-semibold);
|
|
}
|
|
|
|
> p {
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_footer {
|
|
border-top: 1px solid $input-border-color;
|
|
|
|
> h3 {
|
|
margin: var(--cpd-space-3x) 0;
|
|
font-size: $font-12px;
|
|
color: $muted-fg-color;
|
|
font-weight: bold;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.mx_CopyableText.mx_CopyableText_border {
|
|
width: unset; /* full width */
|
|
margin-bottom: 0;
|
|
|
|
> a {
|
|
text-decoration: none;
|
|
flex-shrink: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_other {
|
|
/* Prevent the dialog from jumping around randomly when elements change. */
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 600px;
|
|
overflow: hidden;
|
|
|
|
h2 {
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
white-space: pre-wrap;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.mx_InviteDialog_addressBar {
|
|
margin-inline-end: 0;
|
|
}
|
|
|
|
.mx_InviteDialog_userSections {
|
|
flex-grow: 1;
|
|
padding-inline-end: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-top: var(--cpd-space-3x);
|
|
gap: var(--cpd-space-3x);
|
|
|
|
.mx_InviteDialog_section {
|
|
padding-bottom: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
overflow: hidden;
|
|
|
|
.mx_InviteProgressBody {
|
|
margin-top: var(--cpd-space-12x);
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_transfer {
|
|
width: auto;
|
|
|
|
.mx_InviteDialog_content {
|
|
width: 496px;
|
|
height: 430px;
|
|
overflow: visible;
|
|
|
|
.mx_TabbedView {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-shrink: 1;
|
|
flex-grow: 1;
|
|
min-height: 0;
|
|
|
|
.mx_TabbedView_tabPanel {
|
|
flex-direction: column;
|
|
|
|
.mx_TabbedView_tabPanelContent {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_addressBar {
|
|
margin-top: var(--cpd-space-2x);
|
|
}
|
|
|
|
input[type="checkbox"] {
|
|
margin-inline-end: var(--cpd-space-2x);
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_userSections {
|
|
overflow-y: auto;
|
|
padding: 0 45px var(--cpd-space-1x) 0;
|
|
}
|
|
|
|
.mx_InviteDialog_helpText {
|
|
margin: 0;
|
|
}
|
|
|
|
.mx_InviteDialog_dialPad {
|
|
width: 224px;
|
|
margin-top: var(--cpd-space-4x);
|
|
margin-inline: auto;
|
|
|
|
.mx_InviteDialog_dialPadField {
|
|
border-top: 0;
|
|
border-inline: 0;
|
|
border-radius: 0;
|
|
margin-top: 0;
|
|
border-color: $quaternary-content;
|
|
|
|
&:focus-within {
|
|
border-color: $accent;
|
|
}
|
|
|
|
input {
|
|
font-size: 18px;
|
|
font-weight: var(--cpd-font-weight-semibold);
|
|
padding-top: 0;
|
|
}
|
|
|
|
.mx_Field_postfix {
|
|
/* Remove border separator between postfix and field content */
|
|
border-left: none;
|
|
}
|
|
}
|
|
|
|
.mx_DialPad {
|
|
row-gap: var(--cpd-space-4x);
|
|
column-gap: 48px;
|
|
margin-inline: auto;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_transferConsultConnect {
|
|
padding-top: var(--cpd-space-4x);
|
|
/* This wants a drop shadow the full width of the dialog, so use negative margin to make it full width,
|
|
* then compensate with padding
|
|
*/
|
|
padding-inline: var(--cpd-space-6x);
|
|
margin-inline: calc(-1 * var(--cpd-space-6x));
|
|
border-top: 1px solid $quinary-content;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
|
|
.mx_InviteDialog_transferConsultConnect_pushRight {
|
|
margin-inline-start: auto;
|
|
}
|
|
|
|
.mx_InviteDialog_tile {
|
|
cursor: pointer;
|
|
display: grid;
|
|
gap: var(--cpd-space-2x) var(--cpd-space-3x);
|
|
align-items: center;
|
|
|
|
&.mx_InviteDialog_tile--inviterError {
|
|
grid-template-columns: max-content auto; /* max-content = avatar width */
|
|
}
|
|
|
|
* {
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.mx_InviteDialog_tile_avatarStack {
|
|
width: 36px;
|
|
height: 36px;
|
|
display: inline-block;
|
|
position: relative;
|
|
grid-row-start: 1;
|
|
grid-column-start: 1;
|
|
|
|
& > * {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_tile_nameStack {
|
|
grid-row-start: 1;
|
|
grid-column-start: 2;
|
|
|
|
display: flex;
|
|
flex-flow: column;
|
|
align-self: center;
|
|
align-items: baseline;
|
|
gap: 2px 0;
|
|
overflow: hidden;
|
|
|
|
.mx_InviteDialog_tile_nameStack_name,
|
|
.mx_InviteDialog_tile_nameStack_userId {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.mx_InviteDialog_tile_nameStack_name {
|
|
font-size: $font-15px;
|
|
font-weight: var(--cpd-font-weight-semibold);
|
|
color: $primary-content;
|
|
}
|
|
|
|
.mx_InviteDialog_tile_nameStack_userId {
|
|
font-size: $font-12px;
|
|
color: $muted-fg-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_multiInviterErrorWrapper .mx_Dialog {
|
|
width: 600px;
|
|
max-width: 100%;
|
|
|
|
.mx_Dialog_fixedWidth {
|
|
width: auto;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_multiInviterError {
|
|
> h4 {
|
|
font: var(--cpd-font-body-md-regular);
|
|
color: var(--cpd-color-text-secondary);
|
|
}
|
|
|
|
.mx_InviteDialog_multiInviterError_group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--cpd-space-2x);
|
|
margin-bottom: var(--cpd-space-6x);
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_multiInviterError_reason {
|
|
margin-bottom: var(--cpd-space-2x);
|
|
|
|
font-size: var(--cpd-font-size-body-md);
|
|
color: var(--cpd-color-text-critical-primary);
|
|
}
|
|
}
|
|
|
|
.mx_InviteDialog_identityServer {
|
|
margin-top: 1em;
|
|
}
|
|
|
|
.mx_InviteDialog_oneThreepid {
|
|
font-size: $font-12px;
|
|
margin: var(--cpd-space-2x) 0;
|
|
}
|