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

feat: auto publish after creating new provision. #7249

Merged
merged 24 commits into from
Apr 30, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c9b321b
add trigger for publish
alanlong9278 Apr 20, 2021
91445b6
provision & publish
alanlong9278 Apr 21, 2021
4e6d062
async problem
alanlong9278 Apr 22, 2021
b405caa
Merge branch 'main' into julong/skill-supplement
alanlong9278 Apr 22, 2021
7d2cc99
Merge branch 'main' into julong/skill-supplement
alanlong9278 Apr 23, 2021
1fc3b09
lint
alanlong9278 Apr 23, 2021
cd6ef38
sync file change
alanlong9278 Apr 23, 2021
b876f78
async publish target
alanlong9278 Apr 24, 2021
dd25f1e
navigate to publish page after returning publish result
alanlong9278 Apr 24, 2021
1d9ffbc
add url
alanlong9278 Apr 26, 2021
bc3762e
Merge branch 'main' into julong/skill-supplement
luhan2017 Apr 26, 2021
75d5e7f
Merge branch 'main' into julong/skill-supplement
luhan2017 Apr 27, 2021
a32ab6a
Merge branch 'main' into julong/skill-supplement
boydc2014 Apr 28, 2021
3f74d2c
Merge branch 'main' into julong/skill-supplement
boydc2014 Apr 28, 2021
7bb4d5a
Merge branch 'main' into julong/skill-supplement
luhan2017 Apr 28, 2021
df557ae
Merge branch 'main' into julong/skill-supplement
hatpick Apr 28, 2021
6f9267a
Merge branch 'main' into julong/skill-supplement
alanlong9278 Apr 29, 2021
86f8d05
comments
alanlong9278 Apr 29, 2021
0283f86
bugifx
alanlong9278 Apr 29, 2021
a325857
Merge branch 'main' into julong/skill-supplement
srinaath Apr 29, 2021
e2c7c3e
Merge branch 'main' into julong/skill-supplement
boydc2014 Apr 30, 2021
489be5f
Merge branch 'main' into julong/skill-supplement
alanlong9278 Apr 30, 2021
64fe3fa
lint
alanlong9278 Apr 30, 2021
f2e506e
Merge branch 'julong/skill-supplement' of https://github.com/microsof…
alanlong9278 Apr 30, 2021
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 @@ -22,10 +22,11 @@ import { actionButton } from './styles';

type CreatePublishProfileDialogProps = {
projectId: string;
setIsCreateProfileFromSkill: (isCreateProfileFromSkill: boolean) => void;
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
};

