Skip to content

Commit

Permalink
dash: wired up public keychain requests
Browse files Browse the repository at this point in the history
  • Loading branch information
kiahjh committed Jan 2, 2025
1 parent 8878775 commit 160750a
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 39 deletions.
5 changes: 5 additions & 0 deletions dash/app/cypress/support/intercept.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export function interceptPql(
slug: `RequestMagicLink`,
output: T.RequestMagicLink.Output,
): void;
export function interceptPql(
slug: `RequestPublicKeychain`,
output: T.RequestPublicKeychain.Output,
): void;
export function interceptPql(slug: `ResetPassword`, output: T.ResetPassword.Output): void;
export function interceptPql(
slug: `SaveConferenceEmail`,
Expand Down Expand Up @@ -170,6 +174,7 @@ export function forcePqlErr(
| 'Login'
| 'LoginMagicLink'
| 'RequestMagicLink'
| 'RequestPublicKeychain'
| 'ResetPassword'
| 'SaveConferenceEmail'
| 'SaveDevice'
Expand Down
12 changes: 12 additions & 0 deletions dash/app/src/components/routes/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Loading, ApiErrorMessage } from '@dash/components';
import React, { useEffect, useMemo, useReducer } from 'react';
import { EditUser } from '@dash/components';
import { defaults, type User } from '@dash/types';
import type { RequestPublicKeychain } from '@dash/types';
import * as empty from '../../lib/empty';
import { isDirty } from '../../lib/helpers';
import Current from '../../environment';
Expand Down Expand Up @@ -57,6 +58,13 @@ const UserRoute: React.FC = () => {
},
);

const requestPublicKeychain = useMutation((input: RequestPublicKeychain.Input) =>
Current.api.requestPublicKeychain({
searchQuery: input.searchQuery,
description: input.description,
}),
);

const newUserId = useMemo(() => uuid(), []);
useEffect(() => {
id === `new` && dispatch({ type: `setUser`, user: empty.user(newUserId), new: true });
Expand Down Expand Up @@ -158,6 +166,10 @@ const UserRoute: React.FC = () => {
setBlockedAppSchedule={(id, schedule) =>
dispatch({ type: `setBlockedAppSchedule`, id, schedule })
}
onRequestPublicKeychain={(searchQuery: string, description: string) =>
requestPublicKeychain.mutate({ searchQuery, description })
}
requestPublicKeychainRequest={ReqState.fromMutation(requestPublicKeychain)}
/>
);
};
Expand Down
13 changes: 13 additions & 0 deletions dash/app/src/pairql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,16 @@ export const liveClient = {
);
},

requestPublicKeychain(
input: T.RequestPublicKeychain.Input,
): Promise<T.Result<T.RequestPublicKeychain.Output>> {
return query<T.RequestPublicKeychain.Input, T.RequestPublicKeychain.Output>(
input,
`admin`,
`RequestPublicKeychain`,
);
},

