Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dash: adapt to richer child computer status #442

Merged
merged 1 commit into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dash/app/cypress/e2e/computers.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe(`computers`, () => {
modelFamily: `macBookPro`,
modelIdentifier: `Mac14,10`,
appVersion: `2.0.12`,
users: [{ name: `Little Jimmy`, id: `user-1`, isOnline: true }],
users: [{ name: `Little Jimmy`, id: `user-1`, status: { case: `filterOn` } }],
serialNumber: `C02Z12345678`,
releaseChannel: `stable`,
};
Expand Down
20 changes: 17 additions & 3 deletions dash/app/cypress/e2e/onboarding.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe(`dashboard onboarding nudges`, () => {
subscriptionStatus: { case: `paid` },
notifications: [],
verifiedNotificationMethods: [],
hasAdminChild: false,
});
cy.interceptPql(`CreatePendingAppConnection`, { code: 123456 });
cy.interceptPql(`GetUser`, leopold);
Expand Down Expand Up @@ -55,8 +56,14 @@ describe(`dashboard onboarding nudges`, () => {

it(`connect device from dashboard nudge`, () => {
cy.interceptPql(`GetDashboardWidgets`, {
// we have a child, but no devices
users: [{ name: leopold.name, id: leopold.id, isOnline: true, numDevices: 0 }],
users: [
{
name: leopold.name,
id: leopold.id,
status: { case: `filterOn` },
numDevices: 0, // <- child, but no devices
},
],
unlockRequests: [],
userActivitySummaries: [],
recentScreenshots: [],
Expand All @@ -71,7 +78,14 @@ describe(`dashboard onboarding nudges`, () => {

it(`recommends that you add a notification if there aren't any`, () => {
cy.interceptPql(`GetDashboardWidgets`, {
users: [{ name: leopold.name, id: leopold.id, isOnline: true, numDevices: 1 }],
users: [
{
name: leopold.name,
id: leopold.id,
status: { case: `filterOn` },
numDevices: 1,
},
],
unlockRequests: [],
userActivitySummaries: [],
recentScreenshots: [],
Expand Down
1 change: 1 addition & 0 deletions dash/app/cypress/e2e/signup.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ describe(`payment`, () => {
subscriptionStatus: { case: `paid` },
notifications: [],
verifiedNotificationMethods: [],
hasAdminChild: false,
});

cy.interceptPql(`StripeUrl`, { url: `/stripe-url` });
Expand Down
2 changes: 1 addition & 1 deletion dash/app/src/components/routes/Users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ export function deviceProps(
modelTitle: apiDevice.modelTitle,
modelIdentifier: apiDevice.modelIdentifier,
name: apiDevice.customName,
status: apiDevice.isOnline ? `online` : `offline`,
status: apiDevice.status,
};
}
4 changes: 2 additions & 2 deletions dash/app/src/reducers/__tests__/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export function user(override: Partial<User> = {}): User {
modelFamily: `macBookAir`,
modelTitle: `MacBook Air`,
modelIdentifier: `MacBookAir8,1`,
isOnline: true,
status: { case: `filterOn` },
},
],
createdAt: new Date().toISOString(),
Expand All @@ -101,7 +101,7 @@ export function userDevice(override: Partial<Device> = {}): Device {
{
name: `Little Jimmy`,
id: uuid(),
isOnline: true,
status: { case: `filterOn` },
},
],
modelIdentifier: `MacBookAir8,1`,
Expand Down
47 changes: 25 additions & 22 deletions dash/components/src/Computers/EditComputer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import cx from 'classnames';
import { Button, SelectMenu, TextInput } from '@shared/components';
import { Link } from 'react-router-dom';
import Badge from '@shared/components/src/Badge';
import type { ReleaseChannel } from '@dash/types';
import type { ChildComputerStatus, ReleaseChannel } from '@dash/types';
import PageHeading from '../PageHeading';

interface Props {
Expand All @@ -19,7 +19,7 @@ interface Props {
users: Array<{
name: string;
id: string;
isOnline: boolean;
status: ChildComputerStatus;
}>;
saveButtonDisabled: boolean;
onSave(): unknown;
Expand Down Expand Up @@ -146,25 +146,28 @@ export default EditComputer;
interface ComputerUserProps {
name: string;
id: string;
isOnline: boolean;
status: ChildComputerStatus;
}

const ComputerUser: React.FC<ComputerUserProps> = ({ name, id, isOnline }) => (
<Link
to={`/children/${id}`}
className="flex justify-between items-center odd:bg-slate-50 hover:bg-slate-100 transition-[background-color] duration-100 px-4 py-3 rounded-xl"
>
<h4 className="text-slate-700 font-semibold sm:text-lg">{name}</h4>
<div className="flex items-center gap-2">
<span className={cx(`text-sm`, isOnline ? `text-slate-600` : `text-slate-400`)}>
{isOnline ? `online` : `offline`}
</span>
<div
className={cx(
`w-3 h-3 rounded-full`,
isOnline ? `bg-green-400` : ` shadow-inner bg-slate-100`,
)}
/>
</div>
</Link>
);
const ComputerUser: React.FC<ComputerUserProps> = ({ name, id, status }) => {
const isOnline = status.case !== `offline`;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're getting much richer detail from the API now, but to leverage it well will take some UI design work, to show stuff like "Suspended, resuming in 30 minutes" in the various places where this data is surfaced. So, for now, what I've done is basically downcast the data back to a boolean of "offline/online" like we used to get. This preserves the current behavior, and allows us to release the Macapp Version 2.7.0 which will start sending the richer data, and then we can as soon as we're ready start surfacing it to the parents in the dashboard. Basically, whenever you're ready to do a little design/component work on it.

return (
<Link
to={`/children/${id}`}
className="flex justify-between items-center odd:bg-slate-50 hover:bg-slate-100 transition-[background-color] duration-100 px-4 py-3 rounded-xl"
>
<h4 className="text-slate-700 font-semibold sm:text-lg">{name}</h4>
<div className="flex items-center gap-2">
<span className={cx(`text-sm`, isOnline ? `text-slate-600` : `text-slate-400`)}>
{isOnline ? `online` : `offline`}
</span>
<div
className={cx(
`w-3 h-3 rounded-full`,
isOnline ? `bg-green-400` : ` shadow-inner bg-slate-100`,
)}
/>
</div>
</Link>
);
};
2 changes: 1 addition & 1 deletion dash/components/src/Computers/ListComputers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ListComputers: React.FC<Props> = ({ devices }) => (
)}
<div className="mt-8 grid grid-cols-1 lg+:grid-cols-2 2xl:grid-cols-3 gap-8">
{devices.map((device) => {
const onlineUser = device.users.find((user) => user.isOnline);
const onlineUser = device.users.find((user) => user.status.case !== `offline`);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another case where i simplify the new state back into the old boolean for now

return (
<ComputerCard
key={device.id}
Expand Down
4 changes: 2 additions & 2 deletions dash/components/src/Dashboard/UsersOverviewWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ const UsersOverview: React.FC<Props> = ({ className, users }) => {

export default UsersOverview;

const UserOverview: React.FC<User> = ({ isOnline, name }) => (
const UserOverview: React.FC<User> = ({ status, name }) => (
<div className="flex justify-between items-center rounded-xl py-4 px-4 even:bg-slate-50/50">
<h3 className="font-medium text-slate-900">{name}</h3>
{isOnline ? (
{status.case !== `offline` ? (
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another spot

<Badge size="large" className="!px-4" type="green">
<i className="mr-2 fa-solid fa-circle text-green-400 text-sm scale-50" />
online
Expand Down
5 changes: 3 additions & 2 deletions dash/components/src/Users/UserDevice.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react';
import cx from 'classnames';
import { Link } from 'react-router-dom';
import type { ChildComputerStatus } from '@dash/types';

type Props = {
id: UUID;
deviceId: UUID;
modelTitle: string;
modelIdentifier: string;
name?: string;
status: 'online' | 'offline';
status: ChildComputerStatus;
className?: string;
};

Expand Down Expand Up @@ -42,7 +43,7 @@ const UserDevice: React.FC<Props> = ({
{name && <h4 className="text-sm text-slate-500 line-clamp-1">{modelTitle}</h4>}
</div>
</div>
{status === `online` && (
{status.case !== `offline` && (
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the final spot

<>
<div className="flex items-center gap-2 mr-2">
<span className={`text-sm text-slate-500 hidden xs:block`}>online</span>
Expand Down
3 changes: 2 additions & 1 deletion dash/types/src/pairql/pairs/GetDashboardWidgets.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// auto-generated, do not edit
import type { ChildComputerStatus } from '../shared';

export namespace GetDashboardWidgets {
export type Input = void;
Expand All @@ -7,7 +8,7 @@ export namespace GetDashboardWidgets {
users: Array<{
id: UUID;
name: string;
isOnline: boolean;
status: ChildComputerStatus;
numDevices: number;
}>;
userActivitySummaries: Array<{
Expand Down
12 changes: 10 additions & 2 deletions dash/types/src/pairql/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,21 @@ export interface BlockedApp {
schedule?: RuleSchedule;
}

export type ChildComputerStatus =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the new enum that the API sends back. in a few months, when we push everyone past 2.7.0, the dates will no longer be optional. but for now we'll have to support both types of data, since < 2.7.0 macapps don't send the richer detaill.

| { case: 'filterSuspended'; resuming?: ISODateString }
| { case: 'downtime'; ending?: ISODateString }
| { case: 'downtimePaused'; resuming?: ISODateString }
| { case: 'offline' }
| { case: 'filterOff' }
| { case: 'filterOn' };

export type ClientAuth = 'none' | 'user' | 'admin' | 'superAdmin';

export interface Device {
id: UUID;
name?: string;
releaseChannel: ReleaseChannel;
users: Array<{ id: UUID; name: string; isOnline: boolean }>;
users: Array<{ id: UUID; name: string; status: ChildComputerStatus }>;
appVersion: string;
serialNumber: string;
modelIdentifier: string;
Expand Down Expand Up @@ -207,7 +215,7 @@ export type UserActivityItem =
export interface UserDevice {
id: UUID;
deviceId: UUID;
isOnline: boolean;
status: ChildComputerStatus;
modelFamily: DeviceModelFamily;
modelTitle: string;
modelIdentifier: string;
Expand Down
4 changes: 2 additions & 2 deletions storybook/stories/dash/Computers/EditComputer.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ export const Default: Story = props({
{
name: `Sally`,
id: `456`,
isOnline: false,
status: { case: `offline` },
},
{
name: `Little Jimmy`,
id: `123`,
isOnline: true,
status: { case: `filterOn` },
},
],
saveButtonDisabled: false,
Expand Down
10 changes: 5 additions & 5 deletions storybook/stories/dash/Computers/ListComputers.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const WithOne: Story = props({
name: `Silvery`,
modelIdentifier: `Mac14,10`,
modelTitle: `16" MacBook Pro (2023)`,
users: [{ name: `John Doe`, isOnline: true, id: `123` }],
users: [{ name: `John Doe`, status: { case: `filterOn` }, id: `123` }],
},
],
});
Expand All @@ -36,27 +36,27 @@ export const WithMany: Story = props({
name: `Silvery`,
modelIdentifier: `Mac14,10`,
modelTitle: `16" MacBook Pro (2023)`,
users: [{ name: `John Doe`, isOnline: true, id: `123` }],
users: [{ name: `John Doe`, status: { case: `filterOn` }, id: `123` }],
},
{
id: `device-2`,
name: `Blacky`,
modelIdentifier: `MacPro6,1`,
modelTitle: `Mac Pro (2013)`,
users: [{ name: `John Doe`, isOnline: true, id: `123` }],
users: [{ name: `John Doe`, status: { case: `filterOn` }, id: `123` }],
},
{
id: `device-3`,
modelIdentifier: `Mac14,15`,
modelTitle: `15" MacBook Air (2023)`,
users: [{ name: `John Doe`, isOnline: true, id: `123` }],
users: [{ name: `John Doe`, status: { case: `filterOn` }, id: `123` }],
},
{
id: `device-4`,
name: `Spacey`,
modelIdentifier: `Mac14,13`,
modelTitle: `Mac Studio (2023)`,
users: [{ name: `John Doe`, isOnline: true, id: `123` }],
users: [{ name: `John Doe`, status: { case: `filterOn` }, id: `123` }],
},
],
});
Expand Down
8 changes: 4 additions & 4 deletions storybook/stories/dash/Dashboard/Dashboard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ export const Default: Story = props({
},
]),
users: withIds([
{ name: `Little Jimmy`, isOnline: true, numDevices: 1 },
{ name: `Sally`, isOnline: true, numDevices: 2 },
{ name: `Henry`, isOnline: false, numDevices: 0 },
{ name: `Little Jimmy`, status: { case: `filterOn` }, numDevices: 1 },
{ name: `Sally`, status: { case: `filterOn` }, numDevices: 2 },
{ name: `Henry`, status: { case: `offline` }, numDevices: 0 },
]),
userActivitySummaries: withIdsAnd({ numReviewed: 0 }, [
{ name: `Little Jimmy`, numUnreviewed: 245 },
Expand Down Expand Up @@ -98,7 +98,7 @@ export const NoUsers: Story = props({
// @screenshot: xs,lg
export const NoDevices: Story = props({
...Default.args,
users: withIds([{ name: `Little Jimmy`, isOnline: true, numDevices: 0 }]),
users: withIds([{ name: `Little Jimmy`, status: { case: `filterOn` }, numDevices: 0 }]),
});

// @screenshot: xs,lg
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ type Story = StoryObj<typeof meta>;

export const Default: Story = props({
users: withIds([
{ name: `Little Jimmy`, isOnline: true, numDevices: 1 },
{ name: `Sally`, isOnline: true, numDevices: 2 },
{ name: `Henry`, isOnline: false, numDevices: 0 },
{ name: `Little Jimmy`, status: { case: `filterOn` }, numDevices: 1 },
{ name: `Sally`, status: { case: `filterOn` }, numDevices: 2 },
{ name: `Henry`, status: { case: `offline` }, numDevices: 0 },
]),
});

Expand Down
4 changes: 2 additions & 2 deletions storybook/stories/dash/Users/EditUser.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ export const Default: Story = props({
name: `Silvery`,
modelIdentifier: `Mac14,10`,
modelTitle: `16" MacBook Pro (2023)`,
status: `online`,
status: { case: `filterOn` },
},
{
id: `2`,
deviceId: `2`,
modelIdentifier: `Mac14,14`,
modelTitle: `Mac Studio (2023)`,
status: `offline`,
status: { case: `offline` },
},
],
requestPublicKeychainRequest: { state: `idle` },
Expand Down
6 changes: 3 additions & 3 deletions storybook/stories/dash/Users/ListUsers.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const Default: Story = props({
name: `Silvery`,
modelIdentifier: `Mac14,10`,
modelTitle: `16" MacBook Pro (2023)`,
status: `online`,
status: { case: `filterOn` },
},
],
},
Expand All @@ -64,14 +64,14 @@ export const Default: Story = props({
modelIdentifier: `Mac14,13`,
name: `Lil' Studio`,
modelTitle: `Mac Studio (2023)`,
status: `offline`,
status: { case: `offline` },
},
{
id: `3`,
deviceId: `3`,
modelIdentifier: `iMac21,2`,
modelTitle: `27" iMac (2021)`,
status: `online`,
status: { case: `filterOn` },
},
],
},
Expand Down
Loading