addons/isl/src/SubmitSelectionButton.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {CommitInfo} from './types';
b69ab319
b69ab3110import {Tooltip} from 'isl-components/Tooltip';
b69ab3111import {atom, useAtomValue} from 'jotai';
b69ab3112import {HighlightCommitsWhileHovering} from './HighlightedCommits';
b69ab3113import {OperationDisabledButton} from './OperationDisabledButton';
b69ab3114import {multiSubmitUpdateMessage} from './SubmitUpdateMessageInput';
b69ab3115import {allDiffSummaries, codeReviewProvider} from './codeReview/CodeReviewInfo';
b69ab3116import {submitAsDraft} from './codeReview/DraftCheckbox';
b69ab3117import {publishWhenReady} from './codeReview/PublishWhenReadyCheckbox';
b69ab3118import {t, T} from './i18n';
b69ab3119import {readAtom, writeAtom} from './jotaiUtils';
b69ab3120import {dagWithPreviews} from './previews';
b69ab3121import {selectedCommits} from './selection';
b69ab3122
b69ab3123/**
b69ab3124 * If the selected commits are submittable by the review provider,
b69ab3125 * they may be submit.
b69ab3126 */
b69ab3127export const submittableSelection = atom(get => {
b69ab3128 const selection = get(selectedCommits);
b69ab3129 if (selection.size < 2) {
b69ab3130 return undefined;
b69ab3131 }
b69ab3132 const provider = get(codeReviewProvider);
b69ab3133 const diffSummaries = get(allDiffSummaries);
b69ab3134
b69ab3135 if (provider == null || diffSummaries == null) {
b69ab3136 return undefined;
b69ab3137 }
b69ab3138
b69ab3139 const dag = get(dagWithPreviews);
b69ab3140 const commits = dag.getBatch(dag.sortAsc(dag.present(selection)));
b69ab3141 const submittable =
b69ab3142 (diffSummaries.value != null
b69ab3143 ? provider?.getSubmittableDiffs(commits, diffSummaries.value)
b69ab3144 : undefined) ?? [];
b69ab3145
b69ab3146 return submittable;
b69ab3147});
b69ab3148
b69ab3149/**
b69ab3150 * Button to submit the selected commits, if applicable.
b69ab3151 * If `commit` is provided, only render the button if the commit is the bottom of the selected range.
b69ab3152 * If `commit` is null, always show the button if there are commits to submit.
b69ab3153 */
b69ab3154export function SubmitSelectionButton({commit}: {commit?: CommitInfo}) {
b69ab3155 const submittable = useAtomValue(submittableSelection);
b69ab3156 const provider = useAtomValue(codeReviewProvider);
b69ab3157
b69ab3158 if (
b69ab3159 provider == null ||
b69ab3160 submittable == null ||
b69ab3161 submittable.length < 2 ||
b69ab3162 // show the button on the bottom commit of the submittable selection, if showing the button on a commit.
b69ab3163 (commit != null && submittable?.[0]?.hash !== commit.hash)
b69ab3164 ) {
b69ab3165 return null;
b69ab3166 }
b69ab3167
b69ab3168 return (
b69ab3169 <Tooltip
b69ab3170 title={t('Submit $count selected commits for code review with $provider', {
b69ab3171 replace: {
b69ab3172 $count: String(submittable.length),
b69ab3173 $provider: provider.label ?? 'remote',
b69ab3174 },
b69ab3175 })}>
b69ab3176 <HighlightCommitsWhileHovering toHighlight={submittable}>
b69ab3177 <OperationDisabledButton
b69ab3178 runOperation={() => {
b69ab3179 const updateMessage = readAtom(multiSubmitUpdateMessage(submittable));
b69ab3180 // clear update message on submit
b69ab3181 writeAtom(multiSubmitUpdateMessage(submittable), '');
b69ab3182 return provider.submitOperation(submittable, {
b69ab3183 draft: readAtom(submitAsDraft),
b69ab3184 updateMessage: updateMessage || undefined,
b69ab3185 publishWhenReady: readAtom(publishWhenReady),
b69ab3186 });
b69ab3187 }}
b69ab3188 contextKey={`submit-selection-${submittable[0].hash}`}>
8d8e81589 <T replace={{$count: submittable.length, $action: provider.submitButtonLabel ?? 'Submit'}}>
8d8e81590 $action $count commits
8d8e81591 </T>
b69ab3192 </OperationDisabledButton>
b69ab3193 </HighlightCommitsWhileHovering>
b69ab3194 </Tooltip>
b69ab3195 );
b69ab3196}