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 all 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;
onUpdateIsCreateProfileFromSkill: (isCreateProfileFromSkill: boolean) => void;
};

export const CreatePublishProfileDialog: React.FC<CreatePublishProfileDialogProps> = (props) => {
const { projectId } = props;
const { projectId, onUpdateIsCreateProfileFromSkill } = props;
const { publishTargets } = useRecoilValue(settingsState(projectId));
const { getPublishTargetTypes, setPublishTargets } = useRecoilValue(dispatcherState);
const publishTypes = useRecoilValue(publishTypesState(projectId));
Expand Down Expand Up @@ -102,6 +103,7 @@ export const CreatePublishProfileDialog: React.FC<CreatePublishProfileDialogProp
setPublishTargets={setPublishTargets}
targets={publishTargets || []}
types={publishTypes}
onUpdateIsCreateProfileFromSkill={onUpdateIsCreateProfileFromSkill}
/>
) : null}
</Fragment>
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>;
onUpdateIsCreateProfileFromSkill?: (isCreateProfileFromSkill: boolean) => void;
};

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

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

Expand Down Expand Up @@ -194,7 +203,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);
onUpdateIsCreateProfileFromSkill?.(true);
};
}, [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;
onUpdateIsCreateProfileFromSkill: (isCreateProfileFromSkill: boolean) => void;
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,
onUpdateIsCreateProfileFromSkill,
}) => {
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}
onUpdateIsCreateProfileFromSkill={onUpdateIsCreateProfileFromSkill}
/>
</div>
);
};
114 changes: 108 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,22 @@ 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,
getSkillPendingNotificationCardProps,
} from '../../publish/Notifications';
import { createNotification } from '../../../recoilModel/dispatchers/notification';
import { getManifestUrl } from '../../../utils/skillManifestUtil';

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 +58,12 @@ 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 } = 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 +84,94 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
!isAdaptive ? skillConfiguration?.allowedCallers : runtimeSettings?.skills?.allowedCallers ?? []
);

const [isCreateProfileFromSkill, setIsCreateProfileFromSkill] = useState(false);
const publishUpdaterRef = useRef<PublishStatusPollingUpdater>();
const publishNotificationRef = useRef<Notification>();
const resetDialog = () => {
handleDismiss();
setIsHidden(false);
};
// stop polling updater
const stopUpdater = () => {
publishUpdaterRef.current && publishUpdaterRef.current.stop();
publishUpdaterRef.current = undefined;
resetDialog();
};

const deleteNotificationCard = async () => {
publishNotificationRef.current = undefined;
};
const changeNotificationStatus = async (data) => {
const { apiResponse } = data;
if (!apiResponse) {
stopUpdater();
deleteNotificationCard();
return;
}
const responseData = apiResponse.data;

if (responseData.status !== ApiStatus.Publishing) {
// Show result notifications
const displayedNotification = publishNotificationRef.current;
const publishUpdater = publishUpdaterRef.current;
if (displayedNotification && publishUpdater) {
const currentTarget = publishTargets?.find((target) => target.name === publishUpdater.getPublishTargetName());
const url = currentTarget
? getManifestUrl(JSON.parse(currentTarget.configuration).hostname, skillManifest)
: '';
const notificationCard = getSkillPublishedNotificationCardProps({ ...responseData }, url);
updateNotification(displayedNotification.id, notificationCard);
}
stopUpdater();
}
};

