Skip to content
Draft
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
56 changes: 56 additions & 0 deletions actions/favorite/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
const { asGenericAction } = require('../GenericAction.js');
const { asAuthAction } = require('../AuthAction.js');

const { AppError } = require('../../web-src/src/helpers/ErrorMapper.js');

const wretch = require('wretch');

async function main(params) {
const { data } = params;
try {
// data is an array of objects,
// iterate over each object and make a POST reuest to the API endpoing
// https://hook.app.workfrontfusion.com/cytq82vrakjn5p8xtaashn6gm2qc3jif
// with the data object as the body
// return the response from the API
results = []

console.log('saving new variations ...');

for (const variant of data) {
let r = await wretch(`https://hook.app.workfrontfusion.com/cytq82vrakjn5p8xtaashn6gm2qc3jif`)
.headers({
'Content-Type': 'application/json',
})
.post({
data: variant
})
.json();
results.push(r);
}

return {
statusCode: 200,
body: {
message: 'Favorites updated in API',
results: results
}
};
} catch (error) {
throw new AppError(error, 'FUSION');
}
}

//exports.main = asAuthAction(asGenericAction(main));
exports.main = asGenericAction(main);
12 changes: 12 additions & 0 deletions app.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@ application:
IMS_PRODUCT_CONTEXT: $IMS_PRODUCT_CONTEXT
limits:
timeout: 180000
favorite:
function: actions/favorite/index.js
web: true
runtime: nodejs:18
inputs:
LOG_LEVEL: debug
IMS_ENDPOINT: $IMS_ENDPOINT
IMS_CLIENT_ID: $IMS_CLIENT_ID
IMS_PRODUCT_CONTEXT: $IMS_PRODUCT_CONTEXT
limits:
timeout: 180000

8 changes: 8 additions & 0 deletions web-src/src/components/ApplicationProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import React, {
} from 'react';
import { useSetRecoilState } from 'recoil';
import { FirefallService } from '../services/FirefallService.js';
import { RemoteFavoritesService } from '../services/RemoteFavoritesService.js';
import actions from '../config.json';
import { useShellContext } from './ShellProvider.js';
import { loadPromptTemplates, promptTemplatesState } from '../state/PromptTemplatesState.js';
Expand All @@ -22,6 +23,7 @@ const APP_VERSION = process.env.REACT_APP_VERSION || 'unknown';

const COMPLETE_ACTION = 'complete';
const FEEDBACK_ACTION = 'feedback';
const FAVORITE_ACTION = 'favorite';

const PROMPTS_TEMPLATES_PARAM_NAME = 'prompts';

Expand Down Expand Up @@ -70,6 +72,12 @@ export const ApplicationProvider = ({ children }) => {
imsOrg: user.imsOrg,
accessToken: user.imsToken,
}),
remoteFavoritesService: new RemoteFavoritesService({
favoritesEndpoint: actions[FAVORITE_ACTION],
imsOrg: user.imsOrg,
accessToken: user.imsToken,
websiteUrl,
}),
});

loadPromptTemplates(websiteUrl, promptTemplatesPath).then((templates) => {
Expand Down
49 changes: 49 additions & 0 deletions web-src/src/services/RemoteFavoritesService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2023 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import { wretchRetry } from '../helpers/NetworkHelper.js';
import { AppError } from '../helpers/ErrorMapper.js';

export class RemoteFavoritesService {
constructor({
favoritesEndpoint,
imsOrg,
accessToken,
websiteUrl,
}) {
this.favoritesEndpoint = favoritesEndpoint;
this.imsOrg = imsOrg;
this.accessToken = accessToken;
this.websiteUrl = websiteUrl;

console.debug(`Favorites Endpoint: ${this.favoritesEndpoint}`);
}

async get_favorites() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we consider using camel case for naming methods? Using methods with underscores is unconventional in JavaScript, so we'd need to make an exception in our linting rules.

return wretchRetry(`${this.websiteUrl}/generated-copy.json`).get().json();
}

async save_favorite(data) {
try {
/* eslint-disable-next-line camelcase */
const response = await wretchRetry(this.favoritesEndpoint)
.post({
data,
imsOrg: this.imsOrg,
accessToken: this.accessToken,
})
.json();
return response;
} catch (error) {
throw new AppError(error, 'AIO');
}
}
}
6 changes: 5 additions & 1 deletion web-src/src/state/FavoritesState.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
*/
import { atom } from 'recoil';
import { createPersistentStorageEffect } from './PersistentStorageEffect.js';
import { createRemotePersistenceEffect } from './PersistentRemoteStorageEffect.js';

const STORAGE_KEY = 'favorites';

export const favoritesState = atom({
key: 'favoritesState',
default: [],
effects: [createPersistentStorageEffect(STORAGE_KEY)],
effects: [
createRemotePersistenceEffect(STORAGE_KEY),
createPersistentStorageEffect(STORAGE_KEY),
],
});
66 changes: 66 additions & 0 deletions web-src/src/state/PersistentRemoteStorageEffect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2023 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import { useApplicationContext } from '../components/ApplicationProvider.js';

export const createRemotePersistenceEffect = (key) => ({ setSelf, onSet }) => {
// Flag to indicate if the setSelf was called for initialization
let isInitializing = true;
const { remoteFavoritesService } = useApplicationContext();

// load the favorites from the API when the atom is used
remoteFavoritesService.get_favorites()
.then((favs) => {
if (favs != null) {
const favsData = favs.data;
// remove items from favsData that have the same "id" value
const uniqueFavs = favsData.filter((item, index, self) => index === self.findIndex((t) => (
t.id === item.id
)));
// for each item in uniqueFavs, covert "content" field from string to json
uniqueFavs.forEach((item) => {
// eslint-disable-next-line no-param-reassign
item.content = JSON.parse(item.content);
});
setSelf(uniqueFavs);
isInitializing = false;
}
})
.catch((error) => console.error('Error loading favorites:', error));

// save the favorites to the API when the atom is updated
onSet(async (newValue, _, isReset) => {
// if newValue's array length is 0, then do return
if (newValue.length === 0) {
return;
}
if (isReset) {
return;
}

if (isInitializing) {
return;
}

// remove items from favs that have the same "id" value
const favs = newValue;
const uniqueFavs = favs.filter((item, index, self) => index === self.findIndex((t) => (
t.id === item.id
)));

console.log('Favorites to be stored:', favs);
await remoteFavoritesService.save_favorite(favs)
.then((response) => response)
.then((data) => console.log('Favorites updated in API:', data))
.catch((error) => console.error('Error updating favorites:', error));
});
};