UNPKG

matrix-react-sdk

Version:
711 lines (701 loc) 123 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useRoomHierarchy = exports.toLocalRoom = exports.showRoom = exports.joinRoom = exports.default = exports.HierarchyLevel = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _matrix = require("matrix-js-sdk/src/matrix"); var _roomHierarchy = require("matrix-js-sdk/src/room-hierarchy"); var _classnames = _interopRequireDefault(require("classnames")); var _lodash = require("lodash"); var _logger = require("matrix-js-sdk/src/logger"); var _types = require("matrix-js-sdk/src/types"); var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher")); var _languageHandler = require("../../languageHandler"); var _AccessibleButton = _interopRequireDefault(require("../views/elements/AccessibleButton")); var _Spinner = _interopRequireDefault(require("../views/elements/Spinner")); var _SearchBox = _interopRequireDefault(require("./SearchBox")); var _RoomAvatar = _interopRequireDefault(require("../views/avatars/RoomAvatar")); var _StyledCheckbox = _interopRequireDefault(require("../views/elements/StyledCheckbox")); var _BaseAvatar = _interopRequireDefault(require("../views/avatars/BaseAvatar")); var _Media = require("../../customisations/Media"); var _InfoTooltip = _interopRequireDefault(require("../views/elements/InfoTooltip")); var _TextWithTooltip = _interopRequireDefault(require("../views/elements/TextWithTooltip")); var _useStateToggle = require("../../hooks/useStateToggle"); var _SpaceStore = require("../../stores/spaces/SpaceStore"); var _HtmlUtils = require("../../HtmlUtils"); var _useDispatcher = require("../../hooks/useDispatcher"); var _actions = require("../../dispatcher/actions"); var _RovingTabIndex = require("../../accessibility/RovingTabIndex"); var _MatrixClientContext = _interopRequireDefault(require("../../contexts/MatrixClientContext")); var _useEventEmitter = require("../../hooks/useEventEmitter"); var _RoomUpgrade = require("../../utils/RoomUpgrade"); var _KeyboardShortcuts = require("../../accessibility/KeyboardShortcuts"); var _KeyBindingsManager = require("../../KeyBindingsManager"); var _useTopic = require("../../hooks/room/useTopic"); var _SDKContext = require("../../contexts/SDKContext"); var _Rooms = require("../../Rooms"); var _SettingsStore = _interopRequireDefault(require("../../settings/SettingsStore")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* Copyright 2024 New Vector Ltd. Copyright 2021-2023 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const Tile = ({ room, suggested, selected, hasPermissions, onToggleClick, onViewRoomClick, onJoinRoomClick, numChildRooms, children }) => { const cli = (0, _react.useContext)(_MatrixClientContext.default); const joinedRoom = (0, _useEventEmitter.useTypedEventEmitterState)(cli, _matrix.ClientEvent.Room, () => { const cliRoom = cli?.getRoom(room.room_id); return cliRoom?.getMyMembership() === _types.KnownMembership.Join ? cliRoom : undefined; }); const joinedRoomName = (0, _useEventEmitter.useTypedEventEmitterState)(joinedRoom, _matrix.RoomEvent.Name, room => room?.name); const name = joinedRoomName || room.name || room.canonical_alias || room.aliases?.[0] || (room.room_type === _matrix.RoomType.Space ? (0, _languageHandler._t)("common|unnamed_space") : (0, _languageHandler._t)("common|unnamed_room")); const [showChildren, toggleShowChildren] = (0, _useStateToggle.useStateToggle)(true); const [onFocus, isActive, ref] = (0, _RovingTabIndex.useRovingTabIndex)(); const [busy, setBusy] = (0, _react.useState)(false); const onPreviewClick = ev => { ev.preventDefault(); ev.stopPropagation(); onViewRoomClick(); }; const onJoinClick = async ev => { setBusy(true); ev.preventDefault(); ev.stopPropagation(); try { await onJoinRoomClick(); await (0, _RoomUpgrade.awaitRoomDownSync)(cli, room.room_id); } finally { setBusy(false); } }; let button; if (busy) { button = /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { disabled: true, onClick: onJoinClick, kind: "primary_outline", onFocus: onFocus, tabIndex: isActive ? 0 : -1, title: (0, _languageHandler._t)("space|joining_space") }, /*#__PURE__*/_react.default.createElement(_Spinner.default, { w: 24, h: 24 })); } else if (joinedRoom || room.join_rule === _matrix.JoinRule.Knock) { // If the room is knockable, show the "View" button even if we are not a member; that // allows us to reuse the "request to join" UX in RoomView. button = /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: onPreviewClick, kind: "primary_outline", onFocus: onFocus, tabIndex: isActive ? 0 : -1 }, (0, _languageHandler._t)("action|view")); } else { button = /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: onJoinClick, kind: "primary", onFocus: onFocus, tabIndex: isActive ? 0 : -1 }, (0, _languageHandler._t)("action|join")); } let checkbox; if (onToggleClick) { if (hasPermissions) { checkbox = /*#__PURE__*/_react.default.createElement(_StyledCheckbox.default, { checked: !!selected, onChange: onToggleClick, tabIndex: isActive ? 0 : -1 }); } else { checkbox = /*#__PURE__*/_react.default.createElement(_TextWithTooltip.default, { tooltip: (0, _languageHandler._t)("space|user_lacks_permission"), onClick: ev => { ev.stopPropagation(); } }, /*#__PURE__*/_react.default.createElement(_StyledCheckbox.default, { disabled: true, tabIndex: isActive ? 0 : -1 })); } } let avatar; if (joinedRoom) { avatar = /*#__PURE__*/_react.default.createElement(_RoomAvatar.default, { room: joinedRoom, size: "20px" }); } else { avatar = /*#__PURE__*/_react.default.createElement(_BaseAvatar.default, { name: name, idName: room.room_id, url: room.avatar_url ? (0, _Media.mediaFromMxc)(room.avatar_url).getSquareThumbnailHttp(20) : null, size: "20px" }); } let description = (0, _languageHandler._t)("common|n_members", { count: room.num_joined_members ?? 0 }); if (numChildRooms !== undefined) { description += " · " + (0, _languageHandler._t)("common|n_rooms", { count: numChildRooms }); } let topic; if (joinedRoom) { const topicObj = (0, _useTopic.getTopic)(joinedRoom); topic = (0, _HtmlUtils.topicToHtml)(topicObj?.text, topicObj?.html); } else { topic = room.topic; } let topicSection; if (topic) { topicSection = /*#__PURE__*/_react.default.createElement(_HtmlUtils.Linkify, { options: { attributes: { onClick(ev) { // prevent clicks on links from bubbling up to the room tile ev.stopPropagation(); } } } }, " · ", topic); } let joinedSection; if (joinedRoom) { joinedSection = /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_roomTile_joined" }, (0, _languageHandler._t)("common|joined")); } let suggestedSection; if (suggested && (!joinedRoom || hasPermissions)) { suggestedSection = /*#__PURE__*/_react.default.createElement(_InfoTooltip.default, { tooltip: (0, _languageHandler._t)("space|suggested_tooltip") }, (0, _languageHandler._t)("space|suggested")); } const content = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_roomTile_item" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_roomTile_avatar" }, avatar), /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_roomTile_name" }, name, joinedSection, suggestedSection), /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_roomTile_info" }, description, topicSection)), /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_actions" }, button, checkbox)); let childToggle; let childSection; let onKeyDown; if (children) { // the chevron is purposefully a div rather than a button as it should be ignored for a11y childToggle = /*#__PURE__*/_react.default.createElement("div", { className: (0, _classnames.default)("mx_SpaceHierarchy_subspace_toggle", { mx_SpaceHierarchy_subspace_toggle_shown: showChildren }), onClick: ev => { ev.stopPropagation(); toggleShowChildren(); } }); if (showChildren) { const onChildrenKeyDown = e => { const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getAccessibilityAction(e); switch (action) { case _KeyboardShortcuts.KeyBindingAction.ArrowLeft: e.preventDefault(); e.stopPropagation(); ref.current?.focus(); break; } }; childSection = /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_subspace_children", onKeyDown: onChildrenKeyDown, role: "group" }, children); } onKeyDown = e => { let handled = false; const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getAccessibilityAction(e); switch (action) { case _KeyboardShortcuts.KeyBindingAction.ArrowLeft: if (showChildren) { handled = true; toggleShowChildren(); } break; case _KeyboardShortcuts.KeyBindingAction.ArrowRight: handled = true; if (showChildren) { const childSection = ref.current?.nextElementSibling; childSection?.querySelector(".mx_SpaceHierarchy_roomTile")?.focus(); } else { toggleShowChildren(); } break; } if (handled) { e.preventDefault(); e.stopPropagation(); } }; } return /*#__PURE__*/_react.default.createElement("li", { className: "mx_SpaceHierarchy_roomTileWrapper", role: "treeitem", "aria-selected": selected, "aria-expanded": children ? showChildren : undefined }, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { className: (0, _classnames.default)("mx_SpaceHierarchy_roomTile", { mx_SpaceHierarchy_subspace: room.room_type === _matrix.RoomType.Space, mx_SpaceHierarchy_joining: busy }), onClick: hasPermissions && onToggleClick ? onToggleClick : onPreviewClick, onKeyDown: onKeyDown, ref: ref, onFocus: onFocus, tabIndex: isActive ? 0 : -1 }, content, childToggle), childSection); }; const showRoom = (cli, hierarchy, roomId, roomType) => { const room = hierarchy.roomMap.get(roomId); // Don't let the user view a room they won't be able to either peek or join: // fail earlier so they don't have to click back to the directory. if (cli.isGuest()) { if (!room?.world_readable && !room?.guest_can_join) { _dispatcher.default.dispatch({ action: "require_registration" }); return; } } const roomAlias = (0, _Rooms.getDisplayAliasForAliasSet)(room?.canonical_alias ?? "", room?.aliases ?? []) || undefined; _dispatcher.default.dispatch({ action: _actions.Action.ViewRoom, should_peek: true, room_alias: roomAlias, room_id: roomId, via_servers: Array.from(hierarchy.viaMap.get(roomId) || []), oob_data: { avatarUrl: room?.avatar_url, // XXX: This logic is duplicated from the JS SDK which would normally decide what the name is. name: room?.name || roomAlias || (0, _languageHandler._t)("common|unnamed_room"), roomType }, metricsTrigger: "RoomDirectory" }); }; exports.showRoom = showRoom; const joinRoom = async (cli, hierarchy, roomId) => { // Don't let the user view a room they won't be able to either peek or join: // fail earlier so they don't have to click back to the directory. if (cli.isGuest()) { _dispatcher.default.dispatch({ action: "require_registration" }); return; } try { await cli.joinRoom(roomId, { viaServers: Array.from(hierarchy.viaMap.get(roomId) || []) }); } catch (err) { if (err instanceof _matrix.MatrixError) { _SDKContext.SdkContextClass.instance.roomViewStore.showJoinRoomError(err, roomId); } else { _logger.logger.warn("Got a non-MatrixError while joining room", err); _SDKContext.SdkContextClass.instance.roomViewStore.showJoinRoomError(new _matrix.MatrixError({ error: (0, _languageHandler._t)("error|unknown") }), roomId); } // rethrow error so that the caller can handle react to it too throw err; } _dispatcher.default.dispatch({ action: _actions.Action.JoinRoomReady, roomId, metricsTrigger: "SpaceHierarchy" }); }; exports.joinRoom = joinRoom; const toLocalRoom = (cli, room, hierarchy) => { const history = cli.getRoomUpgradeHistory(room.room_id, true, _SettingsStore.default.getValue("feature_dynamic_room_predecessors")); // Pick latest room that is actually part of the hierarchy let cliRoom = null; for (let idx = history.length - 1; idx >= 0; --idx) { if (hierarchy.roomMap.get(history[idx].roomId)) { cliRoom = history[idx]; break; } } if (cliRoom) { return _objectSpread(_objectSpread({}, room), {}, { room_id: cliRoom.roomId, room_type: cliRoom.getType(), name: cliRoom.name, topic: cliRoom.currentState.getStateEvents(_matrix.EventType.RoomTopic, "")?.getContent().topic, avatar_url: cliRoom.getMxcAvatarUrl() ?? undefined, canonical_alias: cliRoom.getCanonicalAlias() ?? undefined, aliases: cliRoom.getAltAliases(), world_readable: cliRoom.currentState.getStateEvents(_matrix.EventType.RoomHistoryVisibility, "")?.getContent().history_visibility === _matrix.HistoryVisibility.WorldReadable, guest_can_join: cliRoom.currentState.getStateEvents(_matrix.EventType.RoomGuestAccess, "")?.getContent().guest_access === _matrix.GuestAccess.CanJoin, num_joined_members: cliRoom.getJoinedMemberCount() }); } return room; }; exports.toLocalRoom = toLocalRoom; const HierarchyLevel = ({ root, roomSet, hierarchy, parents, selectedMap, onViewRoomClick, onJoinRoomClick, onToggleClick }) => { const cli = (0, _react.useContext)(_MatrixClientContext.default); const space = cli.getRoom(root.room_id); const hasPermissions = space?.currentState.maySendStateEvent(_matrix.EventType.SpaceChild, cli.getSafeUserId()); const sortedChildren = (0, _lodash.sortBy)(root.children_state, ev => { return (0, _SpaceStore.getChildOrder)(ev.content.order, ev.origin_server_ts, ev.state_key); }); const [subspaces, childRooms] = sortedChildren.reduce((result, ev) => { const room = hierarchy.roomMap.get(ev.state_key); if (room && roomSet.has(room)) { result[room.room_type === _matrix.RoomType.Space ? 0 : 1].push(toLocalRoom(cli, room, hierarchy)); } return result; }, [[], []]); const newParents = new Set(parents).add(root.room_id); return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, (0, _lodash.uniqBy)(childRooms, "room_id").map(room => /*#__PURE__*/_react.default.createElement(Tile, { key: room.room_id, room: room, suggested: hierarchy.isSuggested(root.room_id, room.room_id), selected: selectedMap?.get(root.room_id)?.has(room.room_id), onViewRoomClick: () => onViewRoomClick(room.room_id, room.room_type), onJoinRoomClick: () => onJoinRoomClick(room.room_id, newParents), hasPermissions: hasPermissions, onToggleClick: onToggleClick ? () => onToggleClick(root.room_id, room.room_id) : undefined })), subspaces.filter(room => !newParents.has(room.room_id)).map(space => /*#__PURE__*/_react.default.createElement(Tile, { key: space.room_id, room: space, numChildRooms: space.children_state.filter(ev => { const room = hierarchy.roomMap.get(ev.state_key); return room && roomSet.has(room) && !room.room_type; }).length, suggested: hierarchy.isSuggested(root.room_id, space.room_id), selected: selectedMap?.get(root.room_id)?.has(space.room_id), onViewRoomClick: () => onViewRoomClick(space.room_id, _matrix.RoomType.Space), onJoinRoomClick: () => onJoinRoomClick(space.room_id, newParents), hasPermissions: hasPermissions, onToggleClick: onToggleClick ? () => onToggleClick(root.room_id, space.room_id) : undefined }, /*#__PURE__*/_react.default.createElement(HierarchyLevel, { root: space, roomSet: roomSet, hierarchy: hierarchy, parents: newParents, selectedMap: selectedMap, onViewRoomClick: onViewRoomClick, onJoinRoomClick: onJoinRoomClick, onToggleClick: onToggleClick })))); }; exports.HierarchyLevel = HierarchyLevel; const INITIAL_PAGE_SIZE = 20; const useRoomHierarchy = space => { const [rooms, setRooms] = (0, _react.useState)([]); const [hierarchy, setHierarchy] = (0, _react.useState)(); const [error, setError] = (0, _react.useState)(); const resetHierarchy = (0, _react.useCallback)(() => { setError(undefined); const hierarchy = new _roomHierarchy.RoomHierarchy(space, INITIAL_PAGE_SIZE); hierarchy.load().then(() => { if (space !== hierarchy.root) return; // discard stale results setRooms(hierarchy.rooms ?? []); }, setError); setHierarchy(hierarchy); }, [space]); (0, _react.useEffect)(resetHierarchy, [resetHierarchy]); (0, _useDispatcher.useDispatcher)(_dispatcher.default, payload => { if (payload.action === _actions.Action.UpdateSpaceHierarchy) { setRooms([]); // TODO resetHierarchy(); } }); const loadMore = (0, _react.useCallback)(async pageSize => { if (!hierarchy || hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return; await hierarchy.load(pageSize).catch(setError); setRooms(hierarchy.rooms ?? []); }, [error, hierarchy]); // Only return the hierarchy if it is for the space requested if (hierarchy?.root !== space) { return { loading: true, loadMore }; } return { loading: hierarchy.loading, rooms, hierarchy, loadMore, error }; }; exports.useRoomHierarchy = useRoomHierarchy; const useIntersectionObserver = callback => { const handleObserver = entries => { const target = entries[0]; if (target.isIntersecting) { callback(); } }; const observerRef = (0, _react.useRef)(); return element => { if (observerRef.current) { observerRef.current.disconnect(); } else if (element) { observerRef.current = new IntersectionObserver(handleObserver, { root: element.parentElement, rootMargin: "0px 0px 600px 0px" }); } if (observerRef.current && element) { observerRef.current.observe(element); } }; }; const ManageButtons = ({ hierarchy, selected, setSelected, setError }) => { const cli = (0, _react.useContext)(_MatrixClientContext.default); const [removing, setRemoving] = (0, _react.useState)(false); const [saving, setSaving] = (0, _react.useState)(false); const selectedRelations = Array.from(selected.keys()).flatMap(parentId => { return [...selected.get(parentId).values()].map(childId => [parentId, childId]); }); const selectionAllSuggested = selectedRelations.every(([parentId, childId]) => { return hierarchy.isSuggested(parentId, childId); }); const disabled = !selectedRelations.length || removing || saving; let buttonText = (0, _languageHandler._t)("common|saving"); if (!saving) { buttonText = selectionAllSuggested ? (0, _languageHandler._t)("space|unmark_suggested") : (0, _languageHandler._t)("space|mark_suggested"); } const title = !selectedRelations.length ? (0, _languageHandler._t)("space|select_room_below") : undefined; return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: async () => { setRemoving(true); try { const userId = cli.getSafeUserId(); for (const [parentId, childId] of selectedRelations) { await cli.sendStateEvent(parentId, _matrix.EventType.SpaceChild, {}, childId); // remove the child->parent relation too, if we have permission to. const childRoom = cli.getRoom(childId); const parentRelation = childRoom?.currentState.getStateEvents(_matrix.EventType.SpaceParent, parentId); if (childRoom?.currentState.maySendStateEvent(_matrix.EventType.SpaceParent, userId) && Array.isArray(parentRelation?.getContent().via)) { await cli.sendStateEvent(childId, _matrix.EventType.SpaceParent, {}, parentId); } hierarchy.removeRelation(parentId, childId); } } catch (e) { setError((0, _languageHandler._t)("space|failed_remove_rooms")); } setRemoving(false); setSelected(new Map()); }, kind: "danger_outline", disabled: disabled, "aria-label": removing ? (0, _languageHandler._t)("redact|ongoing") : (0, _languageHandler._t)("action|remove"), title: title, placement: "top" }, removing ? (0, _languageHandler._t)("redact|ongoing") : (0, _languageHandler._t)("action|remove")), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: async () => { setSaving(true); try { for (const [parentId, childId] of selectedRelations) { const suggested = !selectionAllSuggested; const existingContent = hierarchy.getRelation(parentId, childId)?.content; if (!existingContent || existingContent.suggested === suggested) continue; const content = _objectSpread(_objectSpread({}, existingContent), {}, { suggested: !selectionAllSuggested }); await cli.sendStateEvent(parentId, _matrix.EventType.SpaceChild, content, childId); // mutate the local state to save us having to refetch the world existingContent.suggested = content.suggested; } } catch (e) { setError("Failed to update some suggestions. Try again later"); } setSaving(false); setSelected(new Map()); }, kind: "primary_outline", disabled: disabled, "aria-label": buttonText, title: title, placement: "top" }, buttonText)); }; const SpaceHierarchy = ({ space, initialText = "", showRoom, additionalButtons }) => { const cli = (0, _react.useContext)(_MatrixClientContext.default); const [query, setQuery] = (0, _react.useState)(initialText); const [selected, setSelected] = (0, _react.useState)(new Map()); // Map<parentId, Set<childId>> const { loading, rooms, hierarchy, loadMore, error: hierarchyError } = useRoomHierarchy(space); const filteredRoomSet = (0, _react.useMemo)(() => { if (!rooms?.length || !hierarchy) return new Set(); const lcQuery = query.toLowerCase().trim(); if (!lcQuery) return new Set(rooms); const directMatches = rooms.filter(r => { return r.name?.toLowerCase().includes(lcQuery) || r.topic?.toLowerCase().includes(lcQuery); }); // Walk back up the tree to find all parents of the direct matches to show their place in the hierarchy const visited = new Set(); const queue = [...directMatches.map(r => r.room_id)]; while (queue.length) { const roomId = queue.pop(); visited.add(roomId); hierarchy.backRefs.get(roomId)?.forEach(parentId => { if (!visited.has(parentId)) { queue.push(parentId); } }); } return new Set(rooms.filter(r => visited.has(r.room_id))); }, [rooms, hierarchy, query]); const [error, setError] = (0, _react.useState)(""); let errorText = error; if (!error && hierarchyError) { errorText = (0, _languageHandler._t)("space|failed_load_rooms"); } const loaderRef = useIntersectionObserver(loadMore); if (!loading && hierarchy.noSupport) { return /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("space|incompatible_server_hierarchy")); } const onKeyDown = (ev, state) => { const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getAccessibilityAction(ev); if (action === _KeyboardShortcuts.KeyBindingAction.ArrowDown && ev.currentTarget.classList.contains("mx_SpaceHierarchy_search")) { state.refs[0]?.current?.focus(); } }; const onToggleClick = (parentId, childId) => { setError(""); if (!selected.has(parentId)) { setSelected(new Map(selected.set(parentId, new Set([childId])))); return; } const parentSet = selected.get(parentId); if (!parentSet.has(childId)) { setSelected(new Map(selected.set(parentId, new Set([...parentSet, childId])))); return; } parentSet.delete(childId); setSelected(new Map(selected.set(parentId, new Set(parentSet)))); }; return /*#__PURE__*/_react.default.createElement(_RovingTabIndex.RovingTabIndexProvider, { onKeyDown: onKeyDown, handleHomeEnd: true, handleUpDown: true }, ({ onKeyDownHandler }) => { let content; if (!hierarchy || loading && !rooms?.length) { content = /*#__PURE__*/_react.default.createElement(_Spinner.default, null); } else { const hasPermissions = space?.getMyMembership() === _types.KnownMembership.Join && space.currentState.maySendStateEvent(_matrix.EventType.SpaceChild, cli.getSafeUserId()); const root = hierarchy.roomMap.get(space.roomId); let results; if (filteredRoomSet.size && root) { results = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(HierarchyLevel, { root: root, roomSet: filteredRoomSet, hierarchy: hierarchy, parents: new Set(), selectedMap: selected, onToggleClick: hasPermissions ? onToggleClick : undefined, onViewRoomClick: (roomId, roomType) => showRoom(cli, hierarchy, roomId, roomType), onJoinRoomClick: async (roomId, parents) => { for (const parent of parents) { if (cli.getRoom(parent)?.getMyMembership() !== _types.KnownMembership.Join) { await joinRoom(cli, hierarchy, parent); } } await joinRoom(cli, hierarchy, roomId); } })); } else if (!hierarchy.canLoadMore) { results = /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_noResults" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("common|no_results_found")), /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("space|no_search_result_hint"))); } let loader; if (hierarchy.canLoadMore) { loader = /*#__PURE__*/_react.default.createElement("div", { ref: loaderRef }, /*#__PURE__*/_react.default.createElement(_Spinner.default, null)); } content = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_listHeader" }, /*#__PURE__*/_react.default.createElement("h4", { className: "mx_SpaceHierarchy_listHeader_header" }, query.trim() ? (0, _languageHandler._t)("space|title_when_query_available") : (0, _languageHandler._t)("space|title_when_query_unavailable")), /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_listHeader_buttons" }, additionalButtons, hasPermissions && /*#__PURE__*/_react.default.createElement(ManageButtons, { hierarchy: hierarchy, selected: selected, setSelected: setSelected, setError: setError }))), errorText && /*#__PURE__*/_react.default.createElement("div", { className: "mx_SpaceHierarchy_error" }, errorText), /*#__PURE__*/_react.default.createElement("ul", { className: "mx_SpaceHierarchy_list", onKeyDown: onKeyDownHandler, role: "tree", "aria-label": (0, _languageHandler._t)("common|space") }, results), loader); } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_SearchBox.default, { className: "mx_SpaceHierarchy_search mx_textinput_icon mx_textinput_search", placeholder: (0, _languageHandler._t)("space|search_placeholder"), onSearch: setQuery, autoFocus: true, initialValue: initialText, onKeyDown: onKeyDownHandler }), content); }); }; var _default = exports.default = SpaceHierarchy; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfbWF0cml4IiwiX3Jvb21IaWVyYXJjaHkiLCJfY2xhc3NuYW1lcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbG9kYXNoIiwiX2xvZ2dlciIsIl90eXBlcyIsIl9kaXNwYXRjaGVyIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX1NwaW5uZXIiLCJfU2VhcmNoQm94IiwiX1Jvb21BdmF0YXIiLCJfU3R5bGVkQ2hlY2tib3giLCJfQmFzZUF2YXRhciIsIl9NZWRpYSIsIl9JbmZvVG9vbHRpcCIsIl9UZXh0V2l0aFRvb2x0aXAiLCJfdXNlU3RhdGVUb2dnbGUiLCJfU3BhY2VTdG9yZSIsIl9IdG1sVXRpbHMiLCJfdXNlRGlzcGF0Y2hlciIsIl9hY3Rpb25zIiwiX1JvdmluZ1RhYkluZGV4IiwiX01hdHJpeENsaWVudENvbnRleHQiLCJfdXNlRXZlbnRFbWl0dGVyIiwiX1Jvb21VcGdyYWRlIiwiX0tleWJvYXJkU2hvcnRjdXRzIiwiX0tleUJpbmRpbmdzTWFuYWdlciIsIl91c2VUb3BpYyIsIl9TREtDb250ZXh0IiwiX1Jvb21zIiwiX1NldHRpbmdzU3RvcmUiLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJlIiwiV2Vha01hcCIsInIiLCJ0IiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJuIiwiX19wcm90b19fIiwiYSIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwidSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImkiLCJzZXQiLCJvd25LZXlzIiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJUaWxlIiwicm9vbSIsInN1Z2dlc3RlZCIsInNlbGVjdGVkIiwiaGFzUGVybWlzc2lvbnMiLCJvblRvZ2dsZUNsaWNrIiwib25WaWV3Um9vbUNsaWNrIiwib25Kb2luUm9vbUNsaWNrIiwibnVtQ2hpbGRSb29tcyIsImNoaWxkcmVuIiwiY2xpIiwidXNlQ29udGV4dCIsIk1hdHJpeENsaWVudENvbnRleHQiLCJqb2luZWRSb29tIiwidXNlVHlwZWRFdmVudEVtaXR0ZXJTdGF0ZSIsIkNsaWVudEV2ZW50IiwiUm9vbSIsImNsaVJvb20iLCJnZXRSb29tIiwicm9vbV9pZCIsImdldE15TWVtYmVyc2hpcCIsIktub3duTWVtYmVyc2hpcCIsIkpvaW4iLCJ1bmRlZmluZWQiLCJqb2luZWRSb29tTmFtZSIsIlJvb21FdmVudCIsIk5hbWUiLCJuYW1lIiwiY2Fub25pY2FsX2FsaWFzIiwiYWxpYXNlcyIsInJvb21fdHlwZSIsIlJvb21UeXBlIiwiU3BhY2UiLCJfdCIsInNob3dDaGlsZHJlbiIsInRvZ2dsZVNob3dDaGlsZHJlbiIsInVzZVN0YXRlVG9nZ2xlIiwib25Gb2N1cyIsImlzQWN0aXZlIiwicmVmIiwidXNlUm92aW5nVGFiSW5kZXgiLCJidXN5Iiwic2V0QnVzeSIsInVzZVN0YXRlIiwib25QcmV2aWV3Q2xpY2siLCJldiIsInByZXZlbnREZWZhdWx0Iiwic3RvcFByb3BhZ2F0aW9uIiwib25Kb2luQ2xpY2siLCJhd2FpdFJvb21Eb3duU3luYyIsImJ1dHRvbiIsImNyZWF0ZUVsZW1lbnQiLCJkaXNhYmxlZCIsIm9uQ2xpY2siLCJraW5kIiwidGFiSW5kZXgiLCJ0aXRsZSIsInciLCJoIiwiam9pbl9ydWxlIiwiSm9pblJ1bGUiLCJLbm9jayIsImNoZWNrYm94IiwiY2hlY2tlZCIsIm9uQ2hhbmdlIiwidG9vbHRpcCIsImF2YXRhciIsInNpemUiLCJpZE5hbWUiLCJ1cmwiLCJhdmF0YXJfdXJsIiwibWVkaWFGcm9tTXhjIiwiZ2V0U3F1YXJlVGh1bWJuYWlsSHR0cCIsImRlc2NyaXB0aW9uIiwiY291bnQiLCJudW1fam9pbmVkX21lbWJlcnMiLCJ0b3BpYyIsInRvcGljT2JqIiwiZ2V0VG9waWMiLCJ0b3BpY1RvSHRtbCIsInRleHQiLCJodG1sIiwidG9waWNTZWN0aW9uIiwiTGlua2lmeSIsIm9wdGlvbnMiLCJhdHRyaWJ1dGVzIiwiam9pbmVkU2VjdGlvbiIsImNsYXNzTmFtZSIsInN1Z2dlc3RlZFNlY3Rpb24iLCJjb250ZW50IiwiRnJhZ21lbnQiLCJjaGlsZFRvZ2dsZSIsImNoaWxkU2VjdGlvbiIsIm9uS2V5RG93biIsImNsYXNzTmFtZXMiLCJteF9TcGFjZUhpZXJhcmNoeV9zdWJzcGFjZV90b2dnbGVfc2hvd24iLCJvbkNoaWxkcmVuS2V5RG93biIsImFjdGlvbiIsImdldEtleUJpbmRpbmdzTWFuYWdlciIsImdldEFjY2Vzc2liaWxpdHlBY3Rpb24iLCJLZXlCaW5kaW5nQWN0aW9uIiwiQXJyb3dMZWZ0IiwiY3VycmVudCIsImZvY3VzIiwicm9sZSIsImhhbmRsZWQiLCJBcnJvd1JpZ2h0IiwibmV4dEVsZW1lbnRTaWJsaW5nIiwicXVlcnlTZWxlY3RvciIsIm14X1NwYWNlSGllcmFyY2h5X3N1YnNwYWNlIiwibXhfU3BhY2VIaWVyYXJjaHlfam9pbmluZyIsInNob3dSb29tIiwiaGllcmFyY2h5Iiwicm9vbUlkIiwicm9vbVR5cGUiLCJyb29tTWFwIiwiaXNHdWVzdCIsIndvcmxkX3JlYWRhYmxlIiwiZ3Vlc3RfY2FuX2pvaW4iLCJkZWZhdWx0RGlzcGF0Y2hlciIsImRpc3BhdGNoIiwicm9vbUFsaWFzIiwiZ2V0RGlzcGxheUFsaWFzRm9yQWxpYXNTZXQiLCJBY3Rpb24iLCJWaWV3Um9vbSIsInNob3VsZF9wZWVrIiwicm9vbV9hbGlhcyIsInZpYV9zZXJ2ZXJzIiwiQXJyYXkiLCJmcm9tIiwidmlhTWFwIiwib29iX2RhdGEiLCJhdmF0YXJVcmwiLCJtZXRyaWNzVHJpZ2dlciIsImV4cG9ydHMiLCJqb2luUm9vbSIsInZpYVNlcnZlcnMiLCJlcnIiLCJNYXRyaXhFcnJvciIsIlNka0NvbnRleHRDbGFzcyIsImluc3RhbmNlIiwicm9vbVZpZXdTdG9yZSIsInNob3dKb2luUm9vbUVycm9yIiwibG9nZ2VyIiwid2FybiIsImVycm9yIiwiSm9pblJvb21SZWFkeSIsInRvTG9jYWxSb29tIiwiaGlzdG9yeSIsImdldFJvb21VcGdyYWRlSGlzdG9yeSIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsImlkeCIsImdldFR5cGUiLCJjdXJyZW50U3RhdGUiLCJnZXRTdGF0ZUV2ZW50cyIsIkV2ZW50VHlwZSIsIlJvb21Ub3BpYyIsImdldENvbnRlbnQiLCJnZXRNeGNBdmF0YXJVcmwiLCJnZXRDYW5vbmljYWxBbGlhcyIsImdldEFsdEFsaWFzZXMiLCJSb29tSGlzdG9yeVZpc2liaWxpdHkiLCJoaXN0b3J5X3Zpc2liaWxpdHkiLCJIaXN0b3J5VmlzaWJpbGl0eSIsIldvcmxkUmVhZGFibGUiLCJSb29tR3Vlc3RBY2Nlc3MiLCJndWVzdF9hY2Nlc3MiLCJHdWVzdEFjY2VzcyIsIkNhbkpvaW4iLCJnZXRKb2luZWRNZW1iZXJDb3VudCIsIkhpZXJhcmNoeUxldmVsIiwicm9vdCIsInJvb21TZXQiLCJwYXJlbnRzIiwic2VsZWN0ZWRNYXAiLCJzcGFjZSIsIm1heVNlbmRTdGF0ZUV2ZW50IiwiU3BhY2VDaGlsZCIsImdldFNhZmVVc2VySWQiLCJzb3J0ZWRDaGlsZHJlbiIsInNvcnRCeSIsImNoaWxkcmVuX3N0YXRlIiwiZ2V0Q2hpbGRPcmRlciIsIm9yZGVyIiwib3JpZ2luX3NlcnZlcl90cyIsInN0YXRlX2tleSIsInN1YnNwYWNlcyIsImNoaWxkUm9vbXMiLCJyZWR1Y2UiLCJyZXN1bHQiLCJuZXdQYXJlbnRzIiwiU2V0IiwiYWRkIiwidW5pcUJ5IiwibWFwIiwia2V5IiwiaXNTdWdnZXN0ZWQiLCJJTklUSUFMX1BBR0VfU0laRSIsInVzZVJvb21IaWVyYXJjaHkiLCJyb29tcyIsInNldFJvb21zIiwic2V0SGllcmFyY2h5Iiwic2V0RXJyb3IiLCJyZXNldEhpZXJhcmNoeSIsInVzZUNhbGxiYWNrIiwiUm9vbUhpZXJhcmNoeSIsImxvYWQiLCJ0aGVuIiwidXNlRWZmZWN0IiwidXNlRGlzcGF0Y2hlciIsInBheWxvYWQiLCJVcGRhdGVTcGFjZUhpZXJhcmNoeSIsImxvYWRNb3JlIiwicGFnZVNpemUiLCJsb2FkaW5nIiwiY2FuTG9hZE1vcmUiLCJub1N1cHBvcnQiLCJjYXRjaCIsInVzZUludGVyc2VjdGlvbk9ic2VydmVyIiwiY2FsbGJhY2siLCJoYW5kbGVPYnNlcnZlciIsImVudHJpZXMiLCJ0YXJnZXQiLCJpc0ludGVyc2VjdGluZyIsIm9ic2VydmVyUmVmIiwidXNlUmVmIiwiZWxlbWVudCIsImRpc2Nvbm5lY3QiLCJJbnRlcnNlY3Rpb25PYnNlcnZlciIsInBhcmVudEVsZW1lbnQiLCJyb290TWFyZ2luIiwib2JzZXJ2ZSIsIk1hbmFnZUJ1dHRvbnMiLCJzZXRTZWxlY3RlZCIsInJlbW92aW5nIiwic2V0UmVtb3ZpbmciLCJzYXZpbmciLCJzZXRTYXZpbmciLCJzZWxlY3RlZFJlbGF0aW9ucyIsImZsYXRNYXAiLCJwYXJlbnRJZCIsInZhbHVlcyIsImNoaWxkSWQiLCJzZWxlY3Rpb25BbGxTdWdnZXN0ZWQiLCJldmVyeSIsImJ1dHRvblRleHQiLCJ1c2VySWQiLCJzZW5kU3RhdGVFdmVudCIsImNoaWxkUm9vbSIsInBhcmVudFJlbGF0aW9uIiwiU3BhY2VQYXJlbnQiLCJpc0FycmF5IiwidmlhIiwicmVtb3ZlUmVsYXRpb24iLCJNYXAiLCJwbGFjZW1lbnQiLCJleGlzdGluZ0NvbnRlbnQiLCJnZXRSZWxhdGlvbiIsIlNwYWNlSGllcmFyY2h5IiwiaW5pdGlhbFRleHQiLCJhZGRpdGlvbmFsQnV0dG9ucyIsInF1ZXJ5Iiwic2V0UXVlcnkiLCJoaWVyYXJjaHlFcnJvciIsImZpbHRlcmVkUm9vbVNldCIsInVzZU1lbW8iLCJsY1F1ZXJ5IiwidG9Mb3dlckNhc2UiLCJ0cmltIiwiZGlyZWN0TWF0Y2hlcyIsImluY2x1ZGVzIiwidmlzaXRlZCIsInF1ZXVlIiwicG9wIiwiYmFja1JlZnMiLCJlcnJvclRleHQiLCJsb2FkZXJSZWYiLCJzdGF0ZSIsIkFycm93RG93biIsImN1cnJlbnRUYXJnZXQiLCJjbGFzc0xpc3QiLCJjb250YWlucyIsInJlZnMiLCJwYXJlbnRTZXQiLCJkZWxldGUiLCJSb3ZpbmdUYWJJbmRleFByb3ZpZGVyIiwiaGFuZGxlSG9tZUVuZCIsImhhbmRsZVVwRG93biIsIm9uS2V5RG93bkhhbmRsZXIiLCJyZXN1bHRzIiwicGFyZW50IiwibG9hZGVyIiwicGxhY2Vob2xkZXIiLCJvblNlYXJjaCIsImF1dG9Gb2N1cyIsImluaXRpYWxWYWx1ZSIsIl9kZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvc3RydWN0dXJlcy9TcGFjZUhpZXJhcmNoeS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjEtMjAyMyBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgUmVhY3QsIHtcbiAgICBEaXNwYXRjaCxcbiAgICBLZXlib2FyZEV2ZW50LFxuICAgIEtleWJvYXJkRXZlbnRIYW5kbGVyLFxuICAgIFJlYWN0RWxlbWVudCxcbiAgICBSZWFjdE5vZGUsXG4gICAgU2V0U3RhdGVBY3Rpb24sXG4gICAgdXNlQ2FsbGJhY2ssXG4gICAgdXNlQ29udGV4dCxcbiAgICB1c2VFZmZlY3QsXG4gICAgdXNlTWVtbyxcbiAgICB1c2VSZWYsXG4gICAgdXNlU3RhdGUsXG59IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHtcbiAgICBSb29tLFxuICAgIFJvb21FdmVudCxcbiAgICBDbGllbnRFdmVudCxcbiAgICBNYXRyaXhDbGllbnQsXG4gICAgTWF0cml4RXJyb3IsXG4gICAgRXZlbnRUeXBlLFxuICAgIFJvb21UeXBlLFxuICAgIEd1ZXN0QWNjZXNzLFxuICAgIEhpc3RvcnlWaXNpYmlsaXR5LFxuICAgIEhpZXJhcmNoeVJlbGF0aW9uLFxuICAgIEhpZXJhcmNoeVJvb20sXG4gICAgSm9pblJ1bGUsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IFJvb21IaWVyYXJjaHkgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvcm9vbS1oaWVyYXJjaHlcIjtcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gXCJjbGFzc25hbWVzXCI7XG5pbXBvcnQgeyBzb3J0QnksIHVuaXFCeSB9IGZyb20gXCJsb2Rhc2hcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcbmltcG9ydCB7IEtub3duTWVtYmVyc2hpcCwgU3BhY2VDaGlsZEV2ZW50Q29udGVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuXG5pbXBvcnQgZGVmYXVsdERpc3BhdGNoZXIgZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgQWNjZXNzaWJsZUJ1dHRvbiwgeyBCdXR0b25FdmVudCB9IGZyb20gXCIuLi92aWV3cy9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgU3Bpbm5lciBmcm9tIFwiLi4vdmlld3MvZWxlbWVudHMvU3Bpbm5lclwiO1xuaW1wb3J0IFNlYXJjaEJveCBmcm9tIFwiLi9TZWFyY2hCb3hcIjtcbmltcG9ydCBSb29tQXZhdGFyIGZyb20gXCIuLi92aWV3cy9hdmF0YXJzL1Jvb21BdmF0YXJcIjtcbmltcG9ydCBTdHlsZWRDaGVja2JveCBmcm9tIFwiLi4vdmlld3MvZWxlbWVudHMvU3R5bGVkQ2hlY2tib3hcIjtcbmltcG9ydCBCYXNlQXZhdGFyIGZyb20gXCIuLi92aWV3cy9hdmF0YXJzL0Jhc2VBdmF0YXJcIjtcbmltcG9ydCB7IG1lZGlhRnJvbU14YyB9IGZyb20gXCIuLi8uLi9jdXN0b21pc2F0aW9ucy9NZWRpYVwiO1xuaW1wb3J0IEluZm9Ub29sdGlwIGZyb20gXCIuLi92aWV3cy9lbGVtZW50cy9JbmZvVG9vbHRpcFwiO1xuaW1wb3J0IFRleHRXaXRoVG9vbHRpcCBmcm9tIFwiLi4vdmlld3MvZWxlbWVudHMvVGV4dFdpdGhUb29sdGlwXCI7XG5pbXBvcnQgeyB1c2VTdGF0ZVRvZ2dsZSB9IGZyb20gXCIuLi8uLi9ob29rcy91c2VTdGF0ZVRvZ2dsZVwiO1xuaW1wb3J0IHsgZ2V0Q2hpbGRPcmRlciB9IGZyb20gXCIuLi8uLi9zdG9yZXMvc3BhY2VzL1NwYWNlU3RvcmVcIjtcbmltcG9ydCB7IExpbmtpZnksIHRvcGljVG9IdG1sIH0gZnJvbSBcIi4uLy4uL0h0bWxVdGlsc1wiO1xuaW1wb3J0IHsgdXNlRGlzcGF0Y2hlciB9IGZyb20gXCIuLi8uLi9ob29rcy91c2VEaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBBY3Rpb24gfSBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9hY3Rpb25zXCI7XG5pbXBvcnQgeyBJU3RhdGUsIFJvdmluZ1RhYkluZGV4UHJvdmlkZXIsIHVzZVJvdmluZ1RhYkluZGV4IH0gZnJvbSBcIi4uLy4uL2FjY2Vzc2liaWxpdHkvUm92aW5nVGFiSW5kZXhcIjtcbmltcG9ydCBNYXRyaXhDbGllbnRDb250ZXh0IGZyb20gXCIuLi8uLi9jb250ZXh0cy9NYXRyaXhDbGllbnRDb250ZXh0XCI7XG5pbXBvcnQgeyB1c2VUeXBlZEV2ZW50RW1pdHRlclN0YXRlIH0gZnJvbSBcIi4uLy4uL2hvb2tzL3VzZUV2ZW50RW1pdHRlclwiO1xuaW1wb3J0IHsgSU9PQkRhdGEgfSBmcm9tIFwiLi4vLi4vc3RvcmVzL1RocmVlcGlkSW52aXRlU3RvcmVcIjtcbmltcG9ydCB7IGF3YWl0Um9vbURvd25TeW5jIH0gZnJvbSBcIi4uLy4uL3V0aWxzL1Jvb21VcGdyYWRlXCI7XG5pbXBvcnQgeyBWaWV3Um9vbVBheWxvYWQgfSBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkcy9WaWV3Um9vbVBheWxvYWRcIjtcbmltcG9ydCB7IEpvaW5Sb29tUmVhZHlQYXlsb2FkIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvSm9pblJvb21SZWFkeVBheWxvYWRcIjtcbmltcG9ydCB7IEtleUJpbmRpbmdBY3Rpb24gfSBmcm9tIFwiLi4vLi4vYWNjZXNzaWJpbGl0eS9LZXlib2FyZFNob3J0Y3V0c1wiO1xuaW1wb3J0IHsgZ2V0S2V5QmluZGluZ3NNYW5hZ2VyIH0gZnJvbSBcIi4uLy4uL0tleUJpbmRpbmdzTWFuYWdlclwiO1xuaW1wb3J0IHsgZ2V0VG9waWMgfSBmcm9tIFwiLi4vLi4vaG9va3Mvcm9vbS91c2VUb3BpY1wiO1xuaW1wb3J0IHsgU2RrQ29udGV4dENsYXNzIH0gZnJvbSBcIi4uLy4uL2NvbnRleHRzL1NES0NvbnRleHRcIjtcbmltcG9ydCB7IGdldERpc3BsYXlBbGlhc0ZvckFsaWFzU2V0IH0gZnJvbSBcIi4uLy4uL1Jvb21zXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuXG5pbnRlcmZhY2UgSVByb3BzIHtcbiAgICBzcGFjZTogUm9vbTtcbiAgICBpbml0aWFsVGV4dD86IHN0cmluZztcbiAgICBhZGRpdGlvbmFsQnV0dG9ucz86IFJlYWN0Tm9kZTtcbiAgICBzaG93Um9vbShjbGk6IE1hdHJpeENsaWVudCwgaGllcmFyY2h5OiBSb29tSGllcmFyY2h5LCByb29tSWQ6IHN0cmluZywgcm9vbVR5cGU/OiBSb29tVHlwZSk6IHZvaWQ7XG59XG5cbmludGVyZmFjZSBJVGlsZVByb3BzIHtcbiAgICByb29tOiBIaWVyYXJjaHlSb29tO1xuICAgIHN1Z2dlc3RlZD86IGJvb2xlYW47XG4gICAgc2VsZWN0ZWQ/OiBib29sZWFuO1xuICAgIG51bUNoaWxkUm9vbXM/OiBudW1iZXI7XG4gICAgaGFzUGVybWlzc2lvbnM/OiBib29sZWFuO1xuICAgIGNoaWxkcmVuPzogUmVhY3ROb2RlO1xuICAgIG9uVmlld1Jvb21DbGljaygpOiB2b2lkO1xuICAgIG9uSm9pblJvb21DbGljaygpOiBQcm9taXNlPHVua25vd24+O1xuICAgIG9uVG9nZ2xlQ2xpY2s/KCk6IHZvaWQ7XG59XG5cbmNvbnN0IFRpbGU6IFJlYWN0LkZDPElUaWxlUHJvcHM+ID0gKHtcbiAgICByb29tLFxuICAgIHN1Z2dlc3RlZCxcbiAgICBzZWxlY3RlZCxcbiAgICBoYXNQZXJtaXNzaW9ucyxcbiAgICBvblRvZ2dsZUNsaWNrLFxuICAgIG9uVmlld1Jvb21DbGljayxcbiAgICBvbkpvaW5Sb29tQ2xpY2ssXG4gICAgbnVtQ2hpbGRSb29tcyxcbiAgICBjaGlsZHJlbixcbn0pID0+IHtcbiAgICBjb25zdCBjbGkgPSB1c2VDb250ZXh0KE1hdHJpeENsaWVudENvbnRleHQpO1xuICAgIGNvbnN0IGpvaW5lZFJvb20gPSB1c2VUeXBlZEV2ZW50RW1pdHRlclN0YXRlKGNsaSwgQ2xpZW50RXZlbnQuUm9vbSwgKCkgPT4ge1xuICAgICAgICBjb25zdCBjbGlSb29tID0gY2xpPy5nZXRSb29tKHJvb20ucm9vbV9pZCk7XG4gICAgICAgIHJldHVybiBjbGlSb29tPy5nZXRNeU1lbWJlcnNoaXAoKSA9PT0gS25vd25NZW1iZXJzaGlwLkpvaW4gPyBjbGlSb29tIDogdW5kZWZpbmVkO1xuICAgIH0pO1xuICAgIGNvbnN0IGpvaW5lZFJvb21OYW1lID0gdXNlVHlwZWRFdmVudEVtaXR0ZXJTdGF0ZShqb2luZWRSb29tLCBSb29tRXZlbnQuTmFtZSwgKHJvb20pID0+IHJvb20/Lm5hbWUpO1xuICAgIGNvbnN0IG5hbWUgPVxuICAgICAgICBqb2luZWRSb29tTmFtZSB8fFxuICAgICAgICByb29tLm5hbWUgfHxcbiAgICAgICAgcm9vbS5jYW5vbmljYWxfYWxpYXMgfHxcbiAgICAgICAgcm9vbS5hbGlhc2VzPy5bMF0gfHxcbiAgICAgICAgKHJvb20ucm9vbV90eXBlID09PSBSb29tVHlwZS5TcGFjZSA/IF90KFwiY29tbW9ufHVubmFtZWRfc3BhY2VcIikgOiBfdChcImNvbW1vbnx1bm5hbWVkX3Jvb21cIikpO1xuXG4gICAgY29uc3QgW3Nob3dDaGlsZHJlbiwgdG9nZ2xlU2hvd0NoaWxkcmVuXSA9IHVzZVN0YXRlVG9nZ2xlKHRydWUpO1xuICAgIGNvbnN0IFtvbkZvY3VzLCBpc0FjdGl2ZSwgcmVmXSA9IHVzZVJvdmluZ1RhYkluZGV4KCk7XG4gICAgY29uc3QgW2J1c3ksIHNldEJ1c3ldID0gdXNlU3RhdGUoZmFsc2UpO1xuXG4gICAgY29uc3Qgb25QcmV2aWV3Q2xpY2sgPSAoZXY6IEJ1dHRvbkV2ZW50KTogdm9pZCA9PiB7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICBvblZpZXdSb29tQ2xpY2soKTtcbiAgICB9O1xuICAgIGNvbnN0IG9uSm9pbkNsaWNrID0gYXN5bmMgKGV2OiBCdXR0b25FdmVudCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBzZXRCdXN5KHRydWUpO1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IG9uSm9pblJvb21DbGljaygpO1xuICAgICAgICAgICAgYXdhaXQgYXdhaXRSb29tRG93blN5bmMoY2xpLCByb29tLnJvb21faWQpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgc2V0QnVzeShmYWxzZSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbGV0IGJ1dHRvbjogUmVhY3RFbGVtZW50O1xuICAgIGlmIChidXN5KSB7XG4gICAgICAgIGJ1dHRvbiA9IChcbiAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uXG4gICAgICAgICAgICAgICAgZGlzYWJsZWQ9e3RydWV9XG4gICAgICAgICAgICAgICAgb25DbGljaz17b25Kb2luQ2xpY2t9XG4gICAgICAgICAgICAgICAga2luZD1cInByaW1hcnlfb3V0bGluZVwiXG4gICAgICAgICAgICAgICAgb25Gb2N1cz17b25Gb2N1c31cbiAgICAgICAgICAgICAgICB0YWJJbmRleD17aXNBY3RpdmUgPyAwIDogLTF9XG4gICAgICAgICAgICAgICAgdGl0bGU9e190KFwic3BhY2V8am9pbmluZ19zcGFjZVwiKX1cbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8U3Bpbm5lciB3PXsyNH0gaD17MjR9IC8+XG4gICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICk7XG4gICAgfSBlbHNlIGlmIChqb2luZWRSb29tIHx8IHJvb20uam9pbl9ydWxlID09PSBKb2luUnVsZS5Lbm9jaykge1xuICAgICAgICAvLyBJZiB0aGUgcm9vbSBpcyBrbm9ja2FibGUsIHNob3cgdGhlIFwiVmlld1wiIGJ1dHRvbiBldmVuIGlmIHdlIGFyZSBub3QgYSBtZW1iZXI7IHRoYXRcbiAgICAgICAgLy8gYWxsb3dzIHVzIHRvIHJldXNlIHRoZSBcInJlcXVlc3QgdG8gam9pblwiIFVYIGluIFJvb21WaWV3LlxuICAgICAgICBidXR0b24gPSAoXG4gICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvblxuICAgICAgICAgICAgICAgIG9uQ2xpY2s9e29uUHJldmlld0NsaWNrfVxuICAgICAgICAgICAgICAgIGtpbmQ9XCJwcmltYXJ5X291dGxpbmVcIlxuICAgICAgICAgICAgICAgIG9uRm9jdXM9e29uRm9jdXN9XG4gICAgICAgICAgICAgICAgdGFiSW5kZXg9e2lzQWN0aXZlID8gMCA6IC0xfVxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIHtfdChcImFjdGlvbnx2aWV3XCIpfVxuICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGJ1dHRvbiA9IChcbiAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIG9uQ2xpY2s9e29uSm9pbkNsaWNrfSBraW5kPVwicHJpbWFyeVwiIG9uRm9jdXM9e29uRm9jdXN9IHRhYkluZGV4PXtpc0FjdGl2ZSA/IDAgOiAtMX0+XG4gICAgICAgICAgICAgICAge190KFwiYWN0aW9ufGpvaW5cIil9XG4gICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IGNoZWNrYm94OiBSZWFjdEVsZW1lbnQgfCB1bmRlZmluZWQ7XG4gICAgaWYgKG9uVG9nZ2xlQ2xpY2spIHtcbiAgICAgICAgaWYgKGhhc1Blcm1pc3Npb25zKSB7XG4gICAgICAgICAgICBjaGVja2JveCA9IDxTdHlsZWRDaGVja2JveCBjaGVja2VkPXshIXNlbGVjdGVkfSBvbkNoYW5nZT17b25Ub2dnbGVDbGlja30gdGFiSW5kZXg9e2lzQWN0aXZlID8gMCA6IC0xfSAvPjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNoZWNrYm94ID0gKFxuICAgICAgICAgICAgICAgIDxUZXh0V2l0aFRvb2x0aXBcbiAgICAgICAgICAgICAgICAgICAgdG9vbHRpcD17X3QoXCJzcGFjZXx1c2VyX2xhY2tzX3Blcm1pc3Npb25cIil9XG4gICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9eyhldikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgIH19XG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICA8U3R5bGVkQ2hlY2tib3ggZGlzYWJsZWQ9e3RydWV9IHRhYkluZGV4PXtpc0FjdGl2ZSA/IDAgOiAtMX0gLz5cbiAgICAgICAgICAgICAgICA8L1RleHRXaXRoVG9vbHRpcD5cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgYXZhdGFyOiBSZWFjdEVsZW1lbnQ7XG4gICAgaWYgKGpvaW5lZFJvb20pIHtcbiAgICAgICAgYXZhdGFyID0gPFJvb21BdmF0YXIgcm9vbT17am9pbmVkUm9vbX0gc2l6ZT1cIjIwcHhcIiAvPjtcbiAgICB9IGVsc2Uge1xuICAgICAgICBhdmF0YXIgPSAoXG4gICAgICAgICAgICA8QmFzZUF2YXRhclxuICAgICAgICAgICAgICAgIG5hbWU9e25hbWV9XG4gICAgICAgICAgICAgICAgaWROYW1lPXtyb29tLnJvb21faWR9XG4gICAgICAgICAgICAgICAgdXJsPXtyb29tLmF2YXRhcl91cmwgPyBtZWRpYUZyb21NeGMocm9vbS5hdmF0YXJfdXJsKS5nZXRTcXVhcmVUaHVtYm5haWxIdHRwKDIwKSA6IG51bGx9XG4gICAgICAgICAgICAgICAgc2l6ZT1cIjIwcHhcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgZGVzY3JpcHRpb24gPSBfdChcImNvbW1vbnxuX21lbWJlcnNcIiwgeyBjb3VudDogcm9vbS5udW1fam9pbmVkX21lbWJlcnMgPz8gMCB9KTtcbiAgICBpZiAobnVtQ2hpbGRSb29tcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGRlc2NyaXB0aW9uICs9IFwiIMK3IFwiICsgX3QoXCJjb21tb258bl9yb29tc1wiLCB7IGNvdW50OiBudW1DaGlsZFJvb21zIH0pO1xuICAgIH1cblxuICAgIGxldCB0b3BpYzogUmVhY3ROb2RlIHwgc3RyaW5nIHwgbnVsbDtcbiAgICBpZiAoam9pbmVkUm9vbSkge1xuICAgICAgICBjb25zdCB0b3BpY09iaiA9IGdldFRvcGljKGpvaW5lZFJvb20pO1xuICAgICAgICB0b3BpYyA9IHRvcGljVG9IdG1sKHRvcGljT2JqPy50ZXh0LCB0b3BpY09iaj8uaHRtbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdG9waWMgPSByb29tLnRvcGljO1xuICAgIH1cblxuICAgIGxldCB0b3BpY1NlY3Rpb246IFJlYWN0Tm9kZSB8IHVuZGVmaW5lZDtcbiAgICBpZiAodG9waWMpIHtcbiAgICAgICAgdG9waWNTZWN0aW9uID0gKFxuICAgICAgICAgICAgPExpbmtpZnlcbiAgICAgICAgICAgICAgICBvcHRpb25zPXt7XG4gICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2soZXY6IE1vdXNlRXZlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBwcmV2ZW50IGNsaWNrcyBvbiBsaW5rcyBmcm9tIGJ1YmJsaW5nIHVwIHRvIHRoZSByb29tIHRpbGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfX1cbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7XCIgwrcgXCJ9XG4gICAgICAgICAgICAgICAge3RvcGljfVxuICAgICAgICAgICAgPC9MaW5raWZ5PlxuICAgICAgICApO1xuICAgIH1cblxuICAgIGxldCBqb2luZWRTZWN0aW9uOiBSZWFjdEVsZW1lbnQgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGpvaW5lZFJvb20pIHtcbiAgICAgICAgam9pbmVkU2VjdGlvbiA9IDxkaXYgY2xhc3NOYW1lPVwibXhfU3BhY2VIaWVyYXJjaHlfcm9vbVRpbGVfam9pbmVkXCI+e190KFwiY29tbW9ufGpvaW5lZFwiKX08L2Rpdj47XG4gICAgfVxuXG4gICAgbGV0IHN1Z2dlc3RlZFNlY3Rpb246IFJlYWN0RWxlbWVudCB8IHVuZGVmaW5lZDtcbiAgICBpZiAoc3VnZ2VzdGVkICYmICgham9pbmVkUm9vbSB8fCBoYXNQZXJtaXNzaW9ucykpIHtcbiAgICAgICAgc3VnZ2VzdGVkU2VjdGlvbiA9IDxJbmZvVG9vbHRpcCB0b29sdGlwPXtfdChcInNwYWNlfHN1Z2dlc3RlZF90b29sdGlwXCIpfT57X3QoXCJzcGFjZXxzdWdnZXN0ZWRcIil9PC9JbmZvVG9vbHRpcD47XG4gICAgfVxuXG4gICAgY29uc3QgY29udGVudCA9IChcbiAgICAgICAgPFJlYWN0LkZyYWdtZW50PlxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9TcGFjZUhpZXJhcmNoeV9yb29tVGlsZV9pdGVtXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9TcGFjZUhpZXJhcmNoeV9yb29tVGlsZV9hdmF0YXJcIj57YXZhdGFyfTwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfU3BhY2VIaWVyYXJjaHlfcm9vbVRpbGVfbmFtZVwiPlxuICAgICAgICAgICAgICAgICAgICB7bmFtZX1cbiAgICAgICAgICAgICAgICAgICAge2pvaW5lZFNlY3Rpb259XG4gICAgICAgICAgICAgICAgICAgIHtzdWdnZXN0ZWRTZWN0aW9ufVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfU3BhY2VIaWVyYXJjaHlfcm9vbVRpbGVfaW5mb1wiPlxuICAgICAgICAgICAgICAgICAgICB7ZGVzY3JpcHRpb259XG4gICAgICAgICAgICAgICAgICAgIHt0b3BpY1NlY3Rpb259XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfU3BhY2VIaWVyYXJjaHlfYWN0aW9uc1wiPlxuICAgICAgICAgICAgICAgIHtidXR0b259XG4gICAgICAgICAgICAgICAge2NoZWNrYm94fVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvUmVhY3QuRnJhZ21lbnQ+XG4gICAgKTtcblxuICA