Skip to content

Commit ac6a3ab

Browse files
committed
Black triangle
1 parent 0740ab0 commit ac6a3ab

13 files changed

+49
-44
lines changed

site/src/api/api.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,9 @@ export const getEntitlements = async (): Promise<TypesGen.Entitlements> => {
384384
return response.data
385385
}
386386

387-
export const getDAUs = async (): Promise<TypesGen.DAUsResponse> => {
388-
const response = await axios.get("/api/v2/metrics/daus")
387+
export const getTemplateDAUs = async (
388+
templateId: string,
389+
): Promise<TypesGen.TemplateDAUsResponse> => {
390+
const response = await axios.get(`/api/v2/templates/${templateId}/daus`)
389391
return response.data
390392
}

site/src/api/typesGenerated.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,6 @@ export interface DAUEntry {
188188
readonly daus: number
189189
}
190190

191-
// From codersdk/metrics.go
192-
export interface DAUsResponse {
193-
readonly entries: DAUEntry[]
194-
}
195-
196191
// From codersdk/workspaceresources.go
197192
export interface DERPRegion {
198193
readonly preferred: boolean
@@ -380,6 +375,11 @@ export interface Template {
380375
readonly created_by_name: string
381376
}
382377

378+
// From codersdk/metrics.go
379+
export interface TemplateDAUsResponse {
380+
readonly entries: DAUEntry[]
381+
}
382+
383383
// From codersdk/templateversions.go
384384
export interface TemplateVersion {
385385
readonly id: string

site/src/pages/UsersPage/DAUCharts.test.tsx renamed to site/src/pages/TemplatePage/DAUCharts.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ describe("DAUChart", () => {
1212
it("renders a helpful paragraph on empty state", async () => {
1313
render(
1414
<DAUChart
15-
userMetricsData={{
15+
templateMetricsData={{
1616
entries: [],
1717
}}
1818
/>,
@@ -23,7 +23,7 @@ describe("DAUChart", () => {
2323
it("renders a graph", async () => {
2424
render(
2525
<DAUChart
26-
userMetricsData={{
26+
templateMetricsData={{
2727
entries: [{ date: "2020-01-01", daus: 1 }],
2828
}}
2929
/>,

site/src/pages/UsersPage/DAUCharts.tsx renamed to site/src/pages/TemplatePage/DAUCharts.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,29 @@ import * as TypesGen from "../../api/typesGenerated"
2424
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend)
2525

2626
export interface DAUChartProps {
27-
userMetricsData: TypesGen.DAUsResponse
27+
templateMetricsData: TypesGen.TemplateDAUsResponse
2828
}
2929
export const Language = {
3030
loadingText: "DAU stats are loading. Check back later.",
3131
chartTitle: "Daily Active Users",
3232
}
3333

34-
export const DAUChart: FC<DAUChartProps> = ({ userMetricsData }) => {
34+
export const DAUChart: FC<DAUChartProps> = ({ templateMetricsData }) => {
3535
const theme: Theme = useTheme()
3636

37-
if (userMetricsData.entries.length === 0) {
37+
if (templateMetricsData.entries.length === 0) {
3838
return (
3939
<div style={{ marginTop: "-20px" }}>
4040
<p>{Language.loadingText}</p>
4141
</div>
4242
)
4343
}
4444

45-
const labels = userMetricsData.entries.map((val) => {
45+
const labels = templateMetricsData.entries.map((val) => {
4646
return moment(val.date).format("l")
4747
})
4848

49-
const data = userMetricsData.entries.map((val) => {
49+
const data = templateMetricsData.entries.map((val) => {
5050
return val.daus
5151
})
5252

@@ -70,7 +70,7 @@ export const DAUChart: FC<DAUChartProps> = ({ userMetricsData }) => {
7070
ticks: {},
7171
},
7272
},
73-
aspectRatio: 6 / 1,
73+
aspectRatio: 10 / 1,
7474
} as ChartOptions
7575

7676
return (

site/src/pages/TemplatePage/TemplatePage.test.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import {
88
} from "../../testHelpers/renderHelpers"
99
import { TemplatePage } from "./TemplatePage"
1010

11+
Object.defineProperty(window, "ResizeObserver", {
12+
value: ResizeObserver,
13+
})
14+
1115
describe("TemplatePage", () => {
1216
it("shows the template name, readme and resources", async () => {
1317
// Mocking the dayjs module within the createDayString file

site/src/pages/TemplatePage/TemplatePage.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
2727
organizationId,
2828
},
2929
})
30+
3031
const { template, activeTemplateVersion, templateResources, templateVersions } =
3132
templateState.context
3233
const isLoading = !template || !activeTemplateVersion || !templateResources

site/src/pages/TemplatePage/TemplatePageView.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import Link from "@material-ui/core/Link"
44
import { makeStyles } from "@material-ui/core/styles"
55
import AddCircleOutline from "@material-ui/icons/AddCircleOutline"
66
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
7+
import { useMachine } from "@xstate/react"
78
import frontMatter from "front-matter"
89
import { FC } from "react"
910
import ReactMarkdown from "react-markdown"
1011
import { Link as RouterLink } from "react-router-dom"
1112
import { firstLetter } from "util/firstLetter"
13+
import { templateMetricsMachine } from "xServices/templateMetrics/templateMetricsXService"
1214
import { Template, TemplateVersion, WorkspaceResource } from "../../api/typesGenerated"
1315
import { Margins } from "../../components/Margins/Margins"
1416
import {
@@ -21,6 +23,7 @@ import { TemplateResourcesTable } from "../../components/TemplateResourcesTable/
2123
import { TemplateStats } from "../../components/TemplateStats/TemplateStats"
2224
import { VersionsTable } from "../../components/VersionsTable/VersionsTable"
2325
import { WorkspaceSection } from "../../components/WorkspaceSection/WorkspaceSection"
26+
import { DAUChart } from "./DAUCharts"
2427

2528
const Language = {
2629
settingsButton: "Settings",
@@ -48,6 +51,13 @@ export const TemplatePageView: FC<React.PropsWithChildren<TemplatePageViewProps>
4851
const readme = frontMatter(activeTemplateVersion.readme)
4952
const hasIcon = template.icon && template.icon !== ""
5053

54+
const [metricsState] = useMachine(templateMetricsMachine, {
55+
context: {
56+
templateId: template.id,
57+
},
58+
})
59+
const { templateMetricsData } = metricsState.context
60+
5161
const getStartedResources = (resources: WorkspaceResource[]) => {
5262
return resources.filter((resource) => resource.workspace_transition === "start")
5363
}
@@ -95,6 +105,8 @@ export const TemplatePageView: FC<React.PropsWithChildren<TemplatePageViewProps>
95105
</Stack>
96106
</PageHeader>
97107

108+
{templateMetricsData && <DAUChart templateMetricsData={templateMetricsData} />}
109+
98110
<Stack spacing={2.5}>
99111
<TemplateStats template={template} activeVersion={activeTemplateVersion} />
100112
<WorkspaceSection

site/src/pages/UsersPage/UsersPage.test.tsx

-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-floating-promises */
22
import { fireEvent, screen, waitFor, within } from "@testing-library/react"
33
import { rest } from "msw"
4-
import { ResizeObserver } from "resize-observer"
54
import { Language as usersXServiceLanguage } from "xServices/users/usersXService"
65
import * as API from "../../api/api"
76
import { Role } from "../../api/typesGenerated"
@@ -21,10 +20,6 @@ import { permissionsToCheck } from "../../xServices/auth/authXService"
2120
import { Language as UsersPageLanguage, UsersPage } from "./UsersPage"
2221
import { Language as UsersViewLanguage } from "./UsersPageView"
2322

24-
Object.defineProperty(window, "ResizeObserver", {
25-
value: ResizeObserver,
26-
})
27-
2823
const suspendUser = async (setupActionSpies: () => void) => {
2924
// Get the first user in the table
3025
const users = await screen.findAllByText(/.*@coder.com/)

site/src/pages/UsersPage/UsersPage.tsx

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { useActor, useMachine } from "@xstate/react"
1+
import { useActor } from "@xstate/react"
22
import { FC, ReactNode, useContext, useEffect } from "react"
33
import { Helmet } from "react-helmet-async"
44
import { useNavigate } from "react-router"
55
import { useSearchParams } from "react-router-dom"
6-
import { userMetricsMachine } from "xServices/userMetrics/userMetricsXService"
76
import { ConfirmDialog } from "../../components/ConfirmDialog/ConfirmDialog"
87
import { ResetPasswordDialog } from "../../components/ResetPasswordDialog/ResetPasswordDialog"
98
import { userFilterQuery } from "../../util/filters"
@@ -45,9 +44,6 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
4544
const [rolesState, rolesSend] = useActor(xServices.siteRolesXService)
4645
const { roles } = rolesState.context
4746

48-
const [metricsState] = useMachine(userMetricsMachine)
49-
const { userMetricsData } = metricsState.context
50-
5147
// Is loading if
5248
// - permissions are loading or
5349
// - users are loading or
@@ -83,7 +79,6 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
8379
<title>{pageTitle("Users")}</title>
8480
</Helmet>
8581
<UsersPageView
86-
userMetricsData={userMetricsData}
8782
roles={roles}
8883
users={users}
8984
openUserCreationDialog={() => {

site/src/pages/UsersPage/UsersPageView.tsx

-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { PageHeader, PageHeaderTitle } from "../../components/PageHeader/PageHea
77
import { SearchBarWithFilter } from "../../components/SearchBarWithFilter/SearchBarWithFilter"
88
import { UsersTable } from "../../components/UsersTable/UsersTable"
99
import { userFilterQuery } from "../../util/filters"
10-
import { DAUChart } from "./DAUCharts"
1110

1211
export const Language = {
1312
pageTitle: "Users",
@@ -16,7 +15,6 @@ export const Language = {
1615
allUsersFilterName: "All users",
1716
}
1817
export interface UsersPageViewProps {
19-
userMetricsData?: TypesGen.DAUsResponse
2018
users?: TypesGen.User[]
2119
roles?: TypesGen.AssignableRoles[]
2220
filter?: string
@@ -34,7 +32,6 @@ export interface UsersPageViewProps {
3432
}
3533

3634
export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
37-
userMetricsData,
3835
users,
3936
roles,
4037
openUserCreationDialog,
@@ -69,8 +66,6 @@ export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
6966
<PageHeaderTitle>{Language.pageTitle}</PageHeaderTitle>
7067
</PageHeader>
7168

72-
{userMetricsData && <DAUChart userMetricsData={userMetricsData} />}
73-
7469
<div style={{ marginTop: "15px" }}>
7570
<SearchBarWithFilter
7671
filter={filter}

site/src/testHelpers/entities.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FieldError } from "api/errors"
22
import * as Types from "../api/types"
33
import * as TypesGen from "../api/typesGenerated"
44

5-
export const MockGetDAUResponse: TypesGen.DAUsResponse = {
5+
export const MockTemplateDAUResponse: TypesGen.TemplateDAUsResponse = {
66
entries: [
77
{ date: "2022-08-27T00:00:00Z", daus: 1 },
88
{ date: "2022-08-29T00:00:00Z", daus: 2 },

site/src/testHelpers/handlers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { permissionsToCheck } from "../xServices/auth/authXService"
55
import * as M from "./entities"
66

77
export const handlers = [
8-
rest.get("/api/v2/metrics/daus", async (req, res, ctx) => {
9-
return res(ctx.status(200), ctx.json(M.MockGetDAUResponse))
8+
rest.get("/api/v2/templates/:templateId/daus", async (req, res, ctx) => {
9+
return res(ctx.status(200), ctx.json(M.MockTemplateDAUResponse))
1010
}),
1111

1212
// build info

site/src/xServices/userMetrics/userMetricsXService.ts renamed to site/src/xServices/templateMetrics/templateMetricsXService.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
import { DAUsResponse } from "api/typesGenerated"
1+
import { TemplateDAUsResponse } from "api/typesGenerated"
22
import { assign, createMachine } from "xstate"
33
import * as API from "../../api/api"
44

5-
export interface UserMetricsContext {
6-
userMetricsData: DAUsResponse
5+
export interface TemplateMetricsContext {
6+
templateId: string
7+
templateMetricsData: TemplateDAUsResponse
78
}
89

9-
export const userMetricsMachine = createMachine(
10+
export const templateMetricsMachine = createMachine(
1011
{
11-
id: "userMetrics",
12+
id: "templateMetrics",
1213
schema: {
13-
context: {} as UserMetricsContext,
14+
context: {} as TemplateMetricsContext,
1415
services: {} as {
1516
loadMetrics: {
16-
data: DAUsResponse
17+
data: TemplateDAUsResponse
1718
}
1819
},
1920
},
20-
tsTypes: {} as import("./userMetricsXService.typegen").Typegen0,
21+
tsTypes: {} as import("./templateMetricsXService.typegen").Typegen0,
2122
initial: "loadingMetrics",
2223
states: {
2324
loadingMetrics: {
@@ -37,11 +38,11 @@ export const userMetricsMachine = createMachine(
3738
{
3839
actions: {
3940
assignDataMetrics: assign({
40-
userMetricsData: (_, event) => event.data,
41+
templateMetricsData: (_, event) => event.data,
4142
}),
4243
},
4344
services: {
44-
loadMetrics: () => API.getDAUs,
45+
loadMetrics: (context) => API.getTemplateDAUs(context.templateId),
4546
},
4647
},
4748
)

0 commit comments

Comments
 (0)