useEffect(() => {
const publish = async () => {
try {
if (!publishTargets || publishTargets.length === 0) return;
const currentTarget = publishTargets.find((item) => {
const config = JSON.parse(item.configuration);
return (
config.settings &&
config.settings.MicrosoftAppId &&
config.hostname &&
config.settings.MicrosoftAppId.length > 0 &&
config.hostname.length > 0
);
});
if (isCreateProfileFromSkill && currentTarget) {
const skillPublishPenddingNotificationCard = getSkillPendingNotificationCardProps();
publishNotificationRef.current = createNotification(skillPublishPenddingNotificationCard);
addNotification(publishNotificationRef.current);
const sensitiveSettings = getSensitiveProperties(settings);
const token = getTokenFromCache('accessToken');
await publishToTarget(projectId, currentTarget, { comment: '' }, sensitiveSettings, token);
publishUpdaterRef.current = new PublishStatusPollingUpdater(projectId, currentTarget.name);
publishUpdaterRef.current.start(changeNotificationStatus);
}
} catch (e) {
console.log(e.message);
}
};
publish();
}, [isCreateProfileFromSkill, publishTargets?.length]);
useEffect(() => {
isCreateProfileFromSkill && setIsHidden(true);
}, [isCreateProfileFromSkill]);

useEffect(() => {
// Clear intervals when unmount
return () => {
if (publishUpdaterRef.current) {
stopUpdater();
}
if (publishNotificationRef.current) {
deleteNotificationCard();
}
};
}, []);

const updateAllowedCallers = React.useCallback(
(allowedCallers: string[] = []) => {
const updatedSetting = isAdaptive
Expand Down Expand Up @@ -167,7 +268,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 @@ -211,6 +312,7 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
value={content}
onChange={(manifestContent) => setSkillManifest({ ...skillManifest, content: manifestContent })}
onUpdateCallers={setCallers}
onUpdateIsCreateProfileFromSkill={setIsCreateProfileFromSkill}
/>
</div>
<DialogFooter>
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 } & Record<string, any>,
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 getSkillPendingNotificationCardProps = (): 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 @@ -4,6 +4,7 @@
import { PublishTarget, SkillManifestFile } from '@bfc/shared';

import { ApiStatus } from '../../utils/publishStatusPollingUpdater';
import { getManifestUrl } from '../../utils/skillManifestUtil';

import { Bot, BotStatus, BotPublishHistory, BotProjectType, BotPropertyType } from './type';

Expand Down Expand Up @@ -35,11 +36,9 @@ const findSkillManifestUrl = (skillManifests: SkillManifestFile[], hostname: str
const urls: string[] = [];
for (const skillManifest of skillManifests || []) {
for (const endpoint of skillManifest?.content?.endpoints || []) {
if (
endpoint?.msAppId === appId &&
!urls.includes(`https://${hostname}.azurewebsites.net/manifests/${skillManifest.id}.json`)
) {
urls.push(`https://${hostname}.azurewebsites.net/manifests/${skillManifest.id}.json`);
const url = getManifestUrl(hostname, skillManifest);
if (endpoint?.msAppId === appId && !urls.includes(url)) {
urls.push(url);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const deleteNotificationInternal = ({ reset, set }: CallbackInterface, id
return notifications.filter((notification) => notification !== id);
});
};
export const updateNotificationInternal = ({ set }: CallbackInterface, id: string, newValue: CardProps) => {
set(notificationsState(id), { ...newValue, id: id });
export const updateNotificationInternal = ({ set }: CallbackInterface, id: string, newValue: Partial<CardProps>) => {
set(notificationsState(id), (current) => ({ ...current, ...newValue }));
// check if notification exist
set(notificationIdsState, (notificationIds) => {
if (notificationIds.some((notificationId) => notificationId === id)) {
Expand All @@ -53,10 +53,17 @@ export const notificationDispatcher = () => {
set(notificationsState(id), (notification) => ({ ...notification, hidden: true }));
});

const updateNotification = useRecoilCallback(
(callbackHelper: CallbackInterface) => (id: string, newValue: Partial<CardProps>) => {
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
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export const publisherDispatcher = () => {
const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
const response = await httpClient.post(`/publish/${projectId}/publish/${target.name}`, {
publishTarget: target,
accessToken: token,
metadata: {
...metadata,
Expand Down Expand Up @@ -251,7 +252,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[] = [];
5 changes: 5 additions & 0 deletions Composer/packages/client/src/utils/skillManifestUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export const getManifestUrl = (hostname, skillManifest) =>
`https://${hostname}.azurewebsites.net/manifests/${skillManifest.id}.json`;
Loading