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
18 changes: 17 additions & 1 deletion crates/atuin-desktop-runtime/src/blocks/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub struct Mysql {

#[builder(default = 0)]
pub auto_refresh: u32,

#[builder(default = false)]
pub skip_sql_mode_init: bool,
}

impl FromDocument for Mysql {
Expand Down Expand Up @@ -78,6 +81,12 @@ impl FromDocument for Mysql {
.and_then(|v| v.as_u64())
.unwrap_or(0) as u32,
)
.skip_sql_mode_init(
props
.get("skipSqlModeInit")
.and_then(|v| v.as_bool())
.unwrap_or(false),
)
.build();

Ok(mysql)
Expand Down Expand Up @@ -170,7 +179,14 @@ impl SqlBlockBehavior for Mysql {
}

async fn create_pool(&self, uri: String) -> Result<Self::Pool, SqlBlockError> {
let opts = MySqlConnectOptions::from_str(&uri)?;
let mut opts = MySqlConnectOptions::from_str(&uri)?;

// Skip sql_mode initialization for databases that don't support dynamic SET statements
// (e.g., StarRocks, Apache Doris)
if self.skip_sql_mode_init {
opts = opts.pipes_as_concat(false).no_engine_substitution(false);
}

Ok(MySqlPool::connect_with(opts).await?)
}

Expand Down
34 changes: 34 additions & 0 deletions src/components/runbooks/editor/blocks/MySQL/MySQL.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DatabaseIcon } from "lucide-react";
import { Switch } from "@heroui/react";

// @ts-ignore
import { createReactBlockSpec } from "@blocknote/react";
Expand All @@ -25,6 +26,7 @@ interface SQLProps {
setAutoRefresh: (autoRefresh: number) => void;
setName: (name: string) => void;
setDependency: (dependency: DependencySpec) => void;
setSkipSqlModeInit: (skip: boolean) => void;
onCodeMirrorFocus?: () => void;
}

Expand All @@ -38,8 +40,28 @@ const MySQL = ({
collapseQuery,
setCollapseQuery,
setDependency,
setSkipSqlModeInit,
onCodeMirrorFocus,
}: SQLProps) => {
const settingsContent = (
<div className="flex items-center justify-between gap-4">
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
Skip SQL mode initialization
</span>
<span className="text-xs text-gray-500 dark:text-gray-400">
Enable for MySQL-compatible databases like StarRocks or Doris
</span>
</div>
<Switch
size="sm"
isSelected={mysql.skipSqlModeInit}
onValueChange={setSkipSqlModeInit}
isDisabled={!isEditable}
/>
</div>
);

return (
<SQL
block={mysql}
Expand All @@ -59,6 +81,8 @@ const MySQL = ({
setCollapseQuery={setCollapseQuery}
setDependency={setDependency}
onCodeMirrorFocus={onCodeMirrorFocus}
settingsContent={settingsContent}
settingsTitle="MySQL Settings"
/>
);
};
Expand All @@ -72,6 +96,7 @@ export default createReactBlockSpec(
uri: { default: "" },
autoRefresh: { default: 0 },
dependency: { default: "{}" },
skipSqlModeInit: { default: false },
},
content: "none",
},
Expand Down Expand Up @@ -133,6 +158,13 @@ export default createReactBlockSpec(
});
};

const setSkipSqlModeInit = (skip: boolean) => {
editor.updateBlock(block, {
// @ts-ignore
props: { ...block.props, skipSqlModeInit: skip },
});
};

