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

[APPX-8397] Integrate optimizely code with Contentful's repo #1

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions apps/optimizely/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REACT_APP_OPTIMIZELY_CLIENT_APP_ID='15687650042'
3 changes: 2 additions & 1 deletion apps/optimizely/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ yarn-debug.log*
yarn-error.log*

# dotenv environment variables file
.env
.env.local

.contentfulrc.json

# Parcel-bundler cache
Expand Down
49,790 changes: 18,247 additions & 31,543 deletions apps/optimizely/package-lock.json

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions apps/optimizely/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.6.15",
"private": true,
"devDependencies": {
"@contentful/app-scripts": "^1.13.0",
"cross-env": "7.0.3"
},
"dependencies": {
Expand All @@ -18,17 +19,20 @@
"prop-types": "15.8.1",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-scripts": "5.0.1",
"react-scripts": "4.0.3",
"use-methods": "0.5.1",
"whatwg-fetch": "3.6.20"
"whatwg-fetch": "3.6.19"
},
"scripts": {
"start": "cross-env BROWSER=none react-scripts --openssl-legacy-provider start",
"build": "react-scripts --openssl-legacy-provider build",
"start": "cross-env BROWSER=none react-scripts start",
"build": "react-scripts build",
"build:local": "npm run env:local && npm run build",
"env:local": "echo REACT_APP_OPTIMIZELY_CLIENT_APP_ID=${REACT_APP_OPTIMIZELY_CLIENT_APP_ID} > .env.local",
"deploy": "aws s3 sync ./build ${STATIC_S3_BASE}/optimizely --acl public-read",
"create-app-definition": "contentful-app-scripts create-app-definition",
"deploy:test": "npm run deploy",
"test": "TZ=UTC react-scripts test",
"test:ci": "TZ=UTC CI=true react-scripts test"
"test:ci": "TZ=UTC react-scripts test"
},
"eslintConfig": {
"extends": "react-app"
Expand Down
4 changes: 4 additions & 0 deletions apps/optimizely/src/AppPage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ describe('AppPage', () => {
...basicProps.sdk,
space: {
getContentTypes: jest.fn(() => Promise.resolve(contentTypesData)),
updateContentType: () => {},
},
app: {
setReady: jest.fn(),
getParameters: jest.fn(() => Promise.resolve({ optimizelyProjectId: '123' })),
onConfigure: jest.fn((fn) => {
configFunc = fn;
}),
onConfigurationCompleted: () => {}
},
};

Expand Down Expand Up @@ -74,6 +76,7 @@ describe('AppPage', () => {
setReady: jest.fn(),
getParameters: jest.fn(() => Promise.resolve({ optimizelyProjectId: '123' })),
onConfigure: jest.fn((fn) => {}),
onConfigurationCompleted: () => {}
},
};
const props = { ...basicProps, sdk };
Expand All @@ -92,6 +95,7 @@ describe('AppPage', () => {
setReady: jest.fn(),
getParameters: jest.fn(() => Promise.resolve({ optimizelyProjectId: '123' })),
onConfigure: jest.fn((fn) => {}),
onConfigurationCompleted: () => {}
},
};
const props = { ...basicProps, accessToken: '123', sdk };
Expand Down
17 changes: 12 additions & 5 deletions apps/optimizely/src/AppPage/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { SkeletonContainer, SkeletonBodyText } from '@contentful/forma-36-react-
import SectionSplitter from '../EditorPage/subcomponents/section-splitter';
import Projects from './Projects';
import ContentTypes from './ContentTypes';
import { ProjectType } from '../constants';

export default class Config extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -32,9 +33,15 @@ export default class Config extends React.Component {
});
}