export const CreatePublishProfileDialog: React.FC<CreatePublishProfileDialogProps> = (props) => {
const { projectId } = props;
const { projectId, setIsCreateProfileFromSkill } = props;
const { publishTargets } = useRecoilValue(settingsState(projectId));
const { getPublishTargetTypes, setPublishTargets } = useRecoilValue(dispatcherState);
const publishTypes = useRecoilValue(publishTypesState(projectId));
Expand Down Expand Up @@ -99,6 +100,7 @@ export const CreatePublishProfileDialog: React.FC<CreatePublishProfileDialogProp
}}
current={currentPublishProfile}
projectId={projectId}
setIsCreateProfileFromSkill={setIsCreateProfileFromSkill}
setPublishTargets={setPublishTargets}
targets={publishTargets || []}
types={publishTypes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type PublishProfileDialogProps = {
types: PublishType[];
projectId: string;
setPublishTargets: (targets: PublishTarget[], projectId: string) => Promise<void>;
setIsCreateProfileFromSkill?: (isCreateProfileFromSkill: boolean) => void;
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
};

const Page = {
Expand All @@ -38,7 +39,7 @@ const Page = {
};

export const PublishProfileDialog: React.FC<PublishProfileDialogProps> = (props) => {
const { current, types, projectId, closeDialog, targets, setPublishTargets } = props;
const { current, types, projectId, closeDialog, targets, setPublishTargets, setIsCreateProfileFromSkill } = props;
const [name, setName] = useState(current?.item.name || '');
const [targetType, setTargetType] = useState<string>(current?.item.type || '');

Expand Down Expand Up @@ -194,7 +195,8 @@ export const PublishProfileDialog: React.FC<PublishProfileDialogProps> = (props)
arm = getTokenFromCache('accessToken');
graph = getTokenFromCache('graphToken');
}
provisionToTarget(fullConfig, config.type, projectId, arm, graph, current?.item);
await provisionToTarget(fullConfig, config.type, projectId, arm, graph, current?.item);
setIsCreateProfileFromSkill?.(true);
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
};
}, [name, targetType, types, savePublishTarget]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export interface ContentProps {
setSelectedDialogs: (dialogs: any[]) => void;
setSelectedTriggers: (selectedTriggers: any[]) => void;
setSkillManifest: (_: Partial<SkillManifestFile>) => void;
setIsCreateProfileFromSkill: (isCreateProfileFromSkill: boolean) => void;
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
schema: JSONSchema7;
selectedDialogs: any[];
selectedTriggers: any[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ export const getManifestId = (
return fileId;
};

export const SelectProfile: React.FC<ContentProps> = ({ manifest, setSkillManifest, value, onChange, projectId }) => {
export const SelectProfile: React.FC<ContentProps> = ({
manifest,
setSkillManifest,
value,
onChange,
projectId,
setIsCreateProfileFromSkill,
}) => {
const [publishingTargets, setPublishingTargets] = useState<PublishTarget[]>([]);
const [currentTarget, setCurrentTarget] = useState<PublishTarget>();
const { updateCurrentTarget } = useRecoilValue(dispatcherState);
Expand Down Expand Up @@ -201,7 +208,10 @@ export const SelectProfile: React.FC<ContentProps> = ({ manifest, setSkillManife
</div>
) : (
<div>
<CreatePublishProfileDialog projectId={projectId}></CreatePublishProfileDialog>
<CreatePublishProfileDialog
projectId={projectId}
setIsCreateProfileFromSkill={setIsCreateProfileFromSkill}
></CreatePublishProfileDialog>
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
</div>
);
};
109 changes: 103 additions & 6 deletions Composer/packages/client/src/pages/design/exportSkillModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import formatMessage from 'format-message';
import { Dialog, DialogFooter, DialogType } from 'office-ui-fabric-react/lib/Dialog';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
Expand All @@ -15,6 +15,7 @@ import { navigate } from '@reach/router';
import { isUsingAdaptiveRuntime } from '@bfc/shared';
import cloneDeep from 'lodash/cloneDeep';

import { Notification } from '../../../recoilModel/types';
import {
dispatcherState,
skillManifestsState,
Expand All @@ -26,11 +27,21 @@ import {
settingsState,
rootBotProjectIdSelector,
} from '../../../recoilModel';
import { mergePropertiesManagedByRootBot } from '../../../recoilModel/dispatchers/utils/project';
import {
getSensitiveProperties,
mergePropertiesManagedByRootBot,
} from '../../../recoilModel/dispatchers/utils/project';
import { getTokenFromCache } from '../../../utils/auth';
import { ApiStatus, PublishStatusPollingUpdater } from '../../../utils/publishStatusPollingUpdater';
import {
getSkillPublishedNotificationCardProps,
getSkilPendingNotificationCardProps,
} from '../../publish/Notifications';
import { createNotification } from '../../../recoilModel/dispatchers/notification';

import { styles } from './styles';
import { generateSkillManifest } from './generateSkillManifest';
import { editorSteps, ManifestEditorSteps, order } from './constants';
import { generateSkillManifest } from './generateSkillManifest';
import { styles } from './styles';

interface ExportSkillModalProps {
isOpen: boolean;
Expand All @@ -46,11 +57,18 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
const luFiles = useRecoilValue(luFilesSelectorFamily(projectId));
const qnaFiles = useRecoilValue(qnaFilesSelectorFamily(projectId));
const skillManifests = useRecoilValue(skillManifestsState(projectId));
const { updateSkillManifest } = useRecoilValue(dispatcherState);
const {
updateSkillManifest,
publishToTarget,
addNotification,
updateNotification,
deleteNotification,
} = useRecoilValue(dispatcherState);

const [currentStep, setCurrentStep] = useState(0);
const [errors, setErrors] = useState({});
const [schema, setSchema] = useState<JSONSchema7>({});
const [isHidden, setIsHidden] = useState(false);

const [skillManifest, setSkillManifest] = useState<Partial<SkillManifestFile>>({});
const { content = {}, id } = skillManifest;
Expand All @@ -71,6 +89,84 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
!isAdaptive ? skillConfiguration?.allowedCallers : runtimeSettings?.skills?.allowedCallers ?? []
);

const [isCreateProfileFromSkill, setIsCreateProfileFromSkill] = useState(false);
let publishUpdater: PublishStatusPollingUpdater;
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
const publishNotificationRef = useRef<Notification>();
// stop polling updater & delete pending notification
const stopUpdater = async (updater) => {
updater.stop();

const notification = publishNotificationRef.current;
notification && (await deleteNotification(notification.id));
publishNotificationRef.current = undefined;
handleDismiss();
setIsHidden(false);
};
const changeNotificationStatus = async (data) => {
const { apiResponse } = data;
if (!apiResponse) {
stopUpdater(publishUpdater);
return;
}
const responseData = apiResponse.data;

if (responseData.status !== ApiStatus.Publishing) {
// Show result notifications
const displayedNotification = publishNotificationRef.current;
if (displayedNotification) {
const currentTarget = publishTargets?.find((target) => target.name === publishUpdater.getPublishTargetName());
const url = currentTarget
? `https://${JSON.parse(currentTarget.configuration).hostname}.azurewebsites.net/manifests/${
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
skillManifest.id
}.json`
: '';
const notificationCard = getSkillPublishedNotificationCardProps({ ...responseData }, url);
updateNotification(displayedNotification.id, notificationCard);
}
stopUpdater(publishUpdater);
navigate(`bot/${projectId}/publish/all`);
}
};

useEffect(() => {
const publish = async () => {
if (!publishTargets || publishTargets.length === 0) return;
const currentTarget = publishTargets.find((item) => {
const config = JSON.parse(item.configuration);
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
return (
config.settings &&
config.settings.MicrosoftAppId &&
config.hostname &&
config.settings.MicrosoftAppId.length > 0 &&
config.hostname.length > 0
);
});
if (isCreateProfileFromSkill && currentTarget) {
const skillPublishPenddingNotificationCard = getSkilPendingNotificationCardProps();
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
publishNotificationRef.current = createNotification(skillPublishPenddingNotificationCard);
addNotification(publishNotificationRef.current);
const sensitiveSettings = getSensitiveProperties(settings);
const token = getTokenFromCache('accessToken');
await publishToTarget(projectId, currentTarget, { comment: '' }, sensitiveSettings, token);
publishUpdater = new PublishStatusPollingUpdater(projectId, currentTarget.name);
publishUpdater.start(changeNotificationStatus);
}
};
publish();
}, [isCreateProfileFromSkill, publishTargets?.length]);
useEffect(() => {
isCreateProfileFromSkill && setIsHidden(true);
}, [isCreateProfileFromSkill]);

useEffect(() => {
// Clear intervals when unmount
return () => {
if (publishUpdater) {
stopUpdater(publishUpdater);
}
};
}, []);

const updateAllowedCallers = React.useCallback(
(allowedCallers: string[] = []) => {
const updatedSetting = isAdaptive
Expand Down Expand Up @@ -167,7 +263,7 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
title: title(),
styles: styles.dialog,
}}
hidden={false}
hidden={isHidden}
modalProps={{
isBlocking: false,
styles: styles.modal,
Expand Down Expand Up @@ -203,6 +299,7 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
selectedDialogs={selectedDialogs}
selectedTriggers={selectedTriggers}
setErrors={setErrors}
setIsCreateProfileFromSkill={setIsCreateProfileFromSkill}
setSchema={setSchema}
setSelectedDialogs={setSelectedDialogs}
setSelectedTriggers={setSelectedTriggers}
Expand Down
21 changes: 20 additions & 1 deletion Composer/packages/client/src/pages/publish/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ export const getPublishedNotificationCardProps = (item: BotStatus): CardProps =>
};
};

export const getSkillPublishedNotificationCardProps = (item: BotStatus, url?: string): CardProps => {
export const getSkillPublishedNotificationCardProps = (
item: { status: number; [key: string]: any },
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
url?: string
): CardProps => {
const skillCardContent = css`
display: flex;
padding: 0 16px 16px 12px;
Expand Down Expand Up @@ -185,6 +188,22 @@ export const getPendingNotificationCardProps = (items: BotStatus[], isSkill = fa
};
};

export const getSkilPendingNotificationCardProps = (): CardProps => {
return {
title: '',
description: formatMessage('Publishing your skill...'),
type: 'pending',
onRenderCardContent: (props) => (
<div css={cardContent}>
<Icon css={infoType} iconName="CloudUpload" />
<div css={cardDetail}>
<ProgressIndicator label={props.description} />
</div>
</div>
),
};
};

export const getPendingQNANotificationCardProps = (): CardProps => {
return {
title: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export const DispatcherWrapper = ({ children }) => {
if (filePersistence.isErrorHandlerEmpty()) {
filePersistence.registerErrorHandler(setProjectError);
}
filePersistence.notify(assets, previousAssets);
await filePersistence.notify(assets, previousAssets);
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,17 @@ export const notificationDispatcher = () => {
set(notificationsState(id), (notification) => ({ ...notification, hidden: true }));
});

const updateNotification = useRecoilCallback(
(callbackHelper: CallbackInterface) => (id: string, newValue: CardProps) => {
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
updateNotificationInternal(callbackHelper, id, newValue);
}
);

return {
addNotification,
deleteNotification,
hideNotification,
markNotificationAsRead,
updateNotification,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const provisionDispatcher = () => {
});

// call provision status api interval to update the state.
updateProvisionStatus(
await updateProvisionStatus(
callbackHelpers,
result.data.id,
projectId,
Expand Down Expand Up @@ -135,7 +135,7 @@ export const provisionDispatcher = () => {
});

// update publishTargets
callbackHelpers.set(settingsState(projectId), (settings) => {
await callbackHelpers.set(settingsState(projectId), (settings) => {
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
const profile = {
configuration: JSON.stringify(response.data.config, null, 2),
name: targetName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,10 @@ export const publisherDispatcher = () => {
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
const filePersistence = await snapshot.getPromise(filePersistenceState(projectId));
await filePersistence.flush();
const response = await httpClient.post(`/publish/${projectId}/publish/${target.name}`, {
publishTarget: target,
accessToken: token,
metadata: {
...metadata,
Expand All @@ -190,7 +193,7 @@ export const publisherDispatcher = () => {
// add job id to storage
const publishJobIds = publishStorage.get('jobIds') || {};
publishJobIds[`${projectId}-${target.name}`] = response.data.id;
publishStorage.set('jobIds', publishJobIds);
await publishStorage.set('jobIds', publishJobIds);
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved

await publishSuccess(callbackHelpers, projectId, response.data, target);
} catch (err) {
Expand Down Expand Up @@ -243,7 +246,7 @@ export const publisherDispatcher = () => {
const { set, snapshot } = callbackHelpers;
try {
const filePersistence = await snapshot.getPromise(filePersistenceState(projectId));
filePersistence.flush();
await filePersistence.flush();
const response = await httpClient.get(`/publish/${projectId}/history/${target.name}`);
set(publishHistoryState(projectId), (publishHistory) => ({
...publishHistory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export class PublishStatusPollingUpdater {
isSameUpdater(botProjectId: string, targetName: string) {
return this.botProjectId === botProjectId && this.publishTargetName === targetName;
}

getPublishTargetName() {
return this.publishTargetName;
}
}

export const pollingUpdaterList: PublishStatusPollingUpdater[] = [];
Loading