Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Power-Maverick/PCF-Controls
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: Timezone-v.1.0.6
Choose a base ref
...
head repository: Power-Maverick/PCF-Controls
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Loading
Showing with 46,492 additions and 93 deletions.
  1. +19 −0 .github/stale.yml
  2. +19 −0 ChatGPTControl/.eslintrc.json
  3. +17 −0 ChatGPTControl/.gitignore
  4. +8 −0 ChatGPTControl/.prettierrc.json
  5. +49 −0 ChatGPTControl/ChatGPT/ControlManifest.Input.xml
  6. +205 −0 ChatGPTControl/ChatGPT/components/chat.tsx
  7. +90 −0 ChatGPTControl/ChatGPT/index.ts
  8. +46 −0 ChatGPTControl/ChatGPTControl.pcfproj
  9. +33 −0 ChatGPTControl/README.md
  10. +8 −0 ChatGPTControl/Solution/ChatGPTPCFSolution/.gitignore
  11. +47 −0 ChatGPTControl/Solution/ChatGPTPCFSolution/ChatGPTPCFSolution.cdsproj
  12. +18 −0 ChatGPTControl/Solution/ChatGPTPCFSolution/src/Other/Customizations.xml
  13. +2 −0 ChatGPTControl/Solution/ChatGPTPCFSolution/src/Other/Relationships.xml
  14. +142 −0 ChatGPTControl/Solution/ChatGPTPCFSolution/src/Other/Solution.xml
  15. BIN ChatGPTControl/assets/configuration.png
  16. BIN ChatGPTControl/assets/screenshot.png
  17. +9,488 −0 ChatGPTControl/package-lock.json
  18. +34 −0 ChatGPTControl/package.json
  19. +3 −0 ChatGPTControl/pcfconfig.json
  20. +7 −0 ChatGPTControl/tsconfig.json
  21. +12 −12 CleverCharacterCounterControl/package-lock.json
  22. +24 −0 CustomLabelControl/.eslintrc.json
  23. +17 −0 CustomLabelControl/.gitignore
  24. +8 −0 CustomLabelControl/.prettierrc.json
  25. +72 −0 CustomLabelControl/CustomLabel/ControlManifest.Input.xml
  26. +14 −0 CustomLabelControl/CustomLabel/components/FluentLabel.tsx
  27. BIN CustomLabelControl/CustomLabel/img/preview.png
  28. +69 −0 CustomLabelControl/CustomLabel/index.ts
  29. +46 −0 CustomLabelControl/CustomLabelControl.pcfproj
  30. +30 −0 CustomLabelControl/README.md
  31. +8 −0 CustomLabelControl/Solution/CustomLabelSolution/.gitignore
  32. +52 −0 CustomLabelControl/Solution/CustomLabelSolution/CustomLabelSolution.cdsproj
  33. +18 −0 CustomLabelControl/Solution/CustomLabelSolution/src/Other/Customizations.xml
  34. +2 −0 CustomLabelControl/Solution/CustomLabelSolution/src/Other/Relationships.xml
  35. +142 −0 CustomLabelControl/Solution/CustomLabelSolution/src/Other/Solution.xml
  36. BIN CustomLabelControl/assets/configuration.png
  37. BIN CustomLabelControl/assets/screenshot.png
  38. +9,271 −0 CustomLabelControl/package-lock.json
  39. +32 −0 CustomLabelControl/package.json
  40. +3 −0 CustomLabelControl/pcfconfig.json
  41. +7 −0 CustomLabelControl/tsconfig.json
  42. +14 −0 FlexibleOrderingGrid/.gitignore
  43. +8 −0 FlexibleOrderingGrid/.prettierrc.json
  44. BIN FlexibleOrderingGrid/Assets/Control-Configuration.png
  45. BIN FlexibleOrderingGrid/Assets/FlexOrderingGrid-WithAutoSave.gif
  46. BIN FlexibleOrderingGrid/Assets/FlexOrderingGrid-WithManualSave.gif
  47. +46 −0 FlexibleOrderingGrid/FlexibleOrderingGrid.pcfproj
  48. +20 −0 FlexibleOrderingGrid/FlexibleOrderingGrid/ControlManifest.Input.xml
  49. +31 −0 FlexibleOrderingGrid/FlexibleOrderingGrid/css/FlexibleOrderingGrid.css
  50. +366 −0 FlexibleOrderingGrid/FlexibleOrderingGrid/extension/ListControl.tsx
  51. BIN FlexibleOrderingGrid/FlexibleOrderingGrid/img/preview.png
  52. +249 −0 FlexibleOrderingGrid/FlexibleOrderingGrid/index.ts
  53. +67 −0 FlexibleOrderingGrid/FlexibleOrderingGrid/strings/FlexibleOrderingGrid.1033.resx
  54. +23 −0 FlexibleOrderingGrid/README.md
  55. +5 −0 FlexibleOrderingGrid/Solution/FlexibleOrderingGridSolution/.gitignore
  56. +47 −0 FlexibleOrderingGrid/Solution/FlexibleOrderingGridSolution/FlexibleOrderingGridSolution.cdsproj
  57. +18 −0 FlexibleOrderingGrid/Solution/FlexibleOrderingGridSolution/src/Other/Customizations.xml
  58. +2 −0 FlexibleOrderingGrid/Solution/FlexibleOrderingGridSolution/src/Other/Relationships.xml
  59. +142 −0 FlexibleOrderingGrid/Solution/FlexibleOrderingGridSolution/src/Other/Solution.xml
  60. BIN FlexibleOrderingGrid/SolutionFile/FlexibleOrderingGridSolution.zip
  61. BIN FlexibleOrderingGrid/SolutionFile/FlexibleOrderingGridSolution_managed.zip
  62. +5 −0 FlexibleOrderingGrid/TestData/SuperHeros.csv
  63. +10,121 −0 FlexibleOrderingGrid/package-lock.json
  64. +33 −0 FlexibleOrderingGrid/package.json
  65. +3 −0 FlexibleOrderingGrid/pcfconfig.json
  66. +6 −0 FlexibleOrderingGrid/tsconfig.json
  67. +17 −9 HoverDetailsList/package-lock.json
  68. +12 −12 InlineTextInput/package-lock.json
  69. +23 −0 PrefixSuffixTextFieldControl/.eslintrc.json
  70. +14 −0 PrefixSuffixTextFieldControl/.gitignore
  71. +8 −0 PrefixSuffixTextFieldControl/.prettierrc.json
  72. +25 −0 PrefixSuffixTextFieldControl/PrefixSuffixTextField/ControlManifest.Input.xml
  73. +61 −0 PrefixSuffixTextFieldControl/PrefixSuffixTextField/components/CustomTextField.tsx
  74. +100 −0 PrefixSuffixTextFieldControl/PrefixSuffixTextField/index.ts
  75. +46 −0 PrefixSuffixTextFieldControl/PrefixSuffixTextFieldControl.pcfproj
  76. +24 −0 PrefixSuffixTextFieldControl/README.md
  77. +5 −0 PrefixSuffixTextFieldControl/Solution/PrefixSuffixTextFieldSolution/.gitignore
  78. +47 −0 ...ffixTextFieldControl/Solution/PrefixSuffixTextFieldSolution/PrefixSuffixTextFieldSolution.cdsproj
  79. +18 −0 PrefixSuffixTextFieldControl/Solution/PrefixSuffixTextFieldSolution/src/Other/Customizations.xml
  80. +2 −0 PrefixSuffixTextFieldControl/Solution/PrefixSuffixTextFieldSolution/src/Other/Relationships.xml
  81. +142 −0 PrefixSuffixTextFieldControl/Solution/PrefixSuffixTextFieldSolution/src/Other/Solution.xml
  82. BIN PrefixSuffixTextFieldControl/SolutionFiles/PrefixSuffixTextFieldSolution.zip
  83. BIN PrefixSuffixTextFieldControl/SolutionFiles/PrefixSuffixTextFieldSolution_managed.zip
  84. BIN PrefixSuffixTextFieldControl/assets/Form-Control-Configuration.png
  85. BIN PrefixSuffixTextFieldControl/assets/Prefix-Suffix-TextFields.gif
  86. +14,491 −0 PrefixSuffixTextFieldControl/package-lock.json
  87. +28 −0 PrefixSuffixTextFieldControl/package.json
  88. +3 −0 PrefixSuffixTextFieldControl/pcfconfig.json
  89. +7 −0 PrefixSuffixTextFieldControl/tsconfig.json
  90. +75 −4 README.md
  91. +17 −9 TextAnalytics/package-lock.json
  92. +10 −1 TimezoneConverterControl/README.md
  93. +12 −12 TimezoneConverterControl/package-lock.json
  94. +5 −11 UrlCardControl/Solution/UrlCardSolution/UrlCardSolution.cdsproj
  95. +1 −1 UrlCardControl/Solution/UrlCardSolution/src/Other/Solution.xml
  96. +1 −1 UrlCardControl/UrlCard/ControlManifest.Input.xml
  97. +1 −0 UrlCardControl/UrlCard/extensions/Card.tsx
  98. +12 −12 UrlCardControl/package-lock.json
  99. +17 −9 WeatherWidget/package-lock.json
