Skip to content
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: 0 additions & 1 deletion .github/workflows/ci-test-custom-script.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ jobs:
db_url=$(grep -oP 'APPSMITH_DB_URL=\K[^ ]+' cicontainerlocal/stacks/configuration/docker.env || echo "")
if [[ -z "$db_url" ]]; then
echo "::error::APPSMITH_DB_URL not found in the environment file"
exit 1
fi
if [[ $db_url == "postgresql"* ]]; then
echo "Database type: Postgres. Ensure PostgreSQL-specific configurations are in place."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,16 @@ describe(
// Click unix cell edit
table.ClickOnEditIcon(row, column);

// Click on specific date within
// Click on a specific date within the view port of the date picker
// Date picker opens in september 2024 due to the Table data set
agHelper.GetNClick(
`${table._dateInputPopover} [aria-label='${table.getFormattedTomorrowDates().verboseFormat}']`,
`${table._dateInputPopover} [aria-label='Thu Sep 26 2024']`,
);

// Check that date is set in column
// Check that the date is set in column
table
.ReadTableRowColumnData(row, column, "v2")
.then((val) =>
expect(val).to.equal(table.getFormattedTomorrowDates().isoFormat),
);
.then((val) => expect(val).to.equal("2024-09-26"));
};

it("1. should allow inline editing of Unix Timestamp in seconds (unix/s)", () => {
Expand Down
34 changes: 0 additions & 34 deletions app/client/cypress/support/Pages/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -854,38 +854,4 @@ export class Table {
this.agHelper.GetHoverNClick(selector, 1, true);
verify && cy.get(selector).eq(1).should("be.disabled");
}

/**
* Helper function to get formatted date strings for tomorrow's date.
*
* @returns {Object} An object containing:
* - verbose format (e.g., "Sat Sep 21 2024")
* - ISO date format (e.g., "2024-09-21")
*/
public getFormattedTomorrowDates() {
// Create a new Date object for today
const tomorrow = new Date();

// Set the date to tomorrow by adding 1 to today's date
tomorrow.setDate(tomorrow.getDate() + 1);

// Format tomorrow's date in verbose form (e.g., "Sat Sep 21 2024")
const verboseFormat = tomorrow
.toLocaleDateString("en-US", {
weekday: "short",
year: "numeric",
month: "short",
day: "2-digit",
})
.replace(/,/g, ""); // Remove commas from the formatted string

// Format tomorrow's date in ISO form (e.g., "2024-09-21")
const isoFormat = tomorrow.toISOString().split("T")[0]; // Extract the date part only

// Return both formatted date strings as an object
return {
verboseFormat,
isoFormat,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const _AIChat = (props: AIChatProps, ref: ForwardedRef<HTMLDivElement>) => {
// assistantName,
chatTitle,
isWaitingForResponse = false,
onApplyAssistantSuggestion,
onPromptChange,
onSubmit,
prompt,
Expand Down Expand Up @@ -56,7 +57,12 @@ const _AIChat = (props: AIChatProps, ref: ForwardedRef<HTMLDivElement>) => {

<ul className={styles.thread} data-testid="t--aichat-thread">
{thread.map((message: ChatMessage) => (
<ThreadMessage {...message} key={message.id} username={username} />
<ThreadMessage
{...message}
key={message.id}
onApplyAssistantSuggestion={onApplyAssistantSuggestion}
username={username}
/>
))}
</ul>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Text } from "@appsmith/wds";
import { clsx } from "clsx";
import React from "react";
import { Button as HeadlessButton } from "react-aria-components";
import styles from "./styles.module.css";
import type { AssistantSuggestionButtonProps } from "./types";

export const AssistantSuggestionButton = ({
children,
className,
...rest
}: AssistantSuggestionButtonProps) => {
return (
<HeadlessButton className={clsx(styles.root, className)} {...rest}>
<Text>{children}</Text>
</HeadlessButton>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./AssistantSuggestionButton";
export * from "./types";
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.root {
height: 30px;
padding: 0 var(--inner-spacing-4);
background-color: var(--bg-neutral-subtle-alt, #e7e8e8);
border-radius: var(--radius-inner-button, 1.8px);

&:hover {
background-color: var(--bg-neutral-subtle-alt-hover, #f0f1f1);
}

&:focus-visible {
box-shadow:
0 0 0 2px var(--color-bg),
0 0 0 4px var(--color-bd-focus);
}

&:active {
background-color: var(--bg-neutral-subtle-alt-active, #e1e2e2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { PropsWithChildren } from "react";
import type { ButtonProps as HeadlessButtonProps } from "react-aria-components";

export interface AssistantSuggestionButtonProps
extends PropsWithChildren<HeadlessButtonProps> {}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Text } from "@appsmith/wds";
import { Flex, Text } from "@appsmith/wds";
import { clsx } from "clsx";
import React from "react";
import Markdown from "react-markdown";
import SyntaxHighlighter from "react-syntax-highlighter";
import { monokai } from "react-syntax-highlighter/dist/cjs/styles/hljs";
import { AssistantSuggestionButton } from "../AssistantSuggestionButton";
import { UserAvatar } from "../UserAvatar";
import styles from "./styles.module.css";
import type { ThreadMessageProps } from "./types";
Expand All @@ -12,6 +13,8 @@ export const ThreadMessage = ({
className,
content,
isAssistant,
onApplyAssistantSuggestion,
promptSuggestions = [],
username,
...rest
}: ThreadMessageProps) => {
Expand Down Expand Up @@ -50,6 +53,25 @@ export const ThreadMessage = ({
{content}
</Markdown>
</Text>

{promptSuggestions.length > 0 && (
<Flex
className={styles.suggestions}
gap="var(--inner-spacing-5)"
paddingTop="spacing-4"
wrap="wrap"
>
{promptSuggestions.map((suggestion) => (
<AssistantSuggestionButton
key={suggestion}
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
onPress={() => onApplyAssistantSuggestion?.(suggestion)}
>
{suggestion}
</AssistantSuggestionButton>
))}
</Flex>
)}
</div>
) : (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ export interface ThreadMessageProps extends HTMLProps<HTMLLIElement> {
content: string;
isAssistant: boolean;
username: string;
promptSuggestions?: string[];
onApplyAssistantSuggestion?: (suggestion: string) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface ChatMessage {
id: string;
content: string;
isAssistant: boolean;
promptSuggestions?: string[];
}

export interface AIChatProps {
Expand All @@ -15,4 +16,5 @@ export interface AIChatProps {
isWaitingForResponse?: boolean;
onPromptChange: (prompt: string) => void;
onSubmit?: () => void;
onApplyAssistantSuggestion?: (suggestion: string) => void;
}
3 changes: 3 additions & 0 deletions app/client/packages/rts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"start": "./start-server.sh"
},
"dependencies": {
"@opentelemetry/instrumentation-http": "^0.53.0",
"@opentelemetry/sdk-trace-node": "^1.26.0",
"@opentelemetry/semantic-conventions": "^1.27.0",
"@shared/ast": "workspace:^",
"axios": "^1.7.4",
"express": "^4.20.0",
Expand Down
50 changes: 50 additions & 0 deletions app/client/packages/rts/src/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
BatchSpanProcessor,
NodeTracerProvider,
} from "@opentelemetry/sdk-trace-node";
import { Resource } from "@opentelemetry/resources";
import {
ATTR_DEPLOYMENT_NAME,
ATTR_SERVICE_INSTANCE_ID,
} from "@opentelemetry/semantic-conventions/incubating";
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";

const provider = new NodeTracerProvider({
resource: new Resource({
[ATTR_DEPLOYMENT_NAME]: `${process.env.APPSMITH_DEPLOYMENT_NAME || "self-hosted"}`,
[ATTR_SERVICE_INSTANCE_ID]: `${process.env.HOSTNAME || "appsmith-0"}`,
[ATTR_SERVICE_NAME]: "rts",
}),
});

const nrTracesExporter = new OTLPTraceExporter({
url: `${process.env.APPSMITH_NEW_RELIC_OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces`,
headers: {
"api-key": `${process.env.APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY}`,
},
});

registerInstrumentations({
instrumentations: [new HttpInstrumentation()],
});

const batchSpanProcessor = new BatchSpanProcessor(
nrTracesExporter,
//Optional BatchSpanProcessor Configurations
{
// The maximum queue size. After the size is reached spans are dropped.
maxQueueSize: 100,
// The maximum batch size of every export. It must be smaller or equal to maxQueueSize.
maxExportBatchSize: 50,
// The interval between two consecutive exports
scheduledDelayMillis: 500,
// How long the export can run before it is cancelled
exportTimeoutMillis: 30000,
},
);

provider.addSpanProcessor(batchSpanProcessor);
provider.register();
1 change: 1 addition & 0 deletions app/client/packages/rts/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "./instrumentation";
import http from "http";
import express from "express";
import { Server } from "socket.io";
Expand Down
14 changes: 11 additions & 3 deletions app/client/src/PluginActionEditor/PluginActionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,27 @@ interface ChildrenProps {
export const PluginActionContextProvider = (
props: ChildrenProps & PluginActionContextType,
) => {
const { action, children, datasource, editorConfig, plugin, settingsConfig } =
props;
const {
action,
actionResponse,
children,
datasource,
editorConfig,
plugin,
settingsConfig,
} = props;

// using useMemo to avoid unnecessary renders
const contextValue = useMemo(
() => ({
action,
actionResponse,
datasource,
editorConfig,
plugin,
settingsConfig,
}),
[action, datasource, editorConfig, plugin, settingsConfig],
[action, actionResponse, datasource, editorConfig, plugin, settingsConfig],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
import { getHasManageActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
import Pagination from "pages/Editor/APIEditor/Pagination";
import { reduxForm } from "redux-form";
import { useHandleRunClick } from "PluginActionEditor/hooks";
import {
useHandleRunClick,
useAnalyticsOnRunClick,
} from "PluginActionEditor/hooks";

const FORM_NAME = API_EDITOR_FORM_NAME;

const APIEditorForm = () => {
const { action } = usePluginActionContext();
const { handleRunClick } = useHandleRunClick();
const { callRunActionAnalytics } = useAnalyticsOnRunClick();
const theme = EditorTheme.LIGHT;

const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
Expand All @@ -25,6 +29,11 @@ const APIEditorForm = () => {
action.userPermissions,
);

const onTestClick = () => {
callRunActionAnalytics();
handleRunClick();
};

return (
<CommonEditorForm
action={action}
Expand All @@ -40,7 +49,7 @@ const APIEditorForm = () => {
paginationUiComponent={
<Pagination
actionName={action.name}
onTestClick={handleRunClick}
onTestClick={onTestClick}
paginationType={action.actionConfiguration.paginationType}
theme={theme}
/>
Expand Down
Loading