onProjectChange = (event) => {
onProjectChange = (allProjects, event) => {
const projectId = event.target.value;
const project = allProjects.find((p) => String(p.id) === projectId);
const projectType = project['is_flags_enabled']
? ProjectType.FeatureExperimentation : ProjectType.FullStack;

this.props.updateConfig({
optimizelyProjectId: event.target.value,
optimizelyProjectId: projectId,
optimizelyProjectType: projectType,
});
};

Expand Down Expand Up @@ -72,7 +79,7 @@ export default class Config extends React.Component {
);

render() {
const { loadingProjects } = this.state;
const { loadingProjects, allProjects } = this.state;

const { contentTypes } = this.props.config;
const addedContentTypes = Object.keys(contentTypes);
Expand All @@ -83,8 +90,8 @@ export default class Config extends React.Component {
this.renderLoader()
) : (
<Projects
allProjects={this.state.allProjects}
onProjectChange={this.onProjectChange}
allProjects={allProjects}
onProjectChange={(event) => this.onProjectChange(allProjects, event)}
selectedProject={this.props.config.optimizelyProjectId}
/>
)}
Expand Down
2 changes: 0 additions & 2 deletions apps/optimizely/src/AppPage/Projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { css } from 'emotion';
import tokens from '@contentful/forma-36-tokens';
import {
Heading,
Paragraph,
SelectField,
Option,
Typography,
Expand All @@ -21,7 +20,6 @@ export default function Projects({ allProjects, selectedProject, onProjectChange
return (
<Typography>
<Heading>Optimizely Project</Heading>
<Paragraph>Works only with Optimizely Full Stack projects</Paragraph>
<SelectField
name="project"
id="project"
Expand Down
89 changes: 82 additions & 7 deletions apps/optimizely/src/AppPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { Heading, Typography, Paragraph } from '@contentful/forma-36-react-compo

import Connect from './Connect';
import Config from './Config';
import OptimizelyLogo from './OptimizelyLogo';
// import OptimizelyLogo from './OptimizelyLogo';
import OptimizelyLogo from '../optimizely-logo';
import SectionSplitter from '../EditorPage/subcomponents/section-splitter';
import { VARIATION_CONTAINER_ID } from './constants';
import { colors } from '../constants';

const styles = {
body: css({
Expand Down Expand Up @@ -63,6 +65,7 @@ export default class AppPage extends React.Component {
this.state = {
config: {
optimizelyProjectId: '',
optimizelyProjectType: '',
contentTypes: {},
},
allContentTypes: [],
Expand All @@ -88,20 +91,26 @@ export default class AppPage extends React.Component {
optimizelyProjectId: currentParameters
? currentParameters.optimizelyProjectId
: prevState.optimizelyProjectId,
optimizelyProjectType: currentParameters
? currentParameters.optimizelyProjectType
: prevState.optimizelyProjectType,
},
}),
() => app.setReady()
);

app.onConfigure(this.configureApp);
app.onConfigurationCompleted(() => {
this.props.sdk.navigator.openEntriesList();
});
}

configureApp = async () => {
if (!this.props.accessToken) {
this.props.sdk.notifier.error(`You must be connected to Optimizely to configure the app.`);
return false;
}

const { config } = this.state;

if (!config.optimizelyProjectId) {
Expand All @@ -111,12 +120,27 @@ export default class AppPage extends React.Component {
return false;
}

const needsVariationContainerInSpace = !this.state.allContentTypes.find(
const variationContainerContentType = this.state.allContentTypes.find(
(ct) => ct.sys.id === VARIATION_CONTAINER_ID
);

if (needsVariationContainerInSpace) {
if (!variationContainerContentType) {
await this.createVariationContainerContentType();
} else {
const flagKeyField = variationContainerContentType.fields.find((f) => f.id === 'flagKey');
const environmentField = variationContainerContentType.fields.find((f) => f.id === 'environment');
const revisionField = variationContainerContentType.fields.find((f) => f.id === 'revision');


if (!flagKeyField || !environmentField) {
await this.updateVariationContainerContentType(
variationContainerContentType, {
addFlagKey: !flagKeyField,
addEnvironment: !environmentField,
addRevision: !revisionField,
}
);
}
}

const res = await this.saveEnabledContentTypes(
Expand All @@ -132,10 +156,11 @@ export default class AppPage extends React.Component {
this.props.sdk.notifier.error('Something went wrong, please try again.');
return false;
}

return {
parameters: {
optimizelyProjectId: config.optimizelyProjectId,
optimizelyProjectType: config.optimizelyProjectType,
},
targetState: {
EditorInterface: {
Expand Down Expand Up @@ -183,12 +208,62 @@ export default class AppPage extends React.Component {
name: 'Experiment Key',
type: 'Symbol',
},
{
id: 'flagKey',
name: 'Flag Key',
type: 'Symbol',
},
{
id: 'environment',
name: 'Environment Key',
type: 'Symbol',
},
{
id: 'revision',
name: 'Revision ID',
type: 'Symbol',
omitted: true,
},
],
});

await this.props.sdk.space.updateContentType(variationContainer);
};

updateVariationContainerContentType = async (variationContainer, opt) => {
const { addFlagKey, addEnvironment, addRevision } = opt;
if (addFlagKey) {
variationContainer.fields.push(
{
id: 'flagKey',
name: 'Flag Key',
type: 'Symbol',
},
);
}

if (addEnvironment) {
variationContainer.fields.push(
{
id: 'environment',
name: 'Environment Key',
type: 'Symbol',
},
);
}

if (addRevision) {
variationContainer.fields.push({
id: 'revision',
name: 'Revision ID',
type: 'Symbol',
omitted: true,
});
}

await this.props.sdk.space.updateContentType(variationContainer);
};

saveEnabledContentTypes = async (contentTypes, allContentTypes) => {
const copyAllCts = JSON.parse(JSON.stringify(allContentTypes));
const output = [];
Expand Down Expand Up @@ -319,7 +394,7 @@ export default class AppPage extends React.Component {
)}
</div>
<div className={styles.logo}>
<OptimizelyLogo />
<OptimizelyLogo width={60} height={60} arccolor={colors.optimizelyBlue}/>
</div>
</>
);
Expand Down
26 changes: 26 additions & 0 deletions apps/optimizely/src/ConnectButton/AuthButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react"
import OptimizelyLogo from "../optimizely-logo";
import { colors } from "../constants";
const AuthButton = (props) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox='0 0 200 40'
width={200} height={40}
{...props}
>
<title>
ConnectWithOptimizelyButton
</title>
<rect width="200" height="40" x="0" y="0" rx="6" ry="6" fill={colors.optimizelyBlue}/>
<g transform={"translate(5, 9)"}>
<OptimizelyLogo width={"25"} height={"25"} arccolor={colors.white}/>
</g>
<g transform={"translate(32, 22)"}>
<text x={0} y ={5} fill={'white'}> Connect with Optimizely </text>
</g>
</svg>
)
};

export default AuthButton;
7 changes: 5 additions & 2 deletions apps/optimizely/src/ConnectButton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import PropTypes from 'prop-types';
import { css } from 'emotion';
import { Button } from '@contentful/forma-36-react-components';

import OptimizelyLogo from './OptimizelyLogo';
// import OptimizelyLogo from './OptimizelyLogo';

// import OptimizelyLogo from '../optimizely-logo';
import AuthButton from './AuthButton';

const styles = {
connect: css({
Expand All @@ -24,7 +27,7 @@ export default function ConnectButton({ openAuth }) {
testId="connect-button"
isFullWidth
buttonType="naked">
<OptimizelyLogo />
<AuthButton/>
</Button>
);
}
Expand Down
6 changes: 4 additions & 2 deletions apps/optimizely/src/EditorPage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ describe('EditorPage', () => {
sdk = { ...sdk, space };

sdk.entry.fields.experimentTitle.setValue = jest.fn();
sdk.entry.fields.experimentId.onValueChanged = (fn) => {
sdk.entry.fields.experimentKey.onValueChanged = (fn) => {
valueChange = fn;
return () => {};
};

const client = {
getProject: () => Promise.resolve(mockVariantData.project),
getProjectEnvironments: () => Promise.resolve(mockVariantData.environments),
getExperiments: () => Promise.resolve(mockVariantData.experiments),
getResultsUrl: (campaignUrl, experimentId) => {
return `https://app.optimizely.com/v2/projects/123/results/${campaignUrl}/experiments/${experimentId}`;
Expand All @@ -61,7 +63,7 @@ describe('EditorPage', () => {
);

await wait();
valueChange('15049730511');
valueChange('landing-page-hero');

await wait();

Expand Down
Loading