19 changes: 19 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 20
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:
- enhancement
- help wanted
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue is closed due to lack of activity and no response. You can reopen or
create another issue. Thank you for your contributions.
19 changes: 19 additions & 0 deletions ChatGPTControl/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended"],
"globals": {
"ComponentFramework": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@microsoft/power-apps", "@typescript-eslint"],
"rules": {
"no-unused-vars": "off"
}
}
17 changes: 17 additions & 0 deletions ChatGPTControl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules

# generated directory
**/generated

# output directory
/out

# msbuild output directories
/bin
/obj

# MSBuild Binary and Structured Log
*.binlog
8 changes: 8 additions & 0 deletions ChatGPTControl/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": false,
"printWidth": 250,
"tabWidth": 4,
"endOfLine": "auto"
}
49 changes: 49 additions & 0 deletions ChatGPTControl/ChatGPT/ControlManifest.Input.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<control namespace="Maverick.Controls" constructor="ChatGPT" version="0.0.2" display-name-key="ChatGPT" description-key="ChatGPT description" control-type="standard">
<!--external-service-usage node declares whether this 3rd party PCF control is using external service or not, if yes, this control will be considered as premium and please also add the external domain it is using.
If it is not using any external service, please set the enabled="false" and DO NOT add any domain below. The "enabled" will be false by default.
Example1:
<external-service-usage enabled="true">
<domain>www.Microsoft.com</domain>
</external-service-usage>
Example2:
<external-service-usage enabled="false">
</external-service-usage>
-->
<external-service-usage enabled="false">
<!--UNCOMMENT TO ADD EXTERNAL DOMAINS
<domain></domain>
<domain></domain>
-->
</external-service-usage>
<!-- property node identifies a specific, configurable piece of data that the control expects from CDS -->
<property name="primary" display-name-key="Primary" description-key="Primary" usage="bound" required="true" of-type-group="Text" />
<property name="organization" display-name-key="Chat GPT Organization" description-key="Chat GPT Organization" usage="input" required="true" of-type="SingleLine.Text" />
<property name="apikey" display-name-key="Chat GPT API Key" description-key="Chat GPT API Key" usage="input" required="true" of-type="SingleLine.Text" />
<resources>
<code path="index.ts" order="1" />
<!-- UNCOMMENT TO ADD MORE RESOURCES
<css path="css/ChatGPT.css" order="1" />
<resx path="strings/ChatGPT.1033.resx" version="1.0.0" />
-->
</resources>
<!-- UNCOMMENT TO ENABLE THE SPECIFIED API
<feature-usage>
<uses-feature name="Device.captureAudio" required="true" />
<uses-feature name="Device.captureImage" required="true" />
<uses-feature name="Device.captureVideo" required="true" />
<uses-feature name="Device.getBarcodeValue" required="true" />
<uses-feature name="Device.getCurrentPosition" required="true" />
<uses-feature name="Device.pickFile" required="true" />
<uses-feature name="Utility" required="true" />
<uses-feature name="WebAPI" required="true" />
</feature-usage>
-->
<type-group name="Text">
<type>SingleLine.Text</type>
<type>SingleLine.TextArea</type>
<type>Multiple</type>
</type-group>
</control>
</manifest>
205 changes: 205 additions & 0 deletions ChatGPTControl/ChatGPT/components/chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import React, { useEffect } from "react";
import { ChatCompletionRequestMessage, Configuration, OpenAIApi } from "openai";
import { FocusZone, FocusZoneDirection } from "@fluentui/react/lib/FocusZone";
import { List } from "@fluentui/react/lib/List";
import { getFocusStyle, getTheme, ITheme, mergeStyleSets } from "@fluentui/react/lib/Styling";
import { TextField } from "@fluentui/react/lib/TextField";
import { IconButton } from "@fluentui/react/lib/Button";
import { IIconProps } from "@fluentui/react/lib/Icon";
import { Image, IImageProps } from "@fluentui/react/lib/Image";
import { Spinner } from "@fluentui/react/lib/Spinner";

