fix(mobile): restore main's guard conditions on the four Project-row actions

Each had gained a non-null target requirement that demanded a number and a
recognised item type where main's guard did not, so a row main would have sent
for now returns silently or reports an error.

File-viewed and the comment reply gate on main's conditions and build the
never-null identity target after them. Metadata update, issue type and comment
add gate on the slug and the number, as main did, through the slug target,
which does not read the item type.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo-H
2026-09-09 12:49:30 -04:00
parent d0994be78e
commit d96f68457c
6 changed files with 23 additions and 26 deletions
@@ -93,7 +93,9 @@ describe('mobile GitHub Project host routing boundary', () => {
it('pins Project-row PR actions to the row repository identity', () => {
// Every Project-row action resolves its target from the row plus the active Project host.
const targets = [
...compositionSource.matchAll(/projectRow(?:Mutation|PullRequest)Target\(([^)]*)\)/g)
...compositionSource.matchAll(
/projectRow(?:Mutation|PullRequest|Slug|Identity)Target\(([^)]*)\)/g
)
]
expect(targets.length).toBeGreaterThan(10)
for (const target of targets) {
@@ -25,9 +25,9 @@ const hash = (parts: string[] | string): string =>
* plus the row-target locals the adapters take in place of inline slug/number checks. Diff hooks,
* declarations and styles are untouched.
*/
const SCREEN_HOOKS = '28f62d2fbd86d171bf162d26c6bd0763e4fb8c3f58895d7cd1a00633c1465f32'
const SCREEN_HOOKS = '5f298d284b82e70b267c499d192c827c39c0e802e7e3cf2b17715480991376a8'
const DIFF_HOOKS = '93c7189b32bed8456cc51814fffa8ce80cf62011ef968a9d53ddec2b9686f58f'
const STATEMENTS = 'd3f99f5ccf5decedadeef99e7633b8ce832b39e9a49675c43fbc0954b2a2e483'
const STATEMENTS = 'd5a642c641b1e830b71a437d53b809ba40e4e8a5fd36adbbbeb8173048569295'
const DECLARATIONS = 'cff54172af17a877789be1479c2eb6ca97d83c3e31dd831cd59395962f2b4c4a'
const SEMANTICS = 'f767906884b93537f2c6369d6d0bd2d4cb39b4314c31cca9d8f9e5e9b78a75ee'
const STYLES = '1db6af69c791d9963928541ad5310942fcbda6d984b422c90b6eb92b6816579a'
@@ -7,7 +7,7 @@ import {
type GitHubProjectRow,
optimisticProjectFieldValue
} from './mobile-tasks-legacy-foundation'
import { projectRowIdentityTarget, projectRowMutationTarget } from './mobile-tasks-mutation-targets'
import { projectRowIdentityTarget, projectRowSlugTarget } from './mobile-tasks-mutation-targets'
export function useMobileTasksProjectMetadataActions(model: ProjectThreadReplyActionsModel) {
const {
@@ -35,8 +35,9 @@ export function useMobileTasksProjectMetadataActions(model: ProjectThreadReplyAc
if (!taskOperations || projectMutating) {
return
}
const target = projectRowMutationTarget(row, activeGitHubProjectHost)
if (!target) {
// main gated on the slug and the number only; an unrecognised item type was not a refusal.
const target = projectRowSlugTarget(row, activeGitHubProjectHost)
if (!target || !row.content.number) {
setProjectRowDetailError('This project item cannot be edited from mobile.')
return
}
@@ -178,8 +179,8 @@ export function useMobileTasksProjectMetadataActions(model: ProjectThreadReplyAc
if (!taskOperations || projectMutating) {
return
}
const target = projectRowMutationTarget(row, activeGitHubProjectHost)
if (row.itemType !== 'ISSUE' || !target) {
const target = projectRowSlugTarget(row, activeGitHubProjectHost)
if (row.itemType !== 'ISSUE' || !target || !row.content.number) {
setProjectRowDetailError('This project issue type cannot be edited from mobile.')
return
}
@@ -6,7 +6,10 @@ import {
type GitHubProjectRow,
splitReviewerList
} from './mobile-tasks-legacy-foundation'
import { projectRowPullRequestTarget } from './mobile-tasks-mutation-targets'
import {
projectRowIdentityTarget,
projectRowPullRequestTarget
} from './mobile-tasks-mutation-targets'
export function useMobileTasksProjectReviewCheckActions(model: ProjectMetadataActionsModel) {
const {
@@ -157,16 +160,10 @@ export function useMobileTasksProjectReviewCheckActions(model: ProjectMetadataAc
const toggleProjectGitHubFileViewed = useCallback(
async (row: GitHubProjectRow, file: GitHubDetailFile): Promise<void> => {
const repo = findProjectRowRepo(row)
const target = projectRowPullRequestTarget(row, activeGitHubProjectHost)
if (
!taskOperations ||
projectMutating ||
row.itemType !== 'PULL_REQUEST' ||
!repo ||
!target
) {
if (!taskOperations || projectMutating || row.itemType !== 'PULL_REQUEST' || !repo) {
return
}
const target = projectRowIdentityTarget(row, activeGitHubProjectHost)
if (projectRowDetail?.provider !== 'github' || !projectRowDetail.pullRequestId) {
setProjectRowDetailError('Unable to sync viewed state for this pull request.')
return
@@ -5,11 +5,7 @@ import {
type GitHubProjectRow,
commentAuthor
} from './mobile-tasks-legacy-foundation'
import {
projectRowIdentityTarget,
projectRowMutationTarget,
projectRowSlugTarget
} from './mobile-tasks-mutation-targets'
import { projectRowIdentityTarget, projectRowSlugTarget } from './mobile-tasks-mutation-targets'
export function useMobileTasksProjectThreadReplyActions(
model: ProjectWorkspaceCommentActionsModel
@@ -116,10 +112,10 @@ export function useMobileTasksProjectThreadReplyActions(
const replyToProjectGitHubComment = useCallback(
async (row: GitHubProjectRow, comment: DetailComment): Promise<void> => {
const repo = findProjectRowRepo(row)
const target = projectRowMutationTarget(row, activeGitHubProjectHost)
if (!taskOperations || projectMutating || !repo || !target) {
if (!taskOperations || projectMutating || !repo || !row.content.number) {
return
}
const target = projectRowIdentityTarget(row, activeGitHubProjectHost)
const key = String(comment.id)
const body = (itemReplyDrafts[key] ?? '').trim()
if (!body) {
@@ -158,9 +158,10 @@ export function useMobileTasksProjectWorkspaceCommentActions(model: WorkspaceCre
if (!taskOperations || projectMutating) {
return
}
const target = projectRowMutationTarget(row, activeGitHubProjectHost)
// main gated on the slug, the number and a non-empty body; the item type was not read.
const target = projectRowSlugTarget(row, activeGitHubProjectHost)
const body = projectCommentDraft.trim()
if (!target || !body) {
if (!target || !row.content.number || !body) {
return
}
setProjectMutating(true)