-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LTLC-115969 Update UI extension, add greeting controller
- Loading branch information
Octavian Condre
committed
Sep 5, 2024
1 parent
bb91961
commit 7c3af17
Showing
26 changed files
with
482 additions
and
3,763 deletions.
There are no files selected for viewing
36 changes: 36 additions & 0 deletions
36
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Controllers/GreetingController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Extensions.Logging; | ||
using System.Text.Json.Nodes; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Rws.LC.UISampleApp.Controllers | ||
{ | ||
[Route("api/[controller]")] | ||
[ApiController] | ||
public class GreetingController : ControllerBase | ||
{ | ||
/// <summary> | ||
/// The logger. | ||
/// </summary> | ||
private ILogger<GreetingController> logger; | ||
|
||
public GreetingController(ILogger<GreetingController> logger) | ||
{ | ||
this.logger = logger; | ||
} | ||
|
||
/// <summary> | ||
/// This endpoint always returns "Hello world!". | ||
/// </summary> | ||
/// <returns>The hardcoded greeting message.</returns> | ||
[Authorize] | ||
[HttpGet("")] | ||
public ActionResult GetGreeting() | ||
{ | ||
logger.LogInformation("Retrieving greeting."); | ||
return Ok(new JsonObject() { { "greeting", "Hello, world!" } }); | ||
} | ||
} | ||
} |
5 changes: 0 additions & 5 deletions
5
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/.npmrc
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/dist/bundle.js
This file was deleted.
Oops, something went wrong.
1 change: 1 addition & 0 deletions
1
...s/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/dist/my-ui-extension-script.js
Large diffs are not rendered by default.
Oops, something went wrong.
154 changes: 154 additions & 0 deletions
154
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/handlers/buttonsHandlers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import { trados, ExtensibilityEventDetail, Project, tradosProjectTemplateApi } from "@trados/trados-ui-extensibility"; | ||
import { logExtensionData } from "./helpers"; | ||
|
||
/** | ||
* Handles the callAppApiButton's click event. | ||
* Calls my own app's greeting API to receive the greeting message which is included in a notification. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const callAppApiButtonClicked = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
|
||
trados | ||
// The callAppApi function will automatically add headers: the account identifier and authorization token. | ||
.callAppApi({ | ||
url: `api/greeting/`, | ||
method: "GET" | ||
}) | ||
.then(data => { | ||
trados.showNotification( | ||
`App backend says <b>${data?.responseData?.greeting}</b>`, | ||
trados.contexts.projects, | ||
trados.notificationTypes.success | ||
); | ||
}) | ||
.catch(reason => { | ||
console.error("[UI Extensibility] [my UI extension] Failed to call my app's API", reason); | ||
trados.showNotification( | ||
"Failed to call my app's API.", | ||
trados.contexts.projects, | ||
trados.notificationTypes.fail | ||
); | ||
}); | ||
} | ||
|
||
/** | ||
* Handles the callPublicApiButton's render event. | ||
* Checks whether the current project is based on a project template, then updates callPublicApiButton's hidden property depending on the outcome. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const callPublicApiButtonRendered = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
const hidden = !detail.project?.projectTemplate; | ||
trados.updateElement("callPublicApiButton", { hidden: hidden }); | ||
}; | ||
|
||
/** | ||
* Handles the callPublicApiButton's click event. | ||
* Calls the ProjectTemplateAPI from Language Cloud Public API to get the current project's project template and displays its name in a notification. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const callPublicApiButtonClicked = (detail: ExtensibilityEventDetail) => { | ||
logExtensionData(detail); | ||
|
||
const projectTemplateId = detail.project?.projectTemplate?.id; | ||
if (projectTemplateId) { | ||
// Call the function that initializes the tradosProjectTemplateApi. | ||
tradosProjectTemplateApi() | ||
// Call the getProjectTemplate API endpoint. | ||
.getProjectTemplate({ | ||
// Provide the project template identifier. | ||
projectTemplateId: projectTemplateId, | ||
// Provide the account identifier and authorization token returned by the getRegistrationResult function. | ||
...trados.getRegistrationResult() | ||
}) | ||
.then(apiData => { | ||
console.log("[UI Extensibility] [my UI extension] Project template details from Language Cloud Public API", apiData); | ||
|
||
trados.showNotification( | ||
`This project was created using the <b>${apiData.name}</b> project template`, | ||
trados.contexts.projects, | ||
trados.notificationTypes.success | ||
); | ||
}) | ||
.catch(e => { | ||
console.error(`[UI Extensibility] [my UI extension] API call failed`, e ); | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Handles the myNavigateButton's render event. | ||
* Checks whether the current project is based on a project template, then updates myNavigateButton's hidden property depending on the outcome. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myNavigateButtonRendered = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
const hidden = !detail.project?.projectTemplate; | ||
trados.updateElement("myNavigateButton", { hidden: hidden }); | ||
}; | ||
|
||
/** | ||
* Handles the myNavigateButton's click event. | ||
* Navigates to the current project's project template details view. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myNavigateButtonClicked = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
if (detail.project?.projectTemplate) { | ||
const projectTemplateId = detail.project.projectTemplate.id; | ||
const projectTemplatePath = `resources/project-templates/${projectTemplateId}`; | ||
trados.navigate(projectTemplatePath, trados.navigationTypes.route); | ||
} | ||
}; | ||
|
||
/** | ||
* Handles the myGetUiDataButton's click event. | ||
* Gets the currently active tab in the project details view from the event detail; the onclick action's payload is ["projectActiveTab"]. | ||
* Gets the currently selected projects in the projects list view using the getLocalData function as an alternative to the action payload approach. | ||
* Shows a notification containing both the active tab and the selected projects in the projects list. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myGetUiDataButtonClicked = (detail: ExtensibilityEventDetail) => { | ||
logExtensionData(detail); | ||
|
||
// The click event detail contains local data requested via onclick action's payload - see extension elements array in index.ts. | ||
const myActiveTab = detail.projectActiveTab; | ||
|
||
// You can also request local UI data using the trados.getLocalData function. | ||
trados | ||
.getLocalData(trados.contexts.projects, trados.dataSelectors.selectedProjects) | ||
.then((data: { selectedProjects: Project[] }) => { | ||
const mySelectedProjects = data.selectedProjects; | ||
const mySelectedProjectsCount = mySelectedProjects.length; | ||
const notificationData = [ | ||
`My active tab is <b>${myActiveTab}</b>.`, | ||
mySelectedProjectsCount | ||
? `My selected projects (${mySelectedProjectsCount}):<br>${mySelectedProjects.map(p => " - " + p.name).join("<br>")}` | ||
: "No selected projects" | ||
]; | ||
trados.showNotification(notificationData.join("<br><br>"), trados.contexts.projects) | ||
}) | ||
.catch(reason => { | ||
console.error("[UI Extensibility] [my UI extension] Failed to get local data", reason); | ||
trados.showNotification( | ||
"Failed to get local data.", | ||
trados.contexts.projects, | ||
trados.notificationTypes.fail | ||
); | ||
}); | ||
}; |
88 changes: 7 additions & 81 deletions
88
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/handlers/helpers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,84 +1,10 @@ | ||
import { ExtensibilityEventDetail } from "@sdl/extensibility-types/extensibility"; | ||
import { | ||
currentProject, | ||
projectImportanceList | ||
} from "./projectToolbarHandlers"; | ||
import { ExtensibilityEventDetail } from "@trados/trados-ui-extensibility"; | ||
|
||
/** | ||
* Logs the event detail object to the console. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const logExtensionData = (detail: ExtensibilityEventDetail) => { | ||
console.log("[UI Extensibility] [extension] Custom event detail", detail); | ||
console.log("[UI Extensibility] [my UI extension] Custom event detail", detail); | ||
}; | ||
|
||
// simple file download | ||
// no longer used for initial "Create invoice" button; still used for "Get local data" button | ||
export const download = (filename: string, data: string | Blob) => { | ||
const element = document.createElement("a"); | ||
if (typeof data === "string") { | ||
element.href = "data:text/plain;charset=utf-8," + encodeURIComponent(data); | ||
} else { | ||
element.href = URL.createObjectURL(data); | ||
} | ||
element.setAttribute("download", filename); | ||
element.style.display = "none"; | ||
document.body.appendChild(element); | ||
element.click(); | ||
document.body.removeChild(element); | ||
}; | ||
|
||
export const downloadData = (data: any) => { | ||
const filename = "local-data.txt"; | ||
console.log( | ||
`[UI Extensibility] [extension] Download data as ${filename} file`, | ||
data | ||
); | ||
|
||
setTimeout(() => { | ||
download(filename, JSON.stringify(data)); | ||
}, 1); | ||
}; | ||
|
||
export const updateProjectImportanceList = (data?: any) => { | ||
const currentProjectImportanceItem = projectImportanceList.find( | ||
i => i.projectId === currentProject!.id | ||
); | ||
if (currentProjectImportanceItem) { | ||
if (data.responseData.importance) { | ||
// update existing entry | ||
currentProjectImportanceItem.importance = | ||
data.responseData.importance.toLowerCase(); | ||
if (currentProjectImportanceItem.pending) { | ||
currentProjectImportanceItem.pending = false; | ||
currentProjectImportanceItem.id = data.responseData.id; | ||
} | ||
} else { | ||
// delete entry | ||
projectImportanceList.splice( | ||
projectImportanceList.indexOf(currentProjectImportanceItem), | ||
1 | ||
); | ||
} | ||
} else { | ||
// add entry | ||
projectImportanceList.push({ | ||
id: data.responseData.id, | ||
projectId: data.responseData.projectId, | ||
importance: data.responseData.importance, | ||
pending: false | ||
}); | ||
} | ||
}; | ||
|
||
// a similar function exists in public-packages/extensibility/src/api/apiClient.ts but is intentionally not exported | ||
// this helper function in the mock extension is used when calling add-on/app backend api directly, see api/project-metadata in projects-app/src/mocks/ui-extensibility/extensions/handlers/projectToolbarHandlers.ts | ||
export const getEnvironmentUrlPartByHost = () => { | ||
const hostEnv = document.location.host.split("-")[0]; | ||
switch (hostEnv) { | ||
case "ci": | ||
case "qa": | ||
case "pte": | ||
case "uat": | ||
case "staging": | ||
return `${hostEnv}-`; | ||
default: | ||
return ""; // prod | ||
} | ||
}; |
71 changes: 71 additions & 0 deletions
71
samples/dotnet/UISampleApp/Rws.LC.UISampleApp/Resources/frontend/handlers/panelsHandlers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { ExtensibilityEventDetail } from "@trados/trados-ui-extensibility"; | ||
import { logExtensionData } from "./helpers"; | ||
|
||
/** | ||
* Handles myCustomSidebarBox's render event. | ||
* Adds HTML content to the sidebarBox. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myCustomSidebarBoxRendered = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
|
||
const sidebarBoxContentWrapper = document.getElementById(detail.domElementId); | ||
if (sidebarBoxContentWrapper) { | ||
// Reset content for re-renders: as the state changes in the Trados UI depending on user actions, re-renders occur. | ||
sidebarBoxContentWrapper.innerHTML = ""; | ||
|
||
// Create and append div. | ||
const div = document.createElement("div"); | ||
div.innerHTML = `Custom sidebar box content inserted on render.`; | ||
sidebarBoxContentWrapper.appendChild(div); | ||
} | ||
}; | ||
|
||
/** | ||
* Handles myCustomPanel's render event. | ||
* Adds HTML content to the panel. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myCustomPanelRendered = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
|
||
const panelContentWrapper = document.getElementById(detail.domElementId); | ||
if (panelContentWrapper) { | ||
// Reset content for re-renders: as the state changes in the Trados UI depending on user actions, re-renders occur. | ||
panelContentWrapper.innerHTML = ""; | ||
|
||
// Create and append div. | ||
const div = document.createElement("div"); | ||
div.innerHTML = `Custom panel content inserted on render.`; | ||
panelContentWrapper.appendChild(div); | ||
} | ||
}; | ||
|
||
/** | ||
* Handles myCustomTab's render event. | ||
* Adds HTML content to the tab. | ||
* | ||
* @param detail The event detail object. | ||
*/ | ||
export const myCustomTabRendered = ( | ||
detail: ExtensibilityEventDetail | ||
) => { | ||
logExtensionData(detail); | ||
|
||
const tabContentWrapper = document.getElementById(detail.domElementId); | ||
if (tabContentWrapper) { | ||
// Reset content for re-renders: as the state changes in the Trados UI depending on user actions, re-renders occur. | ||
tabContentWrapper.innerHTML = ""; | ||
|
||
// Create and append div. | ||
const div = document.createElement("div"); | ||
div.innerHTML = `Custom tab content inserted on render.`; | ||
tabContentWrapper.appendChild(div); | ||
} | ||
}; |
Oops, something went wrong.