export interface IChatListProps {
chatMessages?: Array<ChatCompletionRequestMessage>;
organization?: string;
apiKey?: string;
relayUpdates: (newData: ChatCompletionRequestMessage) => void;
}

const theme: ITheme = getTheme();
const { palette, semanticColors, fonts } = theme;
const classNames = mergeStyleSets({
itemCell: [
getFocusStyle(theme, { inset: -1 }),
{
minHeight: 54,
padding: 10,
boxSizing: "border-box",
borderBottom: `1px solid ${semanticColors.bodyDivider}`,
display: "flex",
selectors: {
"&:hover": { background: palette.neutralLight },
},
},
],
itemImage: {
flexShrink: 0,
paddingRight: 10,
},
itemContent: {
marginLeft: 10,
overflow: "hidden",
flexGrow: 1,
},
itemTitle: [
fonts.xLarge,
{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
textAlign: "left",
display: "flex",
},
],
itemMessage: {
textAlign: "left",
},
msgWrapper: {
display: "flex",
},
msgText: {
width: "50%",
},
search: {
textAlign: "left",
width: "50%",
},
msgEmpty: {
textAlign: "left",
width: "50%",
paddingBottom: "10px",
},
spinnerWrapper: {
display: "flex",
paddingTop: "10px",
paddingBottom: "10px",
},
});