let dependency = DependencySpec.deserialize(block.props.dependency);
let mysql = new MySqlBlock(
block.id,
Expand All @@ -141,6 +173,7 @@ export default createReactBlockSpec(
block.props.query,
block.props.uri,
block.props.autoRefresh,
block.props.skipSqlModeInit,
);

return (
Expand All @@ -154,6 +187,7 @@ export default createReactBlockSpec(
collapseQuery={collapseQuery}
setCollapseQuery={setCollapseQuery}
setDependency={setDependency}
setSkipSqlModeInit={setSkipSqlModeInit}
onCodeMirrorFocus={handleCodeMirrorFocus}
/>
);
Expand Down
62 changes: 52 additions & 10 deletions src/lib/blocks/common/SQL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
ButtonGroup,
Tooltip,
DropdownSection,
Modal,
ModalContent,
ModalHeader,
ModalBody,
} from "@heroui/react";
import {
ArrowDownToLineIcon,
Expand All @@ -24,6 +28,7 @@ import {
RefreshCwIcon,
Maximize2,
Minimize2,
SettingsIcon,
} from "lucide-react";
import CodeMirror, { Extension } from "@uiw/react-codemirror";
import { langs } from "@uiw/codemirror-extensions-langs";
Expand Down Expand Up @@ -77,6 +82,10 @@ interface SQLProps {
setName: (name: string) => void;
setDependency: (dependency: DependencySpec) => void;
onCodeMirrorFocus?: () => void;

// Optional settings content - if provided, shows settings icon + modal
settingsContent?: React.ReactNode;
settingsTitle?: string;
}

const autoRefreshChoices = [
Expand Down Expand Up @@ -111,12 +120,15 @@ const SQL = ({
sqlType,
extensions = [],
onCodeMirrorFocus,
settingsContent,
settingsTitle,
}: SQLProps) => {
let editor = useBlockNoteEditor();
const [results, setResults] = useState<SqlBlockExecutionResult | null>(null);
const [queryCount, setQueryCount] = useState<Option<number>>(None);
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
const [isFullscreenQueryCollapsed, setIsFullscreenQueryCollapsed] = useState<boolean>(false);
const [settingsOpen, setSettingsOpen] = useState<boolean>(false);
const { incrementBadge, decrementBadge } = useContext(TabsContext);

const execution = useBlockExecution(block.id);
Expand Down Expand Up @@ -254,22 +266,34 @@ const SQL = ({
type={block.typeName}
setName={setName}
inlineHeader
topRightElement={
<div className="flex items-center gap-1">
{settingsContent && (
<Tooltip content="Settings" delay={500}>
<button
onClick={() => setSettingsOpen(true)}
className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
>
<SettingsIcon className="h-4 w-4" />
</button>
</Tooltip>
)}
<Tooltip content={isFullscreen ? "Exit fullscreen" : "Open in fullscreen"} delay={500}>
<button
onClick={() => setIsFullscreen(!isFullscreen)}
className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
>
{isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
</button>
</Tooltip>
</div>
}
header={
<>
<div className="flex flex-row justify-between w-full">
<h1 className="text-default-700 font-semibold">
<EditableHeading initialText={name} onTextChange={(text) => setName(text)} />
</h1>
<div className="flex flex-row items-center gap-2">
<Tooltip content={isFullscreen ? "Exit fullscreen" : "Open in fullscreen"}>
<button
onClick={() => setIsFullscreen(!isFullscreen)}
className="p-2 hover:bg-default-100 rounded-md"
>
{isFullscreen ? <Minimize2 size={20} /> : <Maximize2 size={20} />}
</button>
</Tooltip>
</div>
</div>

<div className="flex flex-row gap-2 w-full items-center">
Expand Down Expand Up @@ -583,6 +607,24 @@ const SQL = ({
</div>
</div>
)}

{/* Settings Modal */}
{settingsContent && (
<Modal
isOpen={settingsOpen}
onClose={() => setSettingsOpen(false)}
size="sm"
>
<ModalContent>
<ModalHeader className="text-base font-medium">
{settingsTitle || "Settings"}
</ModalHeader>
<ModalBody className="pb-6">
{settingsContent}
</ModalBody>
</ModalContent>
</Modal>
)}
</Block>
);
};
Expand Down
7 changes: 5 additions & 2 deletions src/lib/workflow/blocks/mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ export class MySqlBlock extends Block {
query: string;
uri: string;
autoRefresh: number;
skipSqlModeInit: boolean;

get typeName() {
return "mysql";
}

constructor(id: string, name: string, dependency: DependencySpec, query: string, uri: string, autoRefresh: number) {
constructor(id: string, name: string, dependency: DependencySpec, query: string, uri: string, autoRefresh: number, skipSqlModeInit: boolean = false) {
super(id, name, dependency);

this.query = query;
this.uri = uri;
this.autoRefresh = autoRefresh;
this.skipSqlModeInit = skipSqlModeInit;
}

object() {
Expand All @@ -25,6 +27,7 @@ export class MySqlBlock extends Block {
query: this.query,
uri: this.uri,
autoRefresh: this.autoRefresh,
skipSqlModeInit: this.skipSqlModeInit,
};
}

Expand All @@ -34,6 +37,6 @@ export class MySqlBlock extends Block {

static deserialize(json: string) {
const data = JSON.parse(json);
return new MySqlBlock(data.id, data.name, data.dependency, data.query, data.uri, data.autoRefresh);
return new MySqlBlock(data.id, data.name, data.dependency, data.query, data.uri, data.autoRefresh, data.skipSqlModeInit ?? false);
}
}
Loading