Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move new search experience to a Beta #7718

Merged
merged 24 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions res/css/views/beta/_BetaCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ limitations under the License.
line-height: $font-15px;
color: $secondary-content;
margin-top: 20px;

> h4 {
margin: 0;
}

> p {
margin-top: 0;
}
}
}

Expand Down
23 changes: 7 additions & 16 deletions res/css/views/dialogs/_SpotlightDialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -251,28 +251,19 @@ limitations under the License.
font-size: $font-12px;
line-height: $font-15px;
color: $secondary-content;
padding: 16px 16px 20px;
padding: 12px 16px 16px;
display: flex;
border-top: 1px solid $quinary-content;

.mx_BetaCard_betaPill {
margin-right: 12px;
}

> span {
position: relative;
padding-left: 20px;
align-self: center;

&::before {
background-color: $secondary-content;
content: "";
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
width: 16px;
height: 16px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
.mx_AccessibleButton_kind_link_inline {
padding: 0;
}
}

Expand Down
Binary file added res/img/betas/new_search_experience.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 33 additions & 1 deletion src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ import { RoomUpdateCause } from "../../stores/room-list/models";
import SecurityCustomisations from "../../customisations/Security";
import Spinner from "../views/elements/Spinner";
import QuestionDialog from "../views/dialogs/QuestionDialog";
import UserSettingsDialog from '../views/dialogs/UserSettingsDialog';
import UserSettingsDialog, { UserTab } from '../views/dialogs/UserSettingsDialog';
import CreateGroupDialog from '../views/dialogs/CreateGroupDialog';
import CreateRoomDialog from '../views/dialogs/CreateRoomDialog';
import RoomDirectory from './RoomDirectory';
Expand Down Expand Up @@ -1553,6 +1553,38 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
showNotificationsToast(false);
}

if (!localStorage.getItem("mx_seen_feature_spotlight_toast")) {
setTimeout(() => {
if (SettingsStore.getValue("feature_spotlight")) return;

const key = "BETA_SPOTLIGHT_TOAST";
ToastStore.sharedInstance().addOrReplaceToast({
key,
title: _t("New search beta available"),
props: {
description: _t("We're testing a new search to make finding what you want quicker.\n"),
acceptLabel: _t("Learn more"),
onAccept: () => {
dis.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Labs,
});
localStorage.setItem("mx_seen_feature_spotlight_toast", "true");
ToastStore.sharedInstance().dismissToast(key);
},
rejectLabel: _t("Dismiss"),
onReject: () => {
localStorage.setItem("mx_seen_feature_spotlight_toast", "true");
ToastStore.sharedInstance().dismissToast(key);
},
},
icon: "labs",
component: GenericToast,
priority: 9,
});
}, 5 * 60 * 1000); // show after 5 minutes to not overload user with toasts on launch
}