const ChatMessages = (props: IChatListProps): JSX.Element => {
const configuration = new Configuration({
organization: props.organization!,
apiKey: props.apiKey!,
});
const openai = new OpenAIApi(configuration);

const submitIcon: IIconProps = { iconName: "Send" };
const [items, setItems] = React.useState(props.chatMessages ?? []);
const [sendNewMessage, setSendNewMessage] = React.useState(false);
const [textFieldValue, setTextFieldValue] = React.useState("");

const userImageProps: Partial<IImageProps> = {
src: "https://img.freepik.com/premium-vector/avatar-profile-icon_188544-4755.jpg",
width: 32,
};

const gptImageProps: Partial<IImageProps> = {
src: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/ChatGPT_logo.svg/1024px-ChatGPT_logo.svg.png",
width: 32,
};

// useEffect(() => {
// if (props.chatMessages) {
// openai
// .createChatCompletion({
// model: "gpt-3.5-turbo",
// messages: props.chatMessages,
// })
// .then((response) => {
// response.data.choices.forEach((choice) => {
// setItems((items) => [...items, choice.message as ChatCompletionRequestMessage]);
// });
// });
// }
// }, [props.chatMessages]);

useEffect(() => {
if (items.length > 0 && sendNewMessage) {
openai
.createChatCompletion({
model: "gpt-3.5-turbo",
messages: items,
})
.then((response) => {
response.data.choices.forEach((choice) => {
setItems((items) => [...items, choice.message as ChatCompletionRequestMessage]);
});
props.relayUpdates(response.data.choices[0].message as ChatCompletionRequestMessage);
setSendNewMessage(false);
});
}
}, [sendNewMessage]);

const onFilterChanged = (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text?: string): void => {
if (text) {
setItems(items.filter((item) => item.content.toLowerCase().indexOf(text.toLowerCase()) >= 0));
} else {
setItems(props.chatMessages!);
}
};

const onRenderCell = (item?: ChatCompletionRequestMessage, index?: number | undefined): JSX.Element => {
if (!item) {
return <></>;
} else {
return (
<div className={classNames.itemCell} data-is-focusable={true}>
<div className={classNames.itemContent}>
<div className={classNames.itemTitle}>
{item?.role === "user" ? <Image {...userImageProps} alt={item?.role} className={classNames.itemImage} /> : <Image {...gptImageProps} alt={item?.role} className={classNames.itemImage} />}
{item?.role}
</div>
{/* <div className={classNames.itemIndex}>{`Item ${index}`}</div> */}
<div className={classNames.itemMessage}>{item?.content}</div>
</div>
</div>
);
}
};

const onChangeTextFieldValue = React.useCallback((event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
setTextFieldValue(newValue || "");
}, []);

const sendToChatGPT = (): void => {
const message: ChatCompletionRequestMessage = { role: "user", content: textFieldValue };
setItems((items) => [...items, message]);
setSendNewMessage(true);
setTextFieldValue("");
props.relayUpdates(message);
};

return (
<FocusZone direction={FocusZoneDirection.vertical}>
{items && items.length > 0 ? (
<>
<TextField
className={classNames.search}
label={"Search"}
placeholder={"Search your content..."}
// eslint-disable-next-line react/jsx-no-bind
onChange={onFilterChanged}
/>
<List items={items} onRenderCell={onRenderCell} />
</>
) : (
<div className={classNames.msgEmpty}>Ask your questions to Chat GPT</div>
)}
{sendNewMessage ? (
<div className={classNames.spinnerWrapper}>
<Spinner label="Chat GPT is responding... Please wait..." ariaLive="assertive" labelPosition="left" />
</div>
) : (
<></>
)}
<div className={classNames.msgWrapper}>
<TextField className={classNames.msgText} placeholder={"Type your message here"} value={textFieldValue} onChange={onChangeTextFieldValue} />
<IconButton iconProps={submitIcon} title="Send" ariaLabel="Send" onClick={sendToChatGPT} />
</div>
</FocusZone>
);
};

export default ChatMessages;
Loading