resetPassword(input: T.ResetPassword.Input): Promise<T.Result<T.ResetPassword.Output>> {
return query<T.ResetPassword.Input, T.ResetPassword.Output>(
input,
Expand Down Expand Up @@ -452,6 +462,9 @@ export const throwingClient: ApiClient = {
requestMagicLink: () => {
throw new Error(`ApiClient.requestMagicLink() not implemented`);
},
requestPublicKeychain: () => {
throw new Error(`ApiClient.requestPublicKeychain() not implemented`);
},
resetPassword: () => {
throw new Error(`ApiClient.resetPassword() not implemented`);
},
Expand Down
3 changes: 3 additions & 0 deletions dash/app/src/pairql/noopClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ const noopClient: ApiClient = {
verifySignupEmail: async () => {
return Result.success({ token: ``, adminId: `` });
},
requestPublicKeychain: async () => {
return Result.success({ success: true });
},
};

export default noopClient;
106 changes: 73 additions & 33 deletions dash/components/src/Users/AddKeychainDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { Badge, Button, Loading, TextInput } from '@shared/components';
import { inflect } from '@shared/string';
import { defaults, type KeychainSummary as Keychain } from '@dash/types';
import type { RuleSchedule as Schedule, RequestState } from '@dash/types';
import type { RuleSchedule as Schedule, RequestState, SuccessOutput } from '@dash/types';
import SchedulePicker from '../Keychains/schedule/SchedulePicker';

interface Props {
Expand All @@ -28,6 +28,8 @@ interface Props {
onConfirm(): unknown;
existingKeychains: Keychain[];
userName: string;
onRequestPublicKeychain(searchQuery: string, description: string): unknown;
requestPublicKeychainRequest: RequestState<SuccessOutput>;
}

const AddKeychainDrawer: React.FC<Props> = ({
Expand All @@ -40,6 +42,8 @@ const AddKeychainDrawer: React.FC<Props> = ({
userName,
schedule,
setSchedule,
onRequestPublicKeychain,
requestPublicKeychainRequest,
}) => {
const shown = request && request.state !== `idle`;
const [whichKeychains, setWhichKeychains] = useState<'own' | 'public'>(`own`);
Expand Down Expand Up @@ -104,38 +108,74 @@ const AddKeychainDrawer: React.FC<Props> = ({
case request?.state === `succeeded` &&
searchQuery.length > 0 &&
whichKeychains === `public`:
return (
<div className="flex flex-col justify-end lg:justify-center lg:mt-4 xs:items-center h-full max-w-md mx-auto w-full">
<h2 className="text-xl font-semibold hidden sm:block">
Want to request a public keychain?
</h2>
<h3 className="text-slate-500 text-center mt-2 text-sm hidden sm:block">
It looks like we don't have a public keychain for{` `}
<b className="font-semibold text-slate-700">{searchQuery}</b>, but you can
request for it to be added.
</h3>
<h2 className="font-semibold sm:hidden text-center">
Looks like that keychain doesn't exist
</h2>
<TextInput
type="textarea"
value={pubKeychainRequest}
setValue={setPubKeychainRequest}
placeholder="Describe what you're looking for..."
rows={2}
className="my-2 xs:my-4"
/>
<Button
type="button"
onClick={() => alert(`todo`)}
color="secondary"
size="small"
>
<i className="fa-solid fa-paper-plane mr-2" />
Request keychain
</Button>
</div>
);
if (
requestPublicKeychainRequest.state === `idle` ||
requestPublicKeychainRequest.state === `ongoing`
) {
return (
<div className="flex flex-col justify-end lg:justify-center lg:mt-4 xs:items-center h-full max-w-md mx-auto w-full">
<h2 className="text-xl font-semibold hidden sm:block">
Want to request a public keychain?
</h2>
<h3 className="text-slate-500 text-center mt-2 text-sm hidden sm:block">
It looks like we don't have a public keychain for{` `}
<b className="font-semibold text-slate-700">{searchQuery}</b>, but you can
request for it to be added.
</h3>
<h2 className="font-semibold sm:hidden text-center">
Looks like that keychain doesn't exist
</h2>
<TextInput
type="textarea"
value={pubKeychainRequest}
setValue={setPubKeychainRequest}
placeholder="Describe what you're looking for..."
rows={2}
className="my-2 xs:my-4"
noResize
disabled={requestPublicKeychainRequest.state === `ongoing`}
/>
<div className="h-10 w-full flex justify-center">
{requestPublicKeychainRequest.state === `ongoing` ? (
<i className="fa-solid fa-spinner animate-spin text-2xl text-slate-500" />
) : (
<Button
type="button"
onClick={() =>
onRequestPublicKeychain(searchQuery, pubKeychainRequest)
}
color="secondary"
size="small"
disabled={!pubKeychainRequest}
className="w-full"
>
<i className="fa-solid fa-paper-plane mr-2" />
Request keychain
</Button>
)}
</div>
</div>
);
} else if (requestPublicKeychainRequest.state === `succeeded`) {
return (
<div className="w-full h-full flex justify-center items-center">
<div className="bg-green-100 text-green-700 p-6 rounded-2xl text-lg font-medium">
We received your request!
</div>
</div>
);
} else {
return (
<div className="w-full h-full flex justify-center items-center">
<div className="bg-red-100 p-6 rounded-2xl font-medium flex flex-col items-center">
<h2 className="text-lg text-red-700">Hmm, something went wrong</h2>
<p className="text-center text-red-700/70">
Try refreshing the page and trying again.
</p>
</div>
</div>
);
}
case request?.state === `succeeded` &&
whichKeychains === `own` &&
keychainsToDisplay.length === 0:
Expand Down
7 changes: 7 additions & 0 deletions dash/components/src/Users/EditUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
ConfirmableEntityAction,
RequestState,
BlockedApp,
SuccessOutput,
} from '@dash/types';
import type { UserKeychainSummary as Keychain } from '@dash/types';
import KeychainCard from '../Keychains/KeychainCard';
Expand Down Expand Up @@ -68,6 +69,8 @@ interface Props {
addNewBlockedApp(): unknown;
removeBlockedApp(id: UUID): unknown;
setBlockedAppSchedule(id: UUID, schedule?: RuleSchedule): unknown;
onRequestPublicKeychain(searchQuery: string, description: string): unknown;
requestPublicKeychainRequest: RequestState<SuccessOutput>;
}

const EditUser: React.FC<Props> = ({
Expand Down Expand Up @@ -114,6 +117,8 @@ const EditUser: React.FC<Props> = ({
addNewBlockedApp,
removeBlockedApp,
setBlockedAppSchedule,
onRequestPublicKeychain,
requestPublicKeychainRequest,
}) => {
if (isNew) {
return (
Expand Down Expand Up @@ -169,6 +174,8 @@ const EditUser: React.FC<Props> = ({
userName={name}
schedule={keychainSchedule}
setSchedule={setAddingKeychainSchedule}
onRequestPublicKeychain={onRequestPublicKeychain}
requestPublicKeychainRequest={requestPublicKeychainRequest}
/>
<ConfirmDeleteEntity
type="connection to computer"
Expand Down
1 change: 1 addition & 0 deletions dash/types/src/pairql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export * from './pairs/LogEvent';
export * from './pairs/Login';
export * from './pairs/LoginMagicLink';
export * from './pairs/RequestMagicLink';
export * from './pairs/RequestPublicKeychain';
export * from './pairs/ResetPassword';
export * from './pairs/SaveConferenceEmail';
export * from './pairs/SaveDevice';
Expand Down
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/GetAdmin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// auto-generated, do not edit
import type {
AdminNotification,
AdminSubscriptionStatus,
VerifiedNotificationMethod,
AdminNotification,
} from '../shared';

export namespace GetAdmin {
Expand Down
11 changes: 11 additions & 0 deletions dash/types/src/pairql/pairs/RequestPublicKeychain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// auto-generated, do not edit
import type { SuccessOutput } from '../shared';

export namespace RequestPublicKeychain {
export interface Input {
searchQuery: string;
description: string;
}

export type Output = SuccessOutput;
}
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/SaveDevice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// auto-generated, do not edit
import type { SuccessOutput, ReleaseChannel } from '../shared';
import type { ReleaseChannel, SuccessOutput } from '../shared';

export namespace SaveDevice {
export interface Input {
Expand Down
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/SaveKey.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// auto-generated, do not edit
import type { SharedKey, SuccessOutput } from '../shared';
import type { SuccessOutput, SharedKey } from '../shared';

export namespace SaveKey {
export interface Input {
Expand Down
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/SaveNotification.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// auto-generated, do not edit
import type { AdminNotificationTrigger, SuccessOutput } from '../shared';
import type { SuccessOutput, AdminNotificationTrigger } from '../shared';

export namespace SaveNotification {
export interface Input {
Expand Down
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/SaveUser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// auto-generated, do not edit
import type { PlainTimeWindow, BlockedApp, SuccessOutput, RuleSchedule } from '../shared';
import type { SuccessOutput, PlainTimeWindow, RuleSchedule, BlockedApp } from '../shared';

export namespace SaveUser {
export interface Input {
Expand Down
2 changes: 1 addition & 1 deletion dash/types/src/pairql/pairs/SecurityEventsFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export namespace SecurityEventsFeed {
case: 'child';
id: UUID;
childId: UUID;
deviceId: UUID;
childName: string;
deviceId: UUID;
deviceName: string;
event: string;
detail?: string;
Expand Down
2 changes: 2 additions & 0 deletions storybook/stories/dash/Users/AddKeychainDrawer.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const Loading: Story = props({
onConfirm: () => {},
existingKeychains: [],
userName: `Little Jimmy`,
requestPublicKeychainRequest: { state: `idle` },
onRequestPublicKeychain: () => {},
});

export const Failed: Story = props({
Expand Down
2 changes: 2 additions & 0 deletions storybook/stories/dash/Users/EditUser.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ export const Default: Story = props({
status: `offline`,
},
],
requestPublicKeychainRequest: { state: `idle` },
onRequestPublicKeychain: () => {},
});

// @screenshot: xs,md
Expand Down

0 comments on commit 160750a

Please sign in to comment.