mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-08 09:43:03 +02:00
Add dropdown to choose contact addition type. Closes #216.
This commit is contained in:
@@ -221,6 +221,9 @@ class CreateContactRequest(BaseModel):
|
|||||||
|
|
||||||
public_key: str = Field(min_length=64, max_length=64, description="Public key (64-char hex)")
|
public_key: str = Field(min_length=64, max_length=64, description="Public key (64-char hex)")
|
||||||
name: str | None = Field(default=None, description="Display name for the contact")
|
name: str | None = Field(default=None, description="Display name for the contact")
|
||||||
|
type: int = Field(
|
||||||
|
default=0, ge=0, le=3, description="Contact type (0=unknown, 1=client, 2=repeater, 3=room)"
|
||||||
|
)
|
||||||
try_historical: bool = Field(
|
try_historical: bool = Field(
|
||||||
default=False,
|
default=False,
|
||||||
description="Attempt to decrypt historical DM packets for this contact",
|
description="Attempt to decrypt historical DM packets for this contact",
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ async def create_contact(
|
|||||||
contact_upsert = ContactUpsert(
|
contact_upsert = ContactUpsert(
|
||||||
public_key=lower_key,
|
public_key=lower_key,
|
||||||
name=request.name,
|
name=request.name,
|
||||||
|
type=request.type,
|
||||||
on_radio=False,
|
on_radio=False,
|
||||||
)
|
)
|
||||||
await ContactRepository.upsert(contact_upsert)
|
await ContactRepository.upsert(contact_upsert)
|
||||||
|
|||||||
+2
-2
@@ -158,10 +158,10 @@ export const api = {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ public_keys: publicKeys }),
|
body: JSON.stringify({ public_keys: publicKeys }),
|
||||||
}),
|
}),
|
||||||
createContact: (publicKey: string, name?: string, tryHistorical?: boolean) =>
|
createContact: (publicKey: string, name?: string, tryHistorical?: boolean, type?: number) =>
|
||||||
fetchJson<Contact>('/contacts', {
|
fetchJson<Contact>('/contacts', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ public_key: publicKey, name, try_historical: tryHistorical }),
|
body: JSON.stringify({ public_key: publicKey, name, type, try_historical: tryHistorical }),
|
||||||
}),
|
}),
|
||||||
markContactRead: (publicKey: string) =>
|
markContactRead: (publicKey: string) =>
|
||||||
fetchJson<{ status: string; public_key: string }>(`/contacts/${publicKey}/mark-read`, {
|
fetchJson<{ status: string; public_key: string }>(`/contacts/${publicKey}/mark-read`, {
|
||||||
|
|||||||
@@ -32,7 +32,12 @@ interface NewMessageModalProps {
|
|||||||
nonce: number;
|
nonce: number;
|
||||||
} | null;
|
} | null;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCreateContact: (name: string, publicKey: string, tryHistorical: boolean) => Promise<void>;
|
onCreateContact: (
|
||||||
|
name: string,
|
||||||
|
publicKey: string,
|
||||||
|
tryHistorical: boolean,
|
||||||
|
type?: number
|
||||||
|
) => Promise<void>;
|
||||||
onCreateChannel: (name: string, key: string, tryHistorical: boolean) => Promise<void>;
|
onCreateChannel: (name: string, key: string, tryHistorical: boolean) => Promise<void>;
|
||||||
onCreateHashtagChannel: (name: string, tryHistorical: boolean) => Promise<void>;
|
onCreateHashtagChannel: (name: string, tryHistorical: boolean) => Promise<void>;
|
||||||
onBulkAddHashtagChannels: (channelNames: string[], tryHistorical: boolean) => Promise<void>;
|
onBulkAddHashtagChannels: (channelNames: string[], tryHistorical: boolean) => Promise<void>;
|
||||||
@@ -91,6 +96,7 @@ export function NewMessageModal({
|
|||||||
}: NewMessageModalProps) {
|
}: NewMessageModalProps) {
|
||||||
const [tab, setTab] = useState<Tab>('new-contact');
|
const [tab, setTab] = useState<Tab>('new-contact');
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
|
const [contactType, setContactType] = useState(1);
|
||||||
const [contactKey, setContactKey] = useState('');
|
const [contactKey, setContactKey] = useState('');
|
||||||
const [channelKey, setChannelKey] = useState('');
|
const [channelKey, setChannelKey] = useState('');
|
||||||
const [bulkChannelText, setBulkChannelText] = useState('');
|
const [bulkChannelText, setBulkChannelText] = useState('');
|
||||||
@@ -103,6 +109,7 @@ export function NewMessageModal({
|
|||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setName('');
|
setName('');
|
||||||
|
setContactType(1);
|
||||||
setContactKey('');
|
setContactKey('');
|
||||||
setChannelKey('');
|
setChannelKey('');
|
||||||
setBulkChannelText('');
|
setBulkChannelText('');
|
||||||
@@ -161,7 +168,7 @@ export function NewMessageModal({
|
|||||||
setError('Name and public key are required');
|
setError('Name and public key are required');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await onCreateContact(name.trim(), contactKey.trim(), tryHistorical);
|
await onCreateContact(name.trim(), contactKey.trim(), tryHistorical, contactType);
|
||||||
} else if (tab === 'new-channel') {
|
} else if (tab === 'new-channel') {
|
||||||
if (!name.trim() || !channelKey.trim()) {
|
if (!name.trim() || !channelKey.trim()) {
|
||||||
setError('Channel name and key are required');
|
setError('Channel name and key are required');
|
||||||
@@ -293,6 +300,19 @@ export function NewMessageModal({
|
|||||||
placeholder="64-character hex public key"
|
placeholder="64-character hex public key"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="contact-type">Type</Label>
|
||||||
|
<select
|
||||||
|
id="contact-type"
|
||||||
|
value={contactType}
|
||||||
|
onChange={(e) => setContactType(Number(e.target.value))}
|
||||||
|
className="block h-9 w-full rounded-md border border-input bg-background px-3 text-sm shadow-sm"
|
||||||
|
>
|
||||||
|
<option value={1}>Client</option>
|
||||||
|
<option value={2}>Repeater</option>
|
||||||
|
<option value={3}>Room Server</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="new-channel" className="mt-4 space-y-4">
|
<TabsContent value="new-channel" className="mt-4 space-y-4">
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ export function useContactsAndChannels({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleCreateContact = useCallback(
|
const handleCreateContact = useCallback(
|
||||||
async (name: string, publicKey: string, tryHistorical: boolean) => {
|
async (name: string, publicKey: string, tryHistorical: boolean, type?: number) => {
|
||||||
const created = await api.createContact(publicKey, name || undefined, tryHistorical);
|
const created = await api.createContact(publicKey, name || undefined, tryHistorical, type);
|
||||||
const data = await fetchAllContacts();
|
const data = await fetchAllContacts();
|
||||||
setContacts(data);
|
setContacts(data);
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ describe('NewMessageModal form reset', () => {
|
|||||||
await user.click(screen.getByRole('button', { name: 'Create' }));
|
await user.click(screen.getByRole('button', { name: 'Create' }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(onCreateContact).toHaveBeenCalledWith('Bob', 'bb'.repeat(32), false);
|
expect(onCreateContact).toHaveBeenCalledWith('Bob', 'bb'.repeat(32), false, 1);
|
||||||
});
|
});
|
||||||
expect(onClose).toHaveBeenCalled();
|
expect(onClose).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user