Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export const OrganizationSettings = ({
releaseDetectionMethod: string
releaseDetectionKey: string
isActive: number
excludedUsers: string
timezone: string
language: string
}
Expand All @@ -60,7 +59,6 @@ export const OrganizationSettings = ({
releaseDetectionMethod: organizationSetting?.releaseDetectionMethod,
releaseDetectionKey: organizationSetting?.releaseDetectionKey,
isActive: organizationSetting?.isActive ? '1' : undefined,
excludedUsers: organizationSetting?.excludedUsers,
timezone: organizationSetting?.timezone ?? DEFAULT_TIMEZONE,
language: organizationSetting?.language,
},
Expand Down Expand Up @@ -173,21 +171,6 @@ export const OrganizationSettings = ({
<div className="text-destructive">{fields.isActive.errors}</div>
</fieldset>

<fieldset className="space-y-1">
<Label htmlFor={fields.excludedUsers.id}>
Excluded Users (comma separated)
</Label>
<Input
{...getInputProps(fields.excludedUsers, { type: 'text' })}
placeholder="e.g. my-org-bot, some-other-bot"
/>
<p className="text-muted-foreground text-sm">
Copilot is excluded by default. Add additional usernames to exclude
from cycle time calculations.
</p>
<div className="text-destructive">{fields.excludedUsers.errors}</div>
</fieldset>

{form.errors && (
<Alert variant="destructive">
<AlertTitle>System Error</AlertTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export const updateOrganizationSetting = async (
| 'releaseDetectionMethod'
| 'releaseDetectionKey'
| 'isActive'
| 'excludedUsers'
| 'timezone'
| 'language'
>,
Expand Down
1 change: 0 additions & 1 deletion app/routes/$orgSlug/settings/_index/+schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const organizationSettingsSchema = z.object({
.literal('on')
.optional()
.transform((val) => (val === 'on' ? 1 : 0)),
excludedUsers: z.string().max(2000).default(''),
timezone: z.string().refine((v) => VALID_TIMEZONES.has(v), {
message: 'Invalid timezone',
}),
Expand Down
2 changes: 0 additions & 2 deletions app/routes/$orgSlug/settings/_index/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export const action = async ({ request, context }: Route.ActionArgs) => {
releaseDetectionMethod,
releaseDetectionKey,
isActive,
excludedUsers,
timezone,
language,
} = submission.value
Expand All @@ -55,7 +54,6 @@ export const action = async ({ request, context }: Route.ActionArgs) => {
releaseDetectionMethod,
releaseDetectionKey,
isActive,
excludedUsers,
timezone,
language,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,18 @@ export function createColumns(timezone: string): ColumnDef<GithubUserRow>[] {
),
},
{
accessorKey: 'createdAt',
accessorKey: 'lastActivityAt',
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Created" />
),
cell: ({ row }) => (
<div className="text-muted-foreground text-nowrap">
{dayjs
.utc(row.getValue('createdAt'))
.tz(timezone)
.format('YYYY-MM-DD')}
</div>
<DataTableColumnHeader column={column} title="Last Activity" />
),
cell: ({ row }) => {
const value = row.getValue<string | null>('lastActivityAt')
return (
<div className="text-muted-foreground text-nowrap">
{value ? dayjs.utc(value).tz(timezone).fromNow() : '-'}
</div>
)
},
},
{
id: 'actions',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const SortSchema = z.object({
z
.union([z.literal('asc'), z.literal('desc')])
.optional()
.default('asc'),
.default('desc'),
),
})

Expand Down Expand Up @@ -99,7 +99,7 @@ export function useDataTableState() {
(prev) => {
if (newSort.sort_by) {
prev.set('sort_by', newSort.sort_by)
prev.set('sort_order', newSort.sort_order || 'asc')
prev.set('sort_order', newSort.sort_order || 'desc')
} else {
prev.delete('sort_by')
prev.delete('sort_order')
Expand Down
15 changes: 13 additions & 2 deletions app/routes/$orgSlug/settings/github-users._index/queries.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const listFilteredGithubUsers = async ({
'companyGithubUsers.displayName',
'companyGithubUsers.type',
'companyGithubUsers.isActive',
'companyGithubUsers.lastActivityAt',
'companyGithubUsers.createdAt',
])

Expand Down Expand Up @@ -71,12 +72,22 @@ export const listFilteredGithubUsers = async ({
displayName: 'companyGithubUsers.displayName',
type: 'companyGithubUsers.type',
isActive: 'companyGithubUsers.isActive',
lastActivityAt: 'companyGithubUsers.lastActivityAt',
createdAt: 'companyGithubUsers.createdAt',
}
const safeSortBy = sortFieldMap[sortBy ?? ''] ?? sortFieldMap.login
const safeSortBy = sortFieldMap[sortBy ?? ''] ?? sortFieldMap.lastActivityAt

// NULL を末尾に配置(lastActivityAt など nullable カラムのソート用)
let sortedQuery = query
if (safeSortBy === sortFieldMap.lastActivityAt) {
sortedQuery = sortedQuery.orderBy(
sql`${sql.ref(safeSortBy)} IS NULL`,
sortOrder === 'desc' ? 'asc' : 'desc',
)
}

const [rows, countResult] = await Promise.all([
query
sortedQuery
.orderBy(sql.ref(safeSortBy), sortOrder)
.limit(pageSize)
.offset((currentPage - 1) * pageSize)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
upsertPullRequestReview,
upsertPullRequestReviewers,
} from '~/batch/db/mutations'
import { getBotLogins } from '~/batch/db/queries'
import { createFetcher } from '~/batch/github/fetcher'
import type { ShapedGitHubPullRequest } from '~/batch/github/model'
import { buildPullRequests } from '~/batch/github/pullrequest'
Expand Down Expand Up @@ -161,15 +162,18 @@ export const action = async ({
timelineItems,
})

// 4. Get organization settings for build config
const settings = await getOrganizationSettings(organization.id)
// 4. Get organization settings and bot logins for build config
const [settings, botLoginsList] = await Promise.all([
getOrganizationSettings(organization.id),
getBotLogins(organization.id),
])

// 5. Build pull request data (analyze)
const result = await buildPullRequests(
{
organizationId: organization.id,
repositoryId,
excludedUsers: settings?.excludedUsers ?? '',
botLogins: new Set(botLoginsList),
releaseDetectionMethod: settings?.releaseDetectionMethod ?? 'branch',
releaseDetectionKey: settings?.releaseDetectionKey ?? '',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const getOrganizationSettings = async (
const tenantDb = getTenantDb(organizationId)
return await tenantDb
.selectFrom('organizationSettings')
.select(['releaseDetectionMethod', 'releaseDetectionKey', 'excludedUsers'])
.select(['releaseDetectionMethod', 'releaseDetectionKey'])
.executeTakeFirst()
}

Expand Down
9 changes: 6 additions & 3 deletions app/services/jobs/analyze-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface WorkerInput {
repositoryId: string
releaseDetectionMethod: string
releaseDetectionKey: string
excludedUsers: string
botLogins: string[]
filterPrNumbers?: number[]
}

Expand Down Expand Up @@ -47,11 +47,14 @@ const result: Awaited<ReturnType<typeof buildPullRequests>> =
repositoryId: input.repositoryId,
releaseDetectionMethod: input.releaseDetectionMethod,
releaseDetectionKey: input.releaseDetectionKey,
excludedUsers: input.excludedUsers,
botLogins: new Set(input.botLogins),
},
await store.loader.pullrequests(),
store.loader,
input.filterPrNumbers ? new Set(input.filterPrNumbers) : undefined,
)

parentPort?.postMessage(result)
parentPort?.postMessage({
...result,
botUsers: [...result.botUsers],
})
1 change: 1 addition & 0 deletions app/services/jobs/crawl.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const crawlJob = defineJob({
}
return {
organizationSetting: org.organizationSetting,
botLogins: org.botLogins,
repositories: org.repositories,
exportSetting: org.exportSetting,
}
Expand Down
1 change: 1 addition & 0 deletions app/services/jobs/recalculate.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const recalculateJob = defineJob({
}
return {
organizationSetting: org.organizationSetting,
botLogins: org.botLogins,
repositories: org.repositories,
exportSetting: org.exportSetting,
}
Expand Down
2 changes: 1 addition & 1 deletion app/services/jobs/run-in-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface AnalyzeWorkerInput {
repositoryId: string
releaseDetectionMethod: string
releaseDetectionKey: string
excludedUsers: string
botLogins: string[]
filterPrNumbers?: number[]
}

Expand Down
9 changes: 7 additions & 2 deletions app/services/jobs/shared-steps.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ interface AnalyzeResult {
reviews: AnalyzedReview[]
reviewers: AnalyzedReviewer[]
reviewResponses: AnalyzedReviewResponse[]
botUsers: string[]
}

interface OrganizationData {
organizationSetting: Pick<
Selectable<TenantDB.OrganizationSettings>,
'releaseDetectionMethod' | 'releaseDetectionKey' | 'excludedUsers'
'releaseDetectionMethod' | 'releaseDetectionKey'
>
botLogins: string[]
repositories: Selectable<TenantDB.Repositories>[]
exportSetting?: Selectable<TenantDB.ExportSettings> | null
}
Expand Down Expand Up @@ -107,6 +109,7 @@ export async function analyzeAndFinalizeSteps(
const allReviews: AnalyzedReview[] = []
const allReviewers: AnalyzedReviewer[] = []
const allReviewResponses: AnalyzedReviewResponse[] = []
const allBotUsers = new Set<string>()
const sqliteBusyEvents: SqliteBusyEvent[] = []

for (let i = 0; i < organization.repositories.length; i++) {
Expand All @@ -127,7 +130,7 @@ export async function analyzeAndFinalizeSteps(
repo.releaseDetectionMethod ?? orgSetting.releaseDetectionMethod,
releaseDetectionKey:
repo.releaseDetectionKey ?? orgSetting.releaseDetectionKey,
excludedUsers: orgSetting.excludedUsers,
botLogins: organization.botLogins,
filterPrNumbers: prNumbers ? [...prNumbers] : undefined,
},
{
Expand All @@ -140,6 +143,7 @@ export async function analyzeAndFinalizeSteps(
allReviews.push(...result.reviews)
allReviewers.push(...result.reviewers)
allReviewResponses.push(...result.reviewResponses)
for (const login of result.botUsers) allBotUsers.add(login)
}

// Upsert
Expand All @@ -151,6 +155,7 @@ export async function analyzeAndFinalizeSteps(
pulls: allPulls,
reviews: allReviews,
reviewers: allReviewers,
botUsers: allBotUsers,
})
})
})
Expand Down
2 changes: 1 addition & 1 deletion app/services/tenant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface CompanyGithubUsers {
createdAt: Generated<string>;
displayName: string;
isActive: 0 | 1;
lastActivityAt: string | null;
login: string;
type: string | null;
updatedAt: string;
Expand Down Expand Up @@ -70,7 +71,6 @@ export interface Integrations {

export interface OrganizationSettings {
createdAt: Generated<string>;
excludedUsers: Generated<string>;
id: string;
isActive: Generated<0 | 1>;
language: Generated<"en" | "ja">;
Expand Down
Loading