office-ui-fabric-react#Label TypeScript Examples

The following examples show how to use office-ui-fabric-react#Label. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Footer.tsx    From website with MIT License 4 votes vote down vote up
Footer = (props: Props) => {
    var theme = useTheme();
    const [cookies, setCookie] = useCookies();
    const locale = LocalizationService.strings();
    var language: string | undefined = LocalizationService.getLanguage();
    const date: Date = addDays(new Date(), 90);

    const themeToggled = () => {
        if (cookies["theme"] === "dark") setCookie("theme", "light", { path: "/", expires: date });
        else { setCookie("theme", "dark", { path: "/", expires: date }); }
        props.changeTheme();
    };

    const changeLanguage = (lang: string) => {
        LocalizationService.localize(lang);
        setCookie("language", lang, { path: "/", expires: date });
        props.changeLanguage(lang);
    };
    
    const wrapIconStyle = { backgroundColor: theme.palette.themeSecondary, borderRadius: '35%', minWidth: 30, minHeight: 30, display: 'inline-block', textAlign: 'center', justifyContent: 'center', verticalAlign: 'middle' } as React.CSSProperties;
    const iconStyle = { color: theme.palette.white, fontSize: '17px', marginTop: 6 };
    
    const buttonStyle = { maxWidth: '270px', boxShadow: theme.effects.elevation8 };
    const buttonIconProps: IIconProps = { iconName: 'ChevronRightSmall', styles: { root: { fontSize: 12 } } };

    /* Theme palette code */
    const colorCells: any[] = palettes.map(x => ({ id: x.id, label: x.label, color: x.palette?.themePrimary }));
    const resetColorIcon: IIconProps = { iconName: 'SyncOccurence' };
    const calloutPropsResetColor = { gapSpace: 10 };
    const hostStylesResetColor: Partial<ITooltipHostStyles> = { root: { display: 'inline-block' } };

    return (
        <footer style={{ backgroundColor: theme.palette.neutralQuaternaryAlt, borderTop: '1px solid', borderColor: theme.palette.neutralLight }} className="pt-4 pb-4">
            <Container style={{ width: '100%', color: theme.palette.neutralSecondary }}>

                <Row className="mb-4">
                    <Col xl={4} lg={4} md={6} sm={12} xs={12} className="mb-4 mb-md-0">
                        <div className="mb-2">
                            <Text styles={semibold} style={{ color: theme.palette.themePrimary }} variant="large">
                                &copy; Network StudentiUniMi
                            </Text>
                        </div>

                        <div className="mb-2 text">
                            <PrimaryButton text={locale?.footer[0].buttonText} iconProps={buttonIconProps} href="https://t.me/unimichat" className="text-decoration-none" allowDisabledFocus style={buttonStyle} />
                        </div>
                    </Col>
                    

                    <Col xl={2} lg={2} md={3} sm={12} xs={12} className="mb-2 mb-md-0">
                        <div>
                            <div className="mb-2">
                                <Text styles={semibold} variant="medium">{locale?.footer[1].header}</Text>
                            </div>

                            <div>
                                <Text variant="medium">
                                    <ul className="list-unstyled mb-3">
                                        <li style={listElement}>
                                            <Link href="http://www.quickunimi.it/">QuickUnimi</Link>
                                        </li>
                                        <li style={listElement}>
                                            <Link href="https://codeshare.tech">Codeshare.tech</Link>
                                        </li>
                                    </ul>
                                </Text>
                            </div>
                        </div>
                    </Col>
                    
                    <Col xl={3} lg={2} md={3} sm={12} xs={12}>
                        <div className="mb-2">
                            <Toggle
                                label={locale?.settingsPanel.changeTheme}
                                onText={locale?.settingsPanel.darkTheme}
                                offText={locale?.settingsPanel.lightTheme}
                                checked={cookies["theme"] === "dark"}
                                onChange={themeToggled}
                                theme={theme}
                            />
                        </div>
                        
                        <div className="mb-2 language-selector">
                            <Label>{locale?.settingsPanel.selectLanguage}</Label>
                            <Text 
                                variant="medium" 
                                style={{ cursor: 'pointer' }} 
                                styles={cookies["language"] === "it" ? bold : {}} onClick={() => { changeLanguage("it") } }
                            >
                                ITA
                            </Text>
                            
                            <Text variant="medium"> | </Text>

                            <Text 
                                variant="medium" 
                                style={{ cursor: 'pointer' }} 
                                styles={cookies["language"] === "en" ? bold : {}} onClick={() => { changeLanguage("en") }}
                            >
                                ENG
                            </Text>
                        </div>
                    </Col>

                    <Col xl={3} lg={4} md={6} sm={12} xs={12}>
                        <div>
                            <Text variant="medium" styles={semibold}>{locale?.settingsPanel.selectColor}  </Text>
                            <TooltipHost
                                content="Reset color"
                                calloutProps={calloutPropsResetColor}
                                styles={hostStylesResetColor}
                            >
                                <IconButton iconProps={resetColorIcon} onClick={() => { setCookie("palette", 'a', { path: "/", expires: date }); props.changePalette('a'); }} />
                            </TooltipHost>
                            <SwatchColorPicker selectedId={cookies["palette"]} columnCount={7} cellShape={'square'} colorCells={colorCells} onColorChanged={(id) => { setCookie("palette", id, { path: "/", expires: date }); props.changePalette(id!); }} />
                        </div>
                    </Col>
                
                </Row>


                <Row>
                    <Col lg={6} sm={12} style={{ display: 'table' }} className="center-mobile mb-2">
                        <Text variant="medium"  style={{  display: 'table-cell', verticalAlign: 'middle' }}>
                            {locale?.footer[0].text}
                        </Text>
                    </Col>

                    <Col lg={6} sm={12}>
                        <div className="mb-1 text-right center-mobile">
                            {footerIcons.map( (x: any, i: number) => { 
                                return (
                                    <TooltipHost
                                        content={x.name[language!]}
                                        calloutProps={calloutPropsResetColor}
                                        styles={hostStylesResetColor}
                                        key={i}
                                        delay={TooltipDelay.zero}
                                    >
                                        <Link href={x.link}>
                                            <span style={wrapIconStyle} className="text-decoration mr-1">
                                                { x.type === 'brand' ?
                                                <FontAwesomeIcon icon={['fab', x.iconName]} style={iconStyle} />
                                                :
                                                <FontAwesomeIcon icon={x.iconName} style={iconStyle} /> }
                                            </span>
                                        </Link>
                                    </TooltipHost>
                                )}
                            )}
                        </div>
                    </Col>

                </Row>

            </Container>
        </footer>
    )
}
Example #2
Source File: GenericObjectEditor.tsx    From sp-site-designs-studio with MIT License 4 votes vote down vote up
export function PropertyEditor(props: IPropertyEditorProps) {
    let { schema,
        label,
        readonly,
        required,
        value,
        onChange } = props;

    const onDropdownChange = ((ev: any, v: IDropdownOption) => {
        onChange(v.key);
    });

    const onNumberInputChange = ((ev: any, v: any) => {
        if (typeof (v) === "number") {
            onChange(v);
        } else {
            const number = parseFloat(v as string);
            onChange(number);
        }
    });

    const onInputChange = ((ev: any, v: any) => {
        onChange(v);
    });

    if (schema.enum) {
        if (schema.enum.length > 1 && !readonly) {
            return (
                <Dropdown
                    required={required}
                    label={label}
                    selectedKey={value}
                    options={schema.enum.map((p) => ({ key: p, text: p }))}
                    onChange={onDropdownChange}
                />
            );
        } else {
            return (
                <TextField
                    label={label}
                    value={value}
                    readOnly={true}
                    required={required}
                    onChange={onInputChange}
                />
            );
        }
    } else {
        switch (schema.type) {
            case 'boolean':
                return (
                    <Toggle
                        label={label}
                        checked={value as boolean}
                        disabled={readonly}
                        onChange={onInputChange}
                    />
                );
            case 'array':
                return <>
                    <Label>{label}</Label>
                    <GenericArrayEditor
                        object={value}
                        schema={schema.items}
                        onObjectChanged={onChange} />
                </>;
            case 'object': // TODO If object is a simple dictionary (key/non-complex object values) => Display a custom control
                // return <GenericObjectEditor
                //     object={value}
                //     schema={schema}
                //     onObjectChanged={onChange}
                // />;
                return <div>
                    <Label>{label}</Label>
                    <MessageBar messageBarType={MessageBarType.info}>{`This value of this property must be a complex object. Please use code editor to edit it`}</MessageBar>
                </div>;
            case 'number':
                return (
                    <TextField
                        required={required}
                        label={label}
                        value={value}
                        readOnly={readonly}
                        onChange={onNumberInputChange}
                    />
                );
            case 'string':
            default:
                return (
                    <TextField
                        required={required}
                        label={label}
                        value={value}
                        readOnly={readonly}
                        onChange={onInputChange}
                    />
                );
        }
    }
}
Example #3
Source File: SiteScriptDesigner.tsx    From sp-site-designs-studio with MIT License 4 votes vote down vote up
SiteScriptActionDesignerBlock = (props: ISiteScriptActionDesignerBlockProps) => {

    const [appContext] = useAppContext<IApplicationState, ActionType>();

    // Get service references
    const siteScriptSchemaService = appContext.serviceScope.consume(SiteScriptSchemaServiceKey);
    const rendering = appContext.serviceScope.consume(RenderingServiceKey);
    const [seeMore, setSeeMore] = useState<boolean>(false);
    const [isSortingSubactions, setIsSortingSubactions] = useState<boolean>(false);


    const getActionDescription = () => siteScriptSchemaService.getActionDescription(props.siteScriptAction, props.parentSiteScriptAction);
    const getActionLabel = () => siteScriptSchemaService.getActionTitle(props.siteScriptAction, props.parentSiteScriptAction);
    const getAddableActions = () => {
        const groupLabel = `${getActionLabel()} - Subactions`;
        return {
            [groupLabel]: siteScriptSchemaService.getAvailableSubActions(props.siteScriptAction).map(a => ({
                group: groupLabel,
                iconName: "SetAction",
                key: a.verb,
                text: a.label,
                item: a
            } as IAddableItem))
        };
    };

    const toggleEdit = () => {
        props.onSiteScriptContentUIChanged(props.siteScriptContentUI.toggleEditing(props.siteScriptAction));
    };

    const onActionUpdated = (siteScriptAction: ISiteScriptActionUIWrapper) => {
        props.onSiteScriptContentUIChanged(props.siteScriptContentUI.replaceAction(siteScriptAction));
    };

    const onActionAdded = (verb: string, parentSiteScriptAction?: ISiteScriptActionUIWrapper) => {
        const newAction = parentSiteScriptAction
            ? siteScriptSchemaService.getNewSubActionFromVerb(parentSiteScriptAction.verb, verb)
            : siteScriptSchemaService.getNewActionFromVerb(verb);
        const updatedContentUI = parentSiteScriptAction
            ? props.siteScriptContentUI.addSubAction(parentSiteScriptAction, newAction)
            : props.siteScriptContentUI.addAction(newAction);
        props.onSiteScriptContentUIChanged(updatedContentUI);
    };

    const onActionRemoved = (removedAction: ISiteScriptActionUIWrapper, parentSiteScriptAction?: ISiteScriptActionUIWrapper) => {
        const updatedContentUI = parentSiteScriptAction
            ? props.siteScriptContentUI.removeSubAction(parentSiteScriptAction, removedAction)
            : props.siteScriptContentUI.removeAction(removedAction);
        props.onSiteScriptContentUIChanged(updatedContentUI);
    };

    const renderSummaryContent = (() => {
        const summaryValues = siteScriptSchemaService.getPropertiesAndValues(props.siteScriptAction, props.parentSiteScriptAction);
        if (!seeMore) {
            const previewSummary = summaryValues.slice(0, SEE_PROPERTIES_DEFAULT_COUNT);
            const displaySeeMoreLink = summaryValues.length >= SEE_PROPERTIES_DEFAULT_COUNT && !seeMore;
            return <ul>
                {previewSummary.map((pv, index) => <li key={`${props.siteScriptAction.$uiKey}_prop_${index}`}>{pv.property}: <strong title={pv.value}>{(!pv.value && pv.value !== false) ? "Not set" : getTrimmedText(pv.value, SUMMARY_VALUE_MAX_LEN)}</strong></li>)}
                {displaySeeMoreLink && <li key={`${props.siteScriptAction.$uiKey}_more_prop`}><Link onClick={() => setSeeMore(true)}>...</Link></li>}
            </ul>;
        } else {
            return <ul>
                {summaryValues.map((pv, index) => <li key={`${props.siteScriptAction.$uiKey}_prop_${index}`}>{pv.property}: <strong title={pv.value}>{!pv.value ? "Not set" : getTrimmedText(pv.value, SUMMARY_VALUE_MAX_LEN)}</strong></li>)}
            </ul>;
        }
    });

    const DragHandle = SortableHandle(() =>
        <div>
            <Icon iconName={props.index === (props.actionsCount - 1) ? "SortUp" : props.index === 0 ? "SortDown" : "Sort"} />
        </div>
    );

    const onSubActionSortChanged = (args: ISortEndEventArgs) => {
        props.onSiteScriptContentUIChanged(props.siteScriptContentUI.reorderSubActions(props.siteScriptAction.$uiKey, args.newIndex, args.oldIndex));
    };


    const toggleSortingSubactions = () => {
        if (!isSortingSubactions) {
            setTimeout(() => {
                props.onSiteScriptContentUIChanged(props.siteScriptContentUI.clearEditing([props.parentSiteScriptAction.$uiKey]));
            }, 0);
        }
        setIsSortingSubactions(!isSortingSubactions);
    };

    const renderScriptSubAction = (scriptActionUI: ISiteScriptActionUIWrapper, index: number) => {

        const scriptActionBlock = <SiteScriptActionDesignerBlock key={scriptActionUI.$uiKey}
            siteScriptAction={scriptActionUI}
            parentSiteScriptAction={props.siteScriptAction}
            siteScriptContentUI={props.siteScriptContentUI}
            onSiteScriptContentUIChanged={props.onSiteScriptContentUIChanged}
            isSorting={isSortingSubactions}
            index={index}
            actionsCount={(props.siteScriptAction
                && props.siteScriptAction.subactions
                && props.siteScriptAction.subactions.length) || 0}
        />;

        if (isSortingSubactions) {
            const SortableItem = SortableElement(() => scriptActionBlock);
            return <SortableItem key={scriptActionUI.$uiKey} index={index} />;
        } else {
            return scriptActionBlock;
        }
    };

    const renderScriptSubActionsList = () => {
        if (!props.siteScriptAction.subactions) {
            return null;
        }

        if (isSortingSubactions) {
            const SortableListContainer = SortableContainer(({ items }) => {
                return <div>{items.map(renderScriptSubAction)}</div>;
            });

            return <SortableListContainer
                items={props.siteScriptAction.subactions}
                // onSortStart={(args) => this._onSortStart(args)}
                onSortEnd={(args: any) => onSubActionSortChanged(args)}
                lockToContainerEdges={true}
                useDragHandle={false}
            />;
        } else {
            return <div>{props.siteScriptAction.subactions.map(renderScriptSubAction)}</div>;
        }
    };



    const hasSubActions = siteScriptSchemaService.hasSubActions(props.siteScriptAction);
    const isEditing = props.siteScriptContentUI.editingActionKeys.indexOf(props.siteScriptAction.$uiKey) >= 0;
    return <div className={`${styles.siteScriptAction} ${isEditing ? styles.isEditing : ""} ${props.isSorting ? styles.isSorting : ''}`}>
        <h4 title={getActionDescription()}>
            {props.isSorting && <span className={styles.sortIndex}>{props.index + 1}</span>}
            <span className={styles.actionLabelText}>{getActionLabel()}</span>
        </h4>
        <div className={styles.tools}>
            <Stack horizontal tokens={{ childrenGap: 3 }}>
                {!isEditing && props.isSorting && <DragHandle />}
                {!props.isSorting && <IconButton iconProps={{ iconName: isEditing ? "Accept" : "Edit" }} onClick={() => toggleEdit()} />}
                {!props.isSorting && !isEditing && <IconButton iconProps={{ iconName: "Delete" }} onClick={() => onActionRemoved(props.siteScriptAction, props.parentSiteScriptAction)} />}
            </Stack>
        </div>
        <div className={`${styles.summary} ${!isEditing || isSortingSubactions ? styles.isNotEditing : styles.isEditing}`}>
            {renderSummaryContent()}
        </div>
        {isEditing && <div className={`${styles.properties} ${isEditing ? styles.isEditing : ""}`}>
            {rendering.renderActionProperties(props.siteScriptAction,
                props.parentSiteScriptAction,
                (o) => onActionUpdated({ ...props.siteScriptAction, ...o } as ISiteScriptActionUIWrapper), ['verb', 'subactions', '$uiKey', '$isEditing'])}
            {hasSubActions && <div className={styles.subactions}>
                <div className={styles.row}>
                    <div className={styles.column10}>
                        <Label>Subactions</Label>
                    </div>
                    <div className={styles.column2}>
                        {props.siteScriptAction.subactions && props.siteScriptAction.subactions.length > 1 && <IconButton iconProps={{ iconName: "Sort" }}
                            // styles={{ root: { position: "absolute", top: -32, right: 9 } }}
                            checked={isSortingSubactions}
                            onClick={toggleSortingSubactions} />}
                    </div>
                </div>
                {renderScriptSubActionsList()}
                {!isSortingSubactions && <Adder items={getAddableActions()}
                    searchBoxPlaceholderText="Search a sub action..."
                    onSelectedItem={(item) => onActionAdded(item.key, props.siteScriptAction)} />}
            </div>}
        </div>}
    </div>;
}
Example #4
Source File: RenderingService.tsx    From sp-site-designs-studio with MIT License 4 votes vote down vote up
public renderActionProperty(siteScriptAction: ISiteScriptAction, parentSiteScriptAction: ISiteScriptAction, propertyName: string, value: any, onChanged: (value: any) => void, ignoredProperties: string[]): JSX.Element {
        if (!siteScriptAction) {
            throw new Error("action verb is not defined");
        }
        const mainActionVerb = parentSiteScriptAction ? parentSiteScriptAction.verb : siteScriptAction.verb;
        const subActionVerb = parentSiteScriptAction ? siteScriptAction.verb : null;

        if (propertyName == "subactions") {
            if (subActionVerb) {
                throw new Error("Subactions cannot have subactions");
            }

            const subactions: ISiteScriptAction[] = siteScriptAction.subactions;
            return <>
                <Label>Subactions</Label>
                {subactions.map((sa, index) => this.renderActionProperties(sa, siteScriptAction, (changedSubAction) => {
                    const updatedSubActions = (subactions).map((usa, updatedIndex) => updatedIndex == index ? changedSubAction : usa);
                    onChanged(updatedSubActions);
                }, ignoredProperties))}
            </>;
        }

        let actionSchema: IPropertySchema = null;

        if (subActionVerb) {
            actionSchema = this._ensureSubActionPropertySchema(mainActionVerb, subActionVerb);
        } else {
            actionSchema = this._ensureActionPropertySchema(mainActionVerb);
        }
        if (!actionSchema) {
            console.warn("Action schema could not be resolved");
            return null;
        }

        let isPropertyRequired = (actionSchema.required
            && actionSchema.required.length
            && actionSchema.required.indexOf(propertyName) > -1) || false;

        const propertySchema = actionSchema.properties[propertyName];
        const propertyLabel = this._getActionPropertyLabel(mainActionVerb, subActionVerb, propertyName, propertySchema);
        let content: JSX.Element = null;
        // Get the rendering config for main action (if any)
        const mainActionRenderingConfig = this._registeredActionPropertyRenderingOptions[mainActionVerb];
        if (subActionVerb) {
            // If the current action is a subaction
            // Get the rendering config for sub action (if any)
            const subActionRenderingConfig = mainActionRenderingConfig
                && mainActionRenderingConfig.subactions
                && mainActionRenderingConfig.subactions[subActionVerb];
            // If there is no rendering config for current action and property
            if (!subActionRenderingConfig || subActionRenderingConfig.propertyName != propertyName) {
                // Use default property editor
                content = <PropertyEditor
                    value={siteScriptAction[propertyName]}
                    required={isPropertyRequired}
                    onChange={onChanged}
                    label={propertyLabel}
                    schema={propertySchema}
                />;
            } else {
                // Otherwise, use the specified renderer
                content = subActionRenderingConfig.renderer(propertyLabel, value, onChanged);
            }
        } else {
            // If the current action is a main action
            // If there is no rendering config for current action and property
            if (!mainActionRenderingConfig || mainActionRenderingConfig.propertyName != propertyName) {
                // Use default property editor
                content = <PropertyEditor
                    value={siteScriptAction[propertyName]}
                    required={isPropertyRequired}
                    onChange={onChanged}
                    label={propertyLabel}
                    schema={propertySchema}
                />;
            } else {
                // Otherwise, use the specified renderer
                content = mainActionRenderingConfig.renderer(propertyLabel, value, onChanged);
            }
        }
        return content;
    }