if (!localStorage.getItem("mx_seen_ia_1.1_changes_toast") && SettingsStore.getValue(UIFeature.Feedback)) {
const key = "IA_1.1_TOAST";
ToastStore.sharedInstance().addOrReplaceToast({
Expand Down
5 changes: 3 additions & 2 deletions src/components/views/beta/BetaCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Modal from "../../../Modal";
import BetaFeedbackDialog from "../dialogs/BetaFeedbackDialog";
import SdkConfig from "../../../SdkConfig";
import SettingsFlag from "../elements/SettingsFlag";
import { useFeatureEnabled } from "../../../hooks/useSettings";

// XXX: Keep this around for re-use in future Betas

Expand Down Expand Up @@ -67,10 +68,10 @@ export const BetaPill = ({ onClick }: { onClick?: () => void }) => {

const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
const info = SettingsStore.getBetaInfo(featureId);
const value = useFeatureEnabled(featureId);
if (!info) return null; // Beta is invalid/disabled

const { title, caption, disclaimer, image, feedbackLabel, feedbackSubheading, extraSettings } = info;
const value = SettingsStore.getValue(featureId);

let feedbackButton;
if (value && feedbackLabel && feedbackSubheading && SdkConfig.get().bug_report_endpoint_url) {
Expand All @@ -91,7 +92,7 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
{ titleOverride || _t(title) }
<BetaPill />
</h3>
<span className="mx_BetaCard_caption">{ _t(caption) }</span>
<span className="mx_BetaCard_caption">{ caption() }</span>
<div className="mx_BetaCard_buttons">
{ feedbackButton }
<AccessibleButton
Expand Down
96 changes: 72 additions & 24 deletions src/components/views/dialogs/SpotlightDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React, {
ChangeEvent,
ComponentProps,
KeyboardEvent,
RefObject,
useCallback,
useContext,
useEffect,
Expand Down Expand Up @@ -63,6 +64,8 @@ import RoomViewStore from "../../../stores/RoomViewStore";
import { showStartChatInviteDialog } from "../../../RoomInvite";
import SettingsStore from "../../../settings/SettingsStore";
import { SettingLevel } from "../../../settings/SettingLevel";
import { BetaPill } from "../beta/BetaCard";
import { UserTab } from "./UserSettingsDialog";

const MAX_RECENT_SEARCHES = 10;
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
Expand Down Expand Up @@ -165,6 +168,10 @@ const useSpaceResults = (space?: Room, query?: string): [IHierarchyRoom[], boole
return [results, hierarchy?.loading ?? false];
};

function refIsForRecentlyViewed(ref: RefObject<HTMLElement>): boolean {
return ref.current?.id.startsWith("mx_SpotlightDialog_button_recentlyViewed_");
}

const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) => {
const cli = MatrixClientPeg.get();
const rovingContext = useContext(RovingTabIndexContext);
Expand Down Expand Up @@ -447,25 +454,45 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
};

const onKeyDown = (ev: KeyboardEvent) => {
let ref: RefObject<HTMLElement>;

switch (ev.key) {
case Key.ARROW_UP:
case Key.ARROW_DOWN:
ev.stopPropagation();
ev.preventDefault();

if (rovingContext.state.refs.length > 0) {
const idx = rovingContext.state.refs.indexOf(rovingContext.state.activeRef);
const ref = findSiblingElement(rovingContext.state.refs, idx + (ev.key === Key.ARROW_UP ? -1 : 1));

if (ref) {
rovingContext.dispatch({
type: Type.SetFocus,
payload: { ref },
});
ref.current?.scrollIntoView({
block: "nearest",
});
let refs = rovingContext.state.refs;
if (!query) {
// If the current selection is not in the recently viewed row then only include the
// first recently viewed so that is the target when the user is switching into recently viewed.
const keptRecentlyViewedRef = refIsForRecentlyViewed(rovingContext.state.activeRef)
? rovingContext.state.activeRef
: refs.find(refIsForRecentlyViewed);
// exclude all other recently viewed items from the list so up/down arrows skip them
refs = refs.filter(ref => ref === keptRecentlyViewedRef || !refIsForRecentlyViewed(ref));
}

const idx = refs.indexOf(rovingContext.state.activeRef);
ref = findSiblingElement(refs, idx + (ev.key === Key.ARROW_UP ? -1 : 1));
}
break;

case Key.ARROW_LEFT:
case Key.ARROW_RIGHT:
// only handle these keys when we are in the recently viewed row of options
if (!query &&
rovingContext.state.refs.length > 0 &&
refIsForRecentlyViewed(rovingContext.state.activeRef)
) {
// we only intercept left/right arrows when the field is empty, and they'd do nothing anyway
ev.stopPropagation();
ev.preventDefault();

const refs = rovingContext.state.refs.filter(refIsForRecentlyViewed);
const idx = refs.indexOf(rovingContext.state.activeRef);
ref = findSiblingElement(refs, idx + (ev.key === Key.ARROW_LEFT ? -1 : 1));
}
break;

Expand All @@ -475,6 +502,25 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
rovingContext.state.activeRef?.current?.click();
break;
}

if (ref) {
rovingContext.dispatch({
type: Type.SetFocus,
payload: { ref },
});
ref.current?.scrollIntoView({
block: "nearest",
});
}
};

const openFeedback = () => {
Modal.createTrackedDialog("Spotlight Feedback", "", GenericFeatureFeedbackDialog, {
title: _t("Spotlight search feedback"),
subheading: _t("Thank you for trying Spotlight search. " +
"Your feedback will help inform the next versions."),
rageshakeLabel: "spotlight-feedback",
});
};

const activeDescendant = rovingContext.state.activeRef?.current?.id;
Expand All @@ -485,6 +531,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
arrows: () => <>
<div>↓</div>
<div>↑</div>
{ !query && <div>←</div> }
{ !query && <div>→</div> }
</>,
}) }
</div>
Expand Down Expand Up @@ -514,21 +562,21 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
</div>

<div className="mx_SpotlightDialog_footer">
<span>
{ activeSpace
? _t("Searching rooms and chats you're in and %(spaceName)s", { spaceName: activeSpace.name })
: _t("Searching rooms and chats you're in") }
</span>
<BetaPill onClick={() => {
defaultDispatcher.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Labs,
});
onFinished();
}} />
{ _t("Results not as expected? Please <a>feedback</a>.", {}, {
a: sub => <AccessibleButton kind="link_inline" onClick={openFeedback}>
{ sub }
</AccessibleButton>,
}) }
<AccessibleButton
kind="primary_outline"
onClick={() => {
Modal.createTrackedDialog("Spotlight Feedback", "", GenericFeatureFeedbackDialog, {
title: _t("Spotlight search feedback"),
subheading: _t("Thank you for trying Spotlight search. " +
"Your feedback will help inform the next versions."),
rageshakeLabel: "spotlight-feedback",
});
}}
onClick={openFeedback}
>
{ _t("Feedback") }
</AccessibleButton>
Expand Down
16 changes: 11 additions & 5 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,13 @@
"Show extensible event representation of events": "Show extensible event representation of events",
"Show info about bridges in room settings": "Show info about bridges in room settings",
"Use new room breadcrumbs": "Use new room breadcrumbs",
"New spotlight search experience": "New spotlight search experience",
"New search experience": "New search experience",
"A new quick way to search spaces and rooms you're in.": "A new quick way to search spaces and rooms you're in.",
"This feature is a work in progress, so all feedback is very welcome.": "This feature is a work in progress, so all feedback is very welcome.",
"Leave beta": "Leave beta",
"Just return to this page or tap on the beta badge when you search.": "Just return to this page or tap on the beta badge when you search.",
"Feedback": "Feedback",
"Search and click on feedback": "Search and click on feedback",
"Right panel stays open (defaults to room member list)": "Right panel stays open (defaults to room member list)",
"Jump to date (adds /jumptodate and jump to date headers)": "Jump to date (adds /jumptodate and jump to date headers)",
"Don't send read receipts": "Don't send read receipts",
Expand Down Expand Up @@ -2552,7 +2558,6 @@
"Feedback sent": "Feedback sent",
"Comment": "Comment",
"Your platform and username will be noted to help us use your feedback as much as we can.": "Your platform and username will be noted to help us use your feedback as much as we can.",
"Feedback": "Feedback",
"You may contact me if you want to follow up or to let me test out upcoming ideas": "You may contact me if you want to follow up or to let me test out upcoming ideas",
"Rate %(brand)s": "Rate %(brand)s",
"Tell us below how you feel about %(brand)s so far.": "Tell us below how you feel about %(brand)s so far.",
Expand Down Expand Up @@ -2778,11 +2783,10 @@
"To search messages, look for this icon at the top of a room <icon/>": "To search messages, look for this icon at the top of a room <icon/>",
"Recent searches": "Recent searches",
"Clear": "Clear",
"Use <arrows/> to scroll results": "Use <arrows/> to scroll results",
"Searching rooms and chats you're in and %(spaceName)s": "Searching rooms and chats you're in and %(spaceName)s",
"Searching rooms and chats you're in": "Searching rooms and chats you're in",
"Spotlight search feedback": "Spotlight search feedback",
"Thank you for trying Spotlight search. Your feedback will help inform the next versions.": "Thank you for trying Spotlight search. Your feedback will help inform the next versions.",
"Use <arrows/> to scroll results": "Use <arrows/> to scroll results",
"Results not as expected? Please <a>feedback</a>.": "Results not as expected? Please <a>feedback</a>.",
"To help us prevent this in future, please <a>send us logs</a>.": "To help us prevent this in future, please <a>send us logs</a>.",
"Missing session data": "Missing session data",
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
Expand Down Expand Up @@ -3036,6 +3040,8 @@
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"Unable to copy room link": "Unable to copy room link",
"Unable to copy a link to the room to the clipboard.": "Unable to copy a link to the room to the clipboard.",
"New search beta available": "New search beta available",
"We're testing a new search to make finding what you want quicker.\n": "We're testing a new search to make finding what you want quicker.\n",
"Testing small changes": "Testing small changes",
"Your feedback is wanted as we try out some design changes.": "Your feedback is wanted as we try out some design changes.",
"More info": "More info",
Expand Down
30 changes: 25 additions & 5 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ limitations under the License.
*/

import { MatrixClient } from 'matrix-js-sdk/src/client';
import { ReactNode } from "react";
import React, { ReactNode } from "react";

import { _td } from '../languageHandler';
import { _t, _td } from '../languageHandler';
import {
NotificationBodyEnabledController,
NotificationsEnabledController,
Expand Down Expand Up @@ -155,7 +155,7 @@ interface IBaseSetting {
// XXX: Keep this around for re-use in future Betas
betaInfo?: {
title: string; // _td
caption: string; // _td
caption: () => ReactNode;
disclaimer?: (enabled: boolean) => ReactNode;
image: string; // require(...)
feedbackSubheading?: string;
Expand Down Expand Up @@ -336,8 +336,28 @@ export const SETTINGS: {[setting: string]: ISetting} = {
isFeature: true,
labsGroup: LabGroup.Rooms,
supportedLevels: LEVELS_FEATURE,
displayName: _td("New spotlight search experience"),
default: false,
displayName: _td("New search experience"),
default: false,
betaInfo: {
title: _td("New search experience"),
caption: () => <>
<p>{ _t("A new quick way to search spaces and rooms you're in.") }</p>
<p>{ _t("This feature is a work in progress, so all feedback is very welcome.") }</p>
</>,
disclaimer: enabled => enabled
? <>
<h4>{ _t("Leave beta") }</h4>
<p>{ _t("Just return to this page or tap on the beta badge when you search.") }</p>
<h4>{ _t("Feedback") }</h4>
<p>{ _t("Search and click on feedback") }</p>
</>
: <>
<h4>{ _t("Feedback") }</h4>
<p>{ _t("Search and click on feedback") }</p>
</>,
feedbackLabel: "spotlight-feedback",
image: require("../../res/img/betas/new_search_experience.gif"),
},
},
"feature_right_panel_default_open": {
isFeature: true,
Expand Down