Skip to content

Commit

Permalink
Add search to room directory landing page (#70)
Browse files Browse the repository at this point in the history
Part of #6
  • Loading branch information
MadLittleMods authored Sep 16, 2022
1 parent f732467 commit 9266899
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 61 deletions.
14 changes: 9 additions & 5 deletions public/css/room-directory.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
}

.RoomDirectoryView_header {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 80px;
padding-left: 10px;
padding-bottom: 80px;
padding-right: 10px;

background-color: #fafafa;
}

.RoomDirectoryView_headerForm {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 80px;
}

.RoomDirectoryView_matrixLogo {
width: 100%;
max-width: 148px;
Expand Down Expand Up @@ -50,6 +53,7 @@
width: 100%;
height: 32px;
padding-left: 32px;
padding-right: 8px;

background: rgba(141, 151, 165, 0.15);
border-radius: 8px;
Expand All @@ -71,7 +75,7 @@
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 80px;
margin-bottom: 160px;
}

.RoomDirectoryView_paginationButtonCombo {
Expand Down
3 changes: 1 addition & 2 deletions public/js/entry-client-hydrogen.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import mounted from 'matrix-public-archive-shared/hydrogen-vm-render-script';
console.log('mounted', mounted);
import 'matrix-public-archive-shared/hydrogen-vm-render-script';
3 changes: 1 addition & 2 deletions public/js/entry-client-room-directory.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import mounted from 'matrix-public-archive-shared/room-directory-vm-render-script';
console.log('mounted', mounted);
import 'matrix-public-archive-shared/room-directory-vm-render-script';
16 changes: 9 additions & 7 deletions server/lib/matrix-utils/fetch-public-rooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@ const config = require('../config');
const matrixServerUrl = config.get('matrixServerUrl');
assert(matrixServerUrl);

async function fetchPublicRooms(accessToken, { server, paginationToken, limit } = {}) {
async function fetchPublicRooms(accessToken, { server, searchTerm, paginationToken, limit } = {}) {
assert(accessToken);

let qs = new URLSearchParams();
if (server) {
qs.append('server', server);
}
if (paginationToken) {
qs.append('since', paginationToken);
}
if (limit) {
qs.append('limit', limit);
}

const publicRoomsEndpoint = urlJoin(
matrixServerUrl,
`_matrix/client/v3/publicRooms?${qs.toString()}`
);

const publicRoomsRes = await fetchEndpointAsJson(publicRoomsEndpoint, {
method: 'POST',
body: {
filter: {
generic_search_term: searchTerm,
},
since: paginationToken,
limit,
},
accessToken,
});

Expand Down
2 changes: 2 additions & 0 deletions server/lib/status-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ function StatusError(status, inputMessage) {
}

this.message = `${status} - ${message}`;
// This will be picked by the default Express error handler and assign the status code,
// https://expressjs.com/en/guide/error-handling.html#the-default-error-handler
this.status = status;
this.name = 'StatusError';
Error.captureStackTrace(this, StatusError);
Expand Down
4 changes: 3 additions & 1 deletion server/routes/room-directory-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ router.get(
'/',
asyncHandler(async function (req, res) {
const paginationToken = req.query.page;
const searchTerm = req.query.search;

const { rooms, nextPaginationToken, prevPaginationToken } = await fetchPublicRooms(
matrixAccessToken,
{
//server: TODO,
searchTerm,
paginationToken,
// It would be good to grab more rooms than we display in case we need
// to filter any out but then the pagination tokens with the homeserver
Expand All @@ -54,7 +56,7 @@ router.get(
rooms,
nextPaginationToken,
prevPaginationToken,
searchTerm: 'foobar (TODO)',
searchTerm,
config: {
basePath,
matrixServerUrl,
Expand Down
15 changes: 11 additions & 4 deletions server/routes/room-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ router.get(
'/',
asyncHandler(async function (req, res) {
const roomIdOrAlias = req.params.roomIdOrAlias;
assert(roomIdOrAlias.startsWith('!') || roomIdOrAlias.startsWith('#'));
const isValidAlias = roomIdOrAlias.startsWith('!') || roomIdOrAlias.startsWith('#');
if (!isValidAlias) {
throw new StatusError(404, `Invalid alias given: ${roomIdOrAlias}`);
}

// In case we're joining a new room for the first time,
// let's avoid redirecting to our join event
// let's avoid redirecting to our join event by getting
// the time before we join and looking backwards.
const dateBeforeJoin = Date.now();

// We have to wait for the room join to happen first before we can fetch
Expand All @@ -99,7 +103,7 @@ router.get(
direction: 'b',
});
if (!originServerTs) {
throw new StatusError(404, 'Unable to find day with an history');
throw new StatusError(404, 'Unable to find day with history');
}

// Redirect to a day with messages
Expand Down Expand Up @@ -127,7 +131,10 @@ router.get(
timeoutMiddleware,
asyncHandler(async function (req, res) {
const roomIdOrAlias = req.params.roomIdOrAlias;
assert(roomIdOrAlias.startsWith('!') || roomIdOrAlias.startsWith('#'));
const isValidAlias = roomIdOrAlias.startsWith('!') || roomIdOrAlias.startsWith('#');
if (!isValidAlias) {
throw new StatusError(404, `Invalid alias given: ${roomIdOrAlias}`);
}

const { fromTimestamp, toTimestamp, hourRange, fromHour, toHour } =
parseArchiveRangeFromReq(req);
Expand Down
4 changes: 4 additions & 0 deletions shared/hydrogen-vm-render-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ function supressBlankAnchorsReloadingThePage() {

// eslint-disable-next-line max-statements
async function mountHydrogen() {
console.log('Mounting Hydrogen...');
console.time('Completed mounting Hydrogen');
const appElement = document.querySelector('#app');

const platformConfig = {};
Expand Down Expand Up @@ -309,6 +311,8 @@ async function mountHydrogen() {
addSupportClasses();

supressBlankAnchorsReloadingThePage();

console.timeEnd('Completed mounting Hydrogen');
}

// N.B.: When we run this in a virtual machine (`vm`), it will return the last
Expand Down
5 changes: 4 additions & 1 deletion shared/lib/url-creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ class URLCreator {
this._basePath = basePath;
}

roomDirectoryUrl({ paginationToken } = {}) {
roomDirectoryUrl({ searchTerm, paginationToken } = {}) {
let qs = new URLSearchParams();
if (searchTerm) {
qs.append('search', searchTerm);
}
if (paginationToken) {
qs.append('page', paginationToken);
}
Expand Down
5 changes: 4 additions & 1 deletion shared/room-directory-vm-render-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ assert(rooms);
const nextPaginationToken = window.matrixPublicArchiveContext.nextPaginationToken;
const prevPaginationToken = window.matrixPublicArchiveContext.prevPaginationToken;
const searchTerm = window.matrixPublicArchiveContext.searchTerm;
assert(searchTerm);
const config = window.matrixPublicArchiveContext.config;
assert(config);
assert(config.matrixServerUrl);
Expand All @@ -27,20 +26,24 @@ assert(config.basePath);
const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(config.basePath);

async function mountHydrogen() {
console.log('Mounting Hydrogen...');
console.time('Completed mounting Hydrogen');
const appElement = document.querySelector('#app');

const roomDirectoryViewModel = new RoomDirectoryViewModel({
homeserverUrl: config.matrixServerUrl,
homeserverName: config.matrixServerName,
matrixPublicArchiveURLCreator,
rooms,
searchTerm,
nextPaginationToken,
prevPaginationToken,
});

const view = new RoomDirectoryView(roomDirectoryViewModel);

appElement.replaceChildren(view.mount());
console.timeEnd('Completed mounting Hydrogen');
}

// N.B.: When we run this in a virtual machine (`vm`), it will return the last
Expand Down
13 changes: 13 additions & 0 deletions shared/viewmodels/RoomDirectoryViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class RoomDirectoryViewModel extends ViewModel {
homeserverName,
matrixPublicArchiveURLCreator,
rooms,
searchTerm,
nextPaginationToken,
prevPaginationToken,
} = options;
Expand All @@ -39,6 +40,7 @@ class RoomDirectoryViewModel extends ViewModel {
};
})
);
this._searchTerm = searchTerm;
this._nextPaginationToken = nextPaginationToken;
this._prevPaginationToken = prevPaginationToken;
}
Expand All @@ -51,9 +53,19 @@ class RoomDirectoryViewModel extends ViewModel {
return this._matrixPublicArchiveURLCreator.roomDirectoryUrl();
}

get searchTerm() {
return this._searchTerm || '';
}

setSearchTerm(newSearchTerm) {
this._searchTerm = newSearchTerm;
this.emitChange('searchTerm');
}

get nextPageUrl() {
if (this._nextPaginationToken) {
return this._matrixPublicArchiveURLCreator.roomDirectoryUrl({
searchTerm: this.searchTerm,
paginationToken: this._nextPaginationToken,
});
}
Expand All @@ -64,6 +76,7 @@ class RoomDirectoryViewModel extends ViewModel {
get prevPageUrl() {
if (this._prevPaginationToken) {
return this._matrixPublicArchiveURLCreator.roomDirectoryUrl({
searchTerm: this.searchTerm,
paginationToken: this._prevPaginationToken,
});
}
Expand Down
2 changes: 2 additions & 0 deletions shared/views/RoomCardView.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class RoomCardView extends TemplateView {
className: {
RoomCardView: true,
},
'data-room-id': vm.roomId,
'data-testid': 'room-card',
},
[
t.a(
Expand Down
96 changes: 60 additions & 36 deletions shared/views/RoomDirectoryView.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ const RoomCardView = require('./RoomCardView');

class RoomDirectoryView extends TemplateView {
render(t, vm) {
// Make sure we don't overwrite the search input value if someone has typed
// before the JavaScript has loaded
const searchInputBeforeRendering = document.querySelector('.RoomDirectoryView_searchInput');
if (searchInputBeforeRendering) {
const searchInputValueBeforeRendering = searchInputBeforeRendering.value;
vm.setSearchTerm(searchInputValueBeforeRendering);
}

const roomList = new ListView(
{
className: 'RoomDirectoryView_roomList',
Expand All @@ -30,46 +38,62 @@ class RoomDirectoryView extends TemplateView {
},
[
t.header({ className: 'RoomDirectoryView_header' }, [
t.a(
{
className: 'RoomDirectoryView_matrixLogo',
title: 'Matrix Public Archive',
href: vm.roomDirectoryUrl,
},
[t.view(new MatrixLogoView(vm))]
),
t.h3(
{ className: 'RoomDirectoryView_subHeader' },
'Browse thousands of rooms using Matrix...'
),
t.div({ className: 'RoomDirectoryView_search' }, [
t.svg(
t.form({ className: 'RoomDirectoryView_headerForm', method: 'GET' }, [
t.a(
{
className: 'RoomDirectoryView_searchIcon',
viewBox: '0 0 18 18',
fill: 'currentColor',
xmlns: 'http://www.w3.org/2000/svg',
className: 'RoomDirectoryView_matrixLogo',
title: 'Matrix Public Archive',
href: vm.roomDirectoryUrl,
},
[
t.path({
'fill-rule': 'evenodd',
'clip-rule': 'evenodd',
d: 'M12.1333 8.06667C12.1333 10.3126 10.3126 12.1333 8.06667 12.1333C5.82071 12.1333 4 10.3126 4 8.06667C4 5.82071 5.82071 4 8.06667 4C10.3126 4 12.1333 5.82071 12.1333 8.06667ZM12.9992 11.5994C13.7131 10.6044 14.1333 9.38463 14.1333 8.06667C14.1333 4.71614 11.4172 2 8.06667 2C4.71614 2 2 4.71614 2 8.06667C2 11.4172 4.71614 14.1333 8.06667 14.1333C9.38457 14.1333 10.6043 13.7131 11.5992 12.9993C11.6274 13.0369 11.6586 13.0729 11.6928 13.1071L14.2928 15.7071C14.6833 16.0977 15.3165 16.0977 15.707 15.7071C16.0975 15.3166 16.0975 14.6834 15.707 14.2929L13.107 11.6929C13.0728 11.6587 13.0368 11.6276 12.9992 11.5994Z',
}),
]
[t.view(new MatrixLogoView(vm))]
),
t.input({
className: 'RoomDirectoryView_searchInput',
placeholder: 'Search rooms (disabled, not implemented yet)',
disabled: true,
}),
]),
t.div({ className: 'RoomDirectoryView_homeserverSelectSection' }, [
t.div({}, 'Show: Matrix rooms on'),
t.select(
{ className: 'RoomDirectoryView_homeserverSelector' },
availableHomeserverOptionElements
t.h3(
{ className: 'RoomDirectoryView_subHeader' },
'Browse thousands of rooms using Matrix...'
),
t.div({ className: 'RoomDirectoryView_search' }, [
t.svg(
{
className: 'RoomDirectoryView_searchIcon',
viewBox: '0 0 18 18',
fill: 'currentColor',
xmlns: 'http://www.w3.org/2000/svg',
},
[
t.path({
'fill-rule': 'evenodd',
'clip-rule': 'evenodd',
d: 'M12.1333 8.06667C12.1333 10.3126 10.3126 12.1333 8.06667 12.1333C5.82071 12.1333 4 10.3126 4 8.06667C4 5.82071 5.82071 4 8.06667 4C10.3126 4 12.1333 5.82071 12.1333 8.06667ZM12.9992 11.5994C13.7131 10.6044 14.1333 9.38463 14.1333 8.06667C14.1333 4.71614 11.4172 2 8.06667 2C4.71614 2 2 4.71614 2 8.06667C2 11.4172 4.71614 14.1333 8.06667 14.1333C9.38457 14.1333 10.6043 13.7131 11.5992 12.9993C11.6274 13.0369 11.6586 13.0729 11.6928 13.1071L14.2928 15.7071C14.6833 16.0977 15.3165 16.0977 15.707 15.7071C16.0975 15.3166 16.0975 14.6834 15.707 14.2929L13.107 11.6929C13.0728 11.6587 13.0368 11.6276 12.9992 11.5994Z',
}),
]
),
t.input({
type: 'search',
className: 'RoomDirectoryView_searchInput',
placeholder: 'Search rooms',
name: 'search',
value: vm.searchTerm,
// Autocomplete is disabled because browsers share autocomplete
// suggestions across domains and this uses a very common
// `name="search"`. The name is important because it's what
// shows up in the query parameters when the `<form
// method="GET">` is submitted. I wish we could scope the
// autocomplete suggestions to the apps domain
// (https://github.com/whatwg/html/issues/8284). Trying some
// custom non-spec value here also doesn't seem to work (Chrome
// decides to autofill based on `name="search"`).
autocomplete: 'off',
autocapitalize: 'off',
'data-testid': 'room-directory-search-input',
}),
]),
t.div({ className: 'RoomDirectoryView_homeserverSelectSection' }, [
t.div({}, 'Show: Matrix rooms on'),
t.select(
{ className: 'RoomDirectoryView_homeserverSelector', name: 'homeserver' },
availableHomeserverOptionElements
),
]),
]),
]),
t.main({ className: 'RoomDirectoryView_mainContent' }, [
Expand Down
Loading

0 comments on commit 9266899

Please sign in to comment.