Example #5
Source File: SiteScriptEditor.tsx    From sp-site-designs-studio with MIT License 3 votes vote down vote up
SiteScriptEditor = (props: ISiteScriptEditorProps) => {
    useTraceUpdate('SiteScriptEditor', props);
    const [appContext, execute] = useAppContext<IApplicationState, ActionType>();

    // Get service references
    const siteDesignsService = appContext.serviceScope.consume(SiteDesignsServiceKey);
    const siteScriptSchemaService = appContext.serviceScope.consume(SiteScriptSchemaServiceKey);
    const exportService = appContext.serviceScope.consume(ExportServiceKey);

    const [state, dispatchState] = useReducer(SiteScriptEditorReducer, {
        siteScriptMetadata: null,
        siteScriptContent: null,
        currentExportPackage: null,
        currentExportType: "json",
        isExportUIVisible: false,
        isSaving: false,
        isAssociatingToSiteDesign: false,
        isValidCode: true,
        updatedContentFrom: null
    });
    const { siteScriptMetadata,
        siteScriptContent,
        isValidCode,
        isExportUIVisible,
        currentExportType,
        currentExportPackage,
        isAssociatingToSiteDesign,
        isSaving } = state;

    // Use refs
    const codeEditorRef = useRef<any>();
    const titleFieldRef = useRef<any>();
    const selectedSiteDesignRef = useRef<string>();


    const setLoading = (loading: boolean) => {
        execute("SET_LOADING", { loading });
    };
    // Use Effects
    useEffect(() => {
        if (!props.siteScript.Id) {
            dispatchState({ type: "SET_SITE_SCRIPT", siteScript: props.siteScript });

            if (titleFieldRef.current) {
                titleFieldRef.current.focus();
            }
            return;
        }

        setLoading(true);
        console.debug("Loading site script...", props.siteScript.Id);
        siteDesignsService.getSiteScript(props.siteScript.Id).then(loadedSiteScript => {
            dispatchState({ type: "SET_SITE_SCRIPT", siteScript: loadedSiteScript });
            console.debug("Loaded: ", loadedSiteScript);
        }).catch(error => {
            console.error(`The Site Script ${props.siteScript.Id} could not be loaded`, error);
        }).then(() => {
            setLoading(false);
        });
    }, [props.siteScript]);

    const onTitleChanged = (ev: any, title: string) => {
        const siteScript = { ...siteScriptMetadata, Title: title };
        dispatchState({ type: "UPDATE_SITE_SCRIPT_METADATA", siteScript });
    };

    let currentDescription = useRef<string>(siteScriptMetadata && siteScriptMetadata.Description);
    const onDescriptionChanging = (ev: any, description: string) => {
        currentDescription.current = description;
    };

    const onDescriptionInputBlur = (ev: any) => {
        const siteScript = { ...siteScriptMetadata, Description: currentDescription.current };
        dispatchState({ type: "UPDATE_SITE_SCRIPT_METADATA", siteScript });
    };

    const onVersionChanged = (ev: any, version: string) => {
        const versionInt = parseInt(version);
        if (!isNaN(versionInt)) {
            const siteScript = { ...siteScriptMetadata, Version: versionInt };
            dispatchState({ type: "UPDATE_SITE_SCRIPT_METADATA", siteScript });
        }
    };

    const onSiteScriptContentUpdatedFromUI = (content: ISiteScriptContent) => {
        dispatchState({ type: "UPDATE_SITE_SCRIPT_CONTENT", content, from: "UI" });
    };

    const onSave = async () => {
        dispatchState({ type: "SET_ISSAVING", isSaving: true });
        try {
            const isNewSiteScript = !siteScriptMetadata.Id;
            const toSave: ISiteScript = { ...siteScriptMetadata, Content: state.siteScriptContent };
            const updated = await siteDesignsService.saveSiteScript(toSave);
            const refreshedSiteScripts = await siteDesignsService.getSiteScripts();
            execute("SET_USER_MESSAGE", {
                userMessage: {
                    message: `${siteScriptMetadata.Title} has been successfully saved.`,
                    messageType: MessageBarType.success
                }
            } as ISetUserMessageArgs);
            execute("SET_ALL_AVAILABLE_SITE_SCRIPTS", { siteScripts: refreshedSiteScripts } as ISetAllAvailableSiteScripts);
            dispatchState({ type: "SET_SITE_SCRIPT", siteScript: updated });
            if (isNewSiteScript) {
                // Ask if the new Site Script should be associated to a Site Design
                if (await Confirm.show({
                    title: `Associate to Site Design`,
                    message: `Do you want to associate the new ${(siteScriptMetadata && siteScriptMetadata.Title)} to a Site Design ?`,
                    cancelLabel: 'No',
                    okLabel: 'Yes'
                })) {
                    dispatchState({ type: "SET_ISASSOCIATINGTOSITEDESIGN", isAssociatingToSiteDesign: true });
                }
            }
        } catch (error) {
            execute("SET_USER_MESSAGE", {
                userMessage: {
                    message: `${siteScriptMetadata.Title} could not be saved. Please make sure you have SharePoint administrator privileges...`,
                    messageType: MessageBarType.error
                }
            } as ISetUserMessageArgs);
            console.error(error);
        }
        dispatchState({ type: "SET_ISSAVING", isSaving: false });

    };

    const onDelete = async () => {
        if (!await Confirm.show({
            title: `Delete Site Script`,
            message: `Are you sure you want to delete ${(siteScriptMetadata && siteScriptMetadata.Title) || "this Site Script"} ?`
        })) {
            return;
        }

        dispatchState({ type: "SET_ISSAVING", isSaving: true });
        try {
            await siteDesignsService.deleteSiteScript(siteScriptMetadata);
            const refreshedSiteScripts = await siteDesignsService.getSiteScripts();
            execute("SET_USER_MESSAGE", {
                userMessage: {
                    message: `${siteScriptMetadata.Title} has been successfully deleted.`,
                    messageType: MessageBarType.success
                }
            } as ISetUserMessageArgs);
            execute("SET_ALL_AVAILABLE_SITE_SCRIPTS", { siteScripts: refreshedSiteScripts } as ISetAllAvailableSiteScripts);
            execute("GO_TO", { page: "SiteScriptsList" } as IGoToActionArgs);
        } catch (error) {
            execute("SET_USER_MESSAGE", {
                userMessage: {
                    message: `${siteScriptMetadata.Title} could not be deleted. Please make sure you have SharePoint administrator privileges...`,
                    messageType: MessageBarType.error
                }
            } as ISetUserMessageArgs);
            console.error(error);
        }
        dispatchState({ type: "SET_ISSAVING", isSaving: false });
    };

    const onAssociateSiteScript = () => {
        if (selectedSiteDesignRef.current != NEW_SITE_DESIGN_KEY) {
            execute("EDIT_SITE_DESIGN", { siteDesign: { Id: selectedSiteDesignRef.current }, additionalSiteScriptIds: [siteScriptMetadata.Id] });
        } else if (selectedSiteDesignRef.current) {
            execute("EDIT_SITE_DESIGN", { siteDesign: createNewSiteDesign(), additionalSiteScriptIds: [siteScriptMetadata.Id] });
        }
    };

    const onExportRequested = (exportType?: ExportType) => {
        const toExport: ISiteScript = { ...siteScriptMetadata, Content: siteScriptContent };
        let exportPromise: Promise<ExportPackage> = null;
        switch (exportType) {
            case "PnPPowershell":
                exportPromise = exportService.generateSiteScriptPnPPowershellExportPackage(toExport);
                break;
            case "PnPTemplate":
                break; // Not yet supported
            case "o365_PS":
                exportPromise = exportService.generateSiteScriptO365CLIExportPackage(toExport, "Powershell");
                break;
            case "o365_Bash":
                exportPromise = exportService.generateSiteScriptO365CLIExportPackage(toExport, "Bash");
                break;
            case "json":
            default:
                exportPromise = exportService.generateSiteScriptJSONExportPackage(toExport);
                break;
        }

        if (exportPromise) {
            exportPromise.then(exportPackage => {
                dispatchState({ type: "SET_EXPORTPACKAGE", exportPackage, exportType });
            });
        }
    };

    let codeUpdateTimeoutHandle: any = null;
    const onCodeChanged = (updatedCode: string) => {
        if (!updatedCode) {
            return;
        }

        if (codeUpdateTimeoutHandle) {
            clearTimeout(codeUpdateTimeoutHandle);
        }

        // if (updatedContentFrom == "UI") {
        //     // Not trigger the change of state if the script content was updated from UI
        //     console.debug("The code has been modified after a change in designer. The event will not be propagated");
        //     dispatchState({ type: "UPDATE_SITE_SCRIPT", siteScript: null, from: "CODE" });
        //     return;
        // }

        codeUpdateTimeoutHandle = setTimeout(() => {
            try {
                const jsonWithIgnoredComments = updatedCode.replace(/\/\*(.*)\*\//g,'');
                if (siteScriptSchemaService.validateSiteScriptJson(jsonWithIgnoredComments)) {
                    const content = JSON.parse(jsonWithIgnoredComments) as ISiteScriptContent;
                    dispatchState({ type: "UPDATE_SITE_SCRIPT_CONTENT", content, isValidCode: true, from: "CODE" });
                } else {
                    dispatchState({ type: "UPDATE_SITE_SCRIPT_CONTENT", content: null, isValidCode: false, from: "CODE" });

                }
            } catch (error) {
                console.warn("Code is not valid site script JSON");
            }
        }, 500);
    };

    const editorDidMount = (_, editor) => {

        const schema = siteScriptSchemaService.getSiteScriptSchema();
        codeEditorRef.current = editor;
        monaco.init().then(monacoApi => {
            monacoApi.languages.json.jsonDefaults.setDiagnosticsOptions({
                schemas: [{
                    uri: 'schema.json',
                    schema
                }],

                validate: true,
                allowComments: false
            });
        }).catch(error => {
            console.error("An error occured while trying to configure code editor");
        });

        const editorModel = editor.getModel();
        console.log("Editor model: ", editorModel);

        editor.onDidChangeModelContent(ev => {
            if (codeEditorRef && codeEditorRef.current) {
                onCodeChanged(codeEditorRef.current.getValue());
            }
        });
    };

    const checkIsValidForSave: () => [boolean, string?] = () => {
        if (!siteScriptMetadata) {
            return [false, "Current Site Script not defined"];
        }

        if (!siteScriptMetadata.Title) {
            return [false, "Please set the title of the Site Script..."];
        }

        if (!isValidCode) {
            return [false, "Please check the validity of the code..."];
        }

        return [true];
    };

    const isLoading = appContext.isLoading;
    const [isValidForSave, validationMessage] = checkIsValidForSave();
    if (!siteScriptMetadata || !siteScriptContent) {
        return null;
    }

    return <div className={styles.SiteScriptEditor}>
        <div className={styles.row}>
            <div className={styles.columnLayout}>
                <div className={styles.row}>
                    <div className={styles.column11}>
                        <TextField
                            styles={{
                                field: {
                                    fontSize: "32px",
                                    lineHeight: "45px",
                                    height: "45px"
                                },
                                root: {
                                    height: "60px",
                                    marginTop: "5px",
                                    marginBottom: "5px"
                                }
                            }}
                            placeholder="Enter the name of the Site Script..."
                            borderless
                            componentRef={titleFieldRef}
                            value={siteScriptMetadata.Title}
                            onChange={onTitleChanged} />
                        {isLoading && <ProgressIndicator />}
                    </div>
                    {!isLoading && <div className={`${styles.column1} ${styles.righted}`}>
                        <Stack horizontal horizontalAlign="end" tokens={{ childrenGap: 15 }}>
                            <CommandButton disabled={isSaving} iconProps={{ iconName: "More" }} menuProps={{
                                items: [
                                    (siteScriptMetadata.Id && {
                                        key: 'deleteScript',
                                        text: 'Delete',
                                        iconProps: { iconName: 'Delete' },
                                        onClick: onDelete
                                    }),
                                    {
                                        key: 'export',
                                        text: 'Export',
                                        iconProps: { iconName: 'Download' },
                                        onClick: () => onExportRequested(),
                                        disabled: !isValidForSave
                                    }
                                ].filter(i => !!i),
                            } as IContextualMenuProps} />
                            <PrimaryButton disabled={isSaving || !isValidForSave} text="Save" iconProps={{ iconName: "Save" }} onClick={() => onSave()} />
                        </Stack>
                    </div>}
                </div>
                <div className={styles.row}>
                    {siteScriptMetadata.Id && <div className={styles.half}>
                        <div className={styles.row}>
                            <div className={styles.column8}>
                                <TextField
                                    label="Id"
                                    readOnly
                                    value={siteScriptMetadata.Id} />
                            </div>
                            <div className={styles.column4}>
                                <TextField
                                    label="Version"
                                    value={siteScriptMetadata.Version.toString()}
                                    onChange={onVersionChanged} />
                            </div>
                        </div>
                    </div>}
                    <div className={styles.half}>
                        <TextField
                            label="Description"
                            value={siteScriptMetadata.Description}
                            multiline={true}
                            rows={2}
                            borderless
                            placeholder="Enter a description for the Site Script..."
                            onChange={onDescriptionChanging}
                            onBlur={onDescriptionInputBlur}
                        />
                    </div>
                </div>
                <div className={styles.row}>
                    <div className={styles.column}>
                        <Label>Actions</Label>
                    </div>
                </div>
                <div className={styles.row}>
                    <div className={styles.designerWorkspace}>
                        <SiteScriptDesigner
                            siteScriptContent={siteScriptContent}
                            onSiteScriptContentUpdated={onSiteScriptContentUpdatedFromUI} />
                    </div>
                    <div className={styles.codeEditorWorkspace}>
                        <CodeEditor
                            height="80vh"
                            language="json"
                            options={{
                                folding: true,
                                renderIndentGuides: true,
                                minimap: {
                                    enabled: false
                                }
                            }}
                            value={toJSON(siteScriptContent)}
                            editorDidMount={editorDidMount}
                        />
                    </div>
                </div>
            </div>
        </div>
        {/* Association to a Site Design */}
        <Panel isOpen={isAssociatingToSiteDesign}
            type={PanelType.smallFixedFar}
            headerText="Associate to a Site Design"
            onRenderFooterContent={(p) => <Stack horizontalAlign="end" horizontal tokens={{ childrenGap: 10 }}>
                <PrimaryButton iconProps={{ iconName: "Check" }} text="Continue" onClick={() => onAssociateSiteScript()} />
                <DefaultButton text="Cancel" onClick={() => dispatchState({ type: "SET_ISASSOCIATINGTOSITEDESIGN", isAssociatingToSiteDesign: false })} /></Stack>}
        >
            <SiteDesignPicker serviceScope={appContext.serviceScope}
                label="Site Design"
                onSiteDesignSelected={(siteDesignId) => {
                    console.log("Selected site design: ", siteDesignId);
                    selectedSiteDesignRef.current = siteDesignId;
                }}
                hasNewSiteDesignOption
                displayPreview />
        </Panel>
        {/* Export options */}
        <Panel isOpen={isExportUIVisible}
            type={PanelType.large}
            headerText="Export Site Script"
            onRenderFooterContent={(p) => <Stack horizontalAlign="end" horizontal tokens={{ childrenGap: 10 }}>
                <PrimaryButton iconProps={{ iconName: "Download" }} text="Download" onClick={() => currentExportPackage && currentExportPackage.download()} />
                <DefaultButton text="Cancel" onClick={() => dispatchState({ type: "SET_EXPORTPACKAGE", exportPackage: null })} /></Stack>}>
            <Pivot
                selectedKey={currentExportType}
                onLinkClick={(item) => onExportRequested(item.props.itemKey as ExportType)}
                headersOnly={true}
            >
                <PivotItem headerText="JSON" itemKey="json" />
                <PivotItem headerText="PnP Powershell" itemKey="PnPPowershell" />
                {/* <PivotItem headerText="PnP Template" itemKey="PnPTemplate" /> */}
                <PivotItem headerText="O365 CLI (Powershell)" itemKey="o365_PS" />
                <PivotItem headerText="O365 CLI (Bash)" itemKey="o365_Bash" />
            </Pivot>
            {currentExportPackage && <ExportPackageViewer exportPackage={currentExportPackage} />}
        </Panel>
    </div >;
}