'use strict'; const { TemplateView, ListView, text } = require('hydrogen-view-sdk'); const ModalView = require('matrix-public-archive-shared/views/ModalView'); const HomeserverSelectionModalContentView = require('./HomeserverSelectionModalContentView'); const MatrixLogoView = require('./MatrixLogoView'); 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', list: vm.rooms, parentProvidesUpdates: false, }, (room) => { return new RoomCardView(room); } ); const homeserverSelectElement = t.select( { className: 'RoomDirectoryView_homeserverSelector', name: 'homeserver', 'data-testid': 'homeserver-select', onInput: (event) => { const optionValue = event.target.value; if (optionValue.startsWith('action:')) { const action = optionValue; vm.onHomeserverSelectionAction(action); // You can't select one of the actions. set the ` is updated when the ViewModel is updated t.mapSideEffect( (vm) => vm.homeserverSelection, (homeserverSelection, oldHomeserverSelection) => { homeserverSelectElement.value = homeserverSelection; const pickedActionOption = homeserverSelection.startsWith('action:'); const isInitialization = oldHomeserverSelection === undefined; if (!pickedActionOption && !isInitialization) { // Clear the hash out before we submit the form so it doesn't come back from // the dead after the page loads. Normally, the hash would go away in the // modal close callback but this races with it and sometimes we beat it. const path = vm.navigation.pathFrom([]); vm.navigation.applyPath(path); // Submit the page with the new homeserver selection to get results. headerForm.submit(); } } ); // Also update the selection whenever the lists change around t.mapSideEffect( (vm) => vm.availableHomeserverList, () => { homeserverSelectElement.value = vm.homeserverSelection; } ); t.mapSideEffect( (vm) => vm.addedHomeserversList, () => { homeserverSelectElement.value = vm.homeserverSelection; } ); return t.div( { className: { RoomDirectoryView: true, }, }, [ t.header({ className: 'RoomDirectoryView_header' }, [headerForm]), t.main({ className: 'RoomDirectoryView_mainContent' }, [ // Display a nice error section when we failed to fetch rooms from the room directory t.if( (vm) => vm.roomFetchError, (t, vm) => { return t.section({ className: 'RoomDirectoryView_roomListError' }, [ t.h3('❗ Unable to fetch rooms from room directory'), t.p({}, [ `This may be a temporary problem with the homeserver where the room directory lives (${vm.pageSearchParameters.homeserver}) or the homeserver that the archive is pulling from (${vm.homeserverName}). You can try adjusting your search term or select a different homeserver to look at. If this problem persists, please open a `, t.a( { href: 'https://github.com/matrix-org/matrix-public-archive/issues/new' }, 'bug report' ), ` with all of this whole section copy-pasted into the issue.`, ]), t.button( { className: 'PrimaryActionButton', onClick: () => { window.location.reload(); }, }, 'Refresh page' ), t.p({}, `The exact error we ran into was:`), t.pre( { className: 'RoomDirectoryView_codeBlock' }, t.code({}, vm.roomFetchError.stack) ), t.p({}, `The error occured with these search paramers:`), t.pre( { className: 'RoomDirectoryView_codeBlock' }, t.code({}, JSON.stringify(vm.pageSearchParameters, null, 2)) ), t.details({}, [ t.summary({}, 'Why are we showing so many details?'), t.p({}, [ `We're showing as much detail as we know so you're not frustrated by a generic message with no feedback on how to move forward. This also makes it easier for you to write a `, t.a( { href: 'https://github.com/matrix-org/matrix-public-archive/issues/new' }, 'bug report' ), ` with all the details necessary for us to triage it.`, ]), t.p({}, t.strong(`Isn't this a security risk?`)), t.p({}, [ `Not really. Usually, people are worried about returning details because it makes it easier for people to know how to prod and poke and get better feedback about what's going wrong to craft exploits. But the `, t.a( { href: 'https://github.com/matrix-org/matrix-public-archive' }, 'Matrix Public Archive' ), ` is already open source so the details of the app are already public and you can run your own instance against the same homeservers that we are to find problems.`, ]), t.p({}, [ `If you find any security vulnerabilities, please `, t.a( { href: 'https://matrix.org/security-disclosure-policy/' }, 'responsibly disclose' ), ` them to us.`, ]), t.p({}, [ `If you have ideas on how we can better present these errors, please `, t.a( { href: 'https://github.com/matrix-org/matrix-public-archive/issues' }, 'create an issue' ), `.`, ]), ]), ]); } ), // Otherwise, display the rooms that we fetched t.view(roomList), t.div({ className: 'RoomDirectoryView_paginationButtonCombo' }, [ t.a( { className: 'RoomDirectoryView_paginationButton', href: vm.prevPageUrl }, 'Previous' ), t.a({ className: 'RoomDirectoryView_paginationButton', href: vm.nextPageUrl }, 'Next'), ]), ]), ] ); } } module.exports = RoomDirectoryView;