mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-20 10:33:41 -05:00
web/rightpanel: add button to track user devices
This commit is contained in:
parent
0fb9805c85
commit
6f3619f632
8 changed files with 47 additions and 2 deletions
|
@ -90,6 +90,14 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any
|
||||||
return unmarshalAndCall(req.Data, func(params *getProfileParams) ([]id.RoomID, error) {
|
return unmarshalAndCall(req.Data, func(params *getProfileParams) ([]id.RoomID, error) {
|
||||||
return h.GetMutualRooms(ctx, params.UserID)
|
return h.GetMutualRooms(ctx, params.UserID)
|
||||||
})
|
})
|
||||||
|
case "track_user_devices":
|
||||||
|
return unmarshalAndCall(req.Data, func(params *getProfileParams) (*ProfileEncryptionInfo, error) {
|
||||||
|
err := h.TrackUserDevices(ctx, params.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return h.GetProfileEncryptionInfo(ctx, params.UserID)
|
||||||
|
})
|
||||||
case "get_profile_encryption_info":
|
case "get_profile_encryption_info":
|
||||||
return unmarshalAndCall(req.Data, func(params *getProfileParams) (*ProfileEncryptionInfo, error) {
|
return unmarshalAndCall(req.Data, func(params *getProfileParams) (*ProfileEncryptionInfo, error) {
|
||||||
return h.GetProfileEncryptionInfo(ctx, params.UserID)
|
return h.GetProfileEncryptionInfo(ctx, params.UserID)
|
||||||
|
|
|
@ -91,3 +91,8 @@ func (h *HiClient) GetProfileEncryptionInfo(ctx context.Context, userID id.UserI
|
||||||
}
|
}
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HiClient) TrackUserDevices(ctx context.Context, userID id.UserID) error {
|
||||||
|
_, err := h.Crypto.FetchKeys(ctx, []id.UserID{userID}, true)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -186,6 +186,10 @@ export default abstract class RPCClient {
|
||||||
return this.request("get_profile_encryption_info", { user_id })
|
return this.request("get_profile_encryption_info", { user_id })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackUserDevices(user_id: UserID): Promise<ProfileEncryptionInfo> {
|
||||||
|
return this.request("track_user_devices", { user_id })
|
||||||
|
}
|
||||||
|
|
||||||
ensureGroupSessionShared(room_id: RoomID): Promise<boolean> {
|
ensureGroupSessionShared(room_id: RoomID): Promise<boolean> {
|
||||||
return this.request("ensure_group_session_shared", { room_id })
|
return this.request("ensure_group_session_shared", { room_id })
|
||||||
}
|
}
|
||||||
|
|
1
web/src/icons/devices-off.svg
Normal file
1
web/src/icons/devices-off.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m354-720-80-80h566v80H354Zm526 520-80-80v-280H640v126l-80-80v-86q0-17 11.5-28.5T600-640h240q17 0 28.5 11.5T880-600v400ZM792-56 688-160h-88q-17 0-28.5-11.5T560-200v-88L240-608v328h240v120H80v-120h80v-408L56-792l56-56 736 736-56 56Zm-72-301Z"/></svg>
|
After Width: | Height: | Size: 365 B |
1
web/src/icons/devices.svg
Normal file
1
web/src/icons/devices.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M80-160v-120h80v-440q0-33 23.5-56.5T240-800h600v80H240v440h240v120H80Zm520 0q-17 0-28.5-11.5T560-200v-400q0-17 11.5-28.5T600-640h240q17 0 28.5 11.5T880-600v400q0 17-11.5 28.5T840-160H600Zm40-120h160v-280H640v280Zm0 0h160-160Z"/></svg>
|
After Width: | Height: | Size: 351 B |
|
@ -135,6 +135,13 @@ div.right-panel-content.user {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.action {
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
width: 100%;
|
||||||
|
gap: .25rem;
|
||||||
|
justify-content: left;
|
||||||
|
}
|
||||||
|
|
||||||
div.devices > details > ul {
|
div.devices > details > ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -73,7 +73,10 @@ const UserInfo = ({ userID }: UserInfoProps) => {
|
||||||
</>}
|
</>}
|
||||||
<DeviceList client={client} room={roomCtx?.store} userID={userID}/>
|
<DeviceList client={client} room={roomCtx?.store} userID={userID}/>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
{errors?.length ? <>
|
||||||
<UserInfoError errors={errors}/>
|
<UserInfoError errors={errors}/>
|
||||||
|
<hr/>
|
||||||
|
</> : null}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
import { useEffect, useState } from "react"
|
import { useCallback, useEffect, useState, useTransition } from "react"
|
||||||
import { ScaleLoader } from "react-spinners"
|
import { ScaleLoader } from "react-spinners"
|
||||||
import Client from "@/api/client.ts"
|
import Client from "@/api/client.ts"
|
||||||
import { RoomStateStore } from "@/api/statestore"
|
import { RoomStateStore } from "@/api/statestore"
|
||||||
import { ProfileDevice, ProfileEncryptionInfo, TrustState, UserID } from "@/api/types"
|
import { ProfileDevice, ProfileEncryptionInfo, TrustState, UserID } from "@/api/types"
|
||||||
import UserInfoError from "./UserInfoError.tsx"
|
import UserInfoError from "./UserInfoError.tsx"
|
||||||
|
import DevicesIcon from "@/icons/devices.svg?react"
|
||||||
import EncryptedOffIcon from "@/icons/encrypted-off.svg?react"
|
import EncryptedOffIcon from "@/icons/encrypted-off.svg?react"
|
||||||
import EncryptedQuestionIcon from "@/icons/encrypted-question.svg?react"
|
import EncryptedQuestionIcon from "@/icons/encrypted-question.svg?react"
|
||||||
import EncryptedIcon from "@/icons/encrypted.svg?react"
|
import EncryptedIcon from "@/icons/encrypted.svg?react"
|
||||||
|
@ -32,6 +33,18 @@ interface DeviceListProps {
|
||||||
const DeviceList = ({ client, room, userID }: DeviceListProps) => {
|
const DeviceList = ({ client, room, userID }: DeviceListProps) => {
|
||||||
const [view, setEncryptionInfo] = useState<ProfileEncryptionInfo | null>(null)
|
const [view, setEncryptionInfo] = useState<ProfileEncryptionInfo | null>(null)
|
||||||
const [errors, setErrors] = useState<string[] | null>(null)
|
const [errors, setErrors] = useState<string[] | null>(null)
|
||||||
|
const [trackChangePending, startTransition] = useTransition()
|
||||||
|
const doTrackDeviceList = useCallback(() => {
|
||||||
|
startTransition(async () => {
|
||||||
|
try {
|
||||||
|
const resp = await client.rpc.trackUserDevices(userID)
|
||||||
|
setEncryptionInfo(resp)
|
||||||
|
setErrors(resp.errors)
|
||||||
|
} catch (err) {
|
||||||
|
setErrors([`${err}`])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [client, userID])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEncryptionInfo(null)
|
setEncryptionInfo(null)
|
||||||
setErrors(null)
|
setErrors(null)
|
||||||
|
@ -60,6 +73,9 @@ const DeviceList = ({ client, room, userID }: DeviceListProps) => {
|
||||||
<h4>Security</h4>
|
<h4>Security</h4>
|
||||||
<p>{encryptionMessage}</p>
|
<p>{encryptionMessage}</p>
|
||||||
<p>This user's device list is not being tracked.</p>
|
<p>This user's device list is not being tracked.</p>
|
||||||
|
<button className="action" onClick={doTrackDeviceList} disabled={trackChangePending}>
|
||||||
|
<DevicesIcon /> Start tracking device list
|
||||||
|
</button>
|
||||||
<UserInfoError errors={errors}/>
|
<UserInfoError errors={errors}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue