1
0
Fork 0
forked from Mirrors/gomuks

web/timeline: render policy list events (#586)

Co-authored-by: Tulir Asokan <tulir@maunium.net>
This commit is contained in:
nexy7574 2025-01-06 12:51:58 +00:00 committed by GitHub
parent 158745b7a0
commit bdc823742e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 77 additions and 0 deletions

View file

@ -111,6 +111,12 @@ export interface ACLEventContent {
deny?: string[] deny?: string[]
} }
export interface PolicyRuleContent {
entity: string
reason: string
recommendation: string
}
export interface PowerLevelEventContent { export interface PowerLevelEventContent {
users?: Record<UserID, number> users?: Record<UserID, number>
users_default?: number users_default?: number

View file

@ -217,6 +217,7 @@ class ContextFields implements MainScreenContextFields {
} }
clickRightPanelOpener = (evt: React.MouseEvent) => { clickRightPanelOpener = (evt: React.MouseEvent) => {
evt.preventDefault()
const type = evt.currentTarget.getAttribute("data-target-panel") const type = evt.currentTarget.getAttribute("data-target-panel")
if (type === "pinned-messages" || type === "members") { if (type === "pinned-messages" || type === "members") {
this.setRightPanel({ type }) this.setRightPanel({ type })

View file

@ -0,0 +1,61 @@
// gomuks - A Matrix client written in Go.
// Copyright (C) 2024 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import { JSX, use } from "react"
import { PolicyRuleContent } from "@/api/types"
import { getDisplayname } from "@/util/validation.ts"
import MainScreenContext from "../../MainScreenContext.ts"
import EventContentProps from "./props.ts"
const PolicyRuleBody = ({ event, sender }: EventContentProps) => {
const content = event.content as PolicyRuleContent
const prevContent = event.unsigned.prev_content as PolicyRuleContent | undefined
const mainScreen = use(MainScreenContext)
const entity = content.entity ?? prevContent?.entity
const recommendation = content.recommendation ?? prevContent?.recommendation
if (!entity || !recommendation) {
return <div className="policy-body">
{getDisplayname(event.sender, sender?.content)} sent an invalid policy rule
</div>
}
let entityElement = <>{entity}</>
if(event.type === "m.policy.rule.user" && !entity?.includes("*") && !entity?.includes("?")) {
entityElement = (
<a
className="hicli-matrix-uri hicli-matrix-uri-user"
href={`matrix:u/${entity.slice(1)}`}
onClick={mainScreen.clickRightPanelOpener}
data-target-panel="user"
data-target-user={entity}
>
{entity}
</a>
)
}
let recommendationElement: JSX.Element | string = <code>{recommendation}</code>
if (recommendation === "m.ban") {
recommendationElement = "ban"
}
const action = prevContent ? ((content.entity && content.recommendation) ? "updated" : "removed") : "added"
const target = event.type.replace(/^m\.policy\.rule\./, "")
return <div className="policy-body">
{getDisplayname(event.sender, sender?.content)} {action} a {recommendationElement} rule
for {target}s matching <code>{entityElement}</code>
{content.reason ? <> for <code>{content.reason}</code></> : null}
</div>
}
export default PolicyRuleBody

View file

@ -7,6 +7,7 @@ import LocationMessageBody from "./LocationMessageBody.tsx"
import MediaMessageBody from "./MediaMessageBody.tsx" import MediaMessageBody from "./MediaMessageBody.tsx"
import MemberBody from "./MemberBody.tsx" import MemberBody from "./MemberBody.tsx"
import PinnedEventsBody from "./PinnedEventsBody.tsx" import PinnedEventsBody from "./PinnedEventsBody.tsx"
import PolicyRuleBody from "./PolicyRuleBody.tsx"
import PowerLevelBody from "./PowerLevelBody.tsx" import PowerLevelBody from "./PowerLevelBody.tsx"
import RedactedBody from "./RedactedBody.tsx" import RedactedBody from "./RedactedBody.tsx"
import RoomAvatarBody from "./RoomAvatarBody.tsx" import RoomAvatarBody from "./RoomAvatarBody.tsx"
@ -24,6 +25,7 @@ export { default as MediaMessageBody } from "./MediaMessageBody.tsx"
export { default as LocationMessageBody } from "./LocationMessageBody.tsx" export { default as LocationMessageBody } from "./LocationMessageBody.tsx"
export { default as MemberBody } from "./MemberBody.tsx" export { default as MemberBody } from "./MemberBody.tsx"
export { default as PinnedEventsBody } from "./PinnedEventsBody.tsx" export { default as PinnedEventsBody } from "./PinnedEventsBody.tsx"
export { default as PolicyRuleBody } from "./PolicyRuleBody.tsx"
export { default as PowerLevelBody } from "./PowerLevelBody.tsx" export { default as PowerLevelBody } from "./PowerLevelBody.tsx"
export { default as RedactedBody } from "./RedactedBody.tsx" export { default as RedactedBody } from "./RedactedBody.tsx"
export { default as RoomAvatarBody } from "./RoomAvatarBody.tsx" export { default as RoomAvatarBody } from "./RoomAvatarBody.tsx"
@ -82,6 +84,12 @@ export function getBodyType(evt: MemDBEvent, forReply = false): React.FunctionCo
return RoomAvatarBody return RoomAvatarBody
case "m.room.server_acl": case "m.room.server_acl":
return ACLBody return ACLBody
case "m.policy.rule.user":
return PolicyRuleBody
case "m.policy.rule.room":
return PolicyRuleBody
case "m.policy.rule.server":
return PolicyRuleBody
case "m.room.pinned_events": case "m.room.pinned_events":
return PinnedEventsBody return PinnedEventsBody
case "m.room.power_levels": case "m.room.power_levels":
@ -97,6 +105,7 @@ export function isSmallEvent(bodyType: React.FunctionComponent<EventContentProps
case RoomNameBody: case RoomNameBody:
case RoomAvatarBody: case RoomAvatarBody:
case ACLBody: case ACLBody:
case PolicyRuleBody:
case PinnedEventsBody: case PinnedEventsBody:
case PowerLevelBody: case PowerLevelBody:
return true return true