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
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

.account-events-table {
padding: 0 !important;
border-radius: 1rem;
border-radius: $border-radius-sm;
overflow: hidden;
border: 1px solid $border-color;
height: 100%;
border-radius: 1rem;
& .expandable-table {
table-layout: fixed;
overflow: hidden;
Expand Down
117 changes: 109 additions & 8 deletions apps/frontend/src/components/modals/SQLTerminal/SQLTerminal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,75 @@
}

.terminal-output {
height: 47vh;
height: 40vh;
overflow: hidden;
width: 100%;
resize: none;
font-size: $font-size-base;
white-space: pre-wrap;
padding: 1rem 0 1rem 2rem;
padding: 1rem;
margin-bottom: 1.5rem;
background-color: $body-bg-light;
border-radius: $border-radius;
border-radius: $border-radius-sm;
border: $input-border-width solid $input-border-color;
box-shadow: 0px 1px 2px rgba($dark-blue, 0.05);

& .terminal-json-header {
padding: 1rem 1rem 0.75rem 1rem;
margin-bottom: 0.5rem;
display: flex;
align-items: flex-start;
justify-content: space-between;
}

&.terminal-table-wrapper {
padding: 0;
display: flex;
flex-direction: column;

.terminal-table-header {
padding: 0.75rem 1rem 0.25rem;
margin-bottom: 0.5rem;
display: flex;
align-items: flex-start;
justify-content: space-between;
}

.ps {
flex: 1;
min-height: 0;
overflow: hidden !important;
&.ps--active-x > .ps__rail-x {
display: block !important;
background-color: transparent;
opacity: 1;
z-index: 99;
height: 0.5rem;
& .ps__thumb-x {
height: 0.25rem;
background-color: #DFB316;
}
}
}
}

& .terminal-output-scroll-container {
height: 33vh;
overflow: hidden;
width: 100%;
resize: none;
white-space: pre-wrap;
background-color: transparent;
}
}

.btn-copy-output {
padding: 1rem;
padding: 0;
border: none;
cursor: pointer;
position: absolute;
right: 0;
background: transparent;
z-index: 1;
border-radius: $border-radius;
border-radius: $border-radius-sm;
&:hover,
&:focus-visible {
outline: none;
Expand All @@ -50,9 +96,64 @@
}
}

.sql-table {
height: 100%;
min-width: 100%;
border-collapse: collapse;

& .sql-table-head {
& .sql-table-header-row > th {
color: $primary;
border: 1px solid $border-color;
background-color: $body-bg;
padding: 0.5rem 0.75rem;
position: sticky;
top: 0;
z-index: 1;
}
}

& .sql-table-body {
& .sql-table-row {
background-color: $card-bg;

&:hover {
background-color: $body-bg-light;
}

& > td {
border: 1px solid $border-color;
padding: 0.5rem 0.75rem;
}
}
}
}

@include color-mode(dark) {
.terminal-output {
background-color: $body-bg-dark;
border: $input-border-width solid $input-border-color;
}

.sql-table {
& .sql-table-head {
& .sql-table-header-row > th {
background-color: $tooltip-bg-dark;
border: 1px solid $border-color-dark;
}
}

& .sql-table-body {
& .sql-table-row {
background-color: $card-bg-dark;

&:hover {
background-color: $tooltip-bg-dark;
}

& > td {
border: 1px solid $border-color-dark;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@ describe('SQLTerminal', () => {
cln: mockCLNStoreData,
bkpr: mockBKPRStoreData
};

it('should be in the document', async () => {
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
expect(screen.getByTestId('terminal-container')).not.toBeEmptyDOMElement();
});

it('should render the terminal container', async () => {
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const terminalContainer = screen.getByTestId('terminal-container');
expect(terminalContainer).toBeInTheDocument();
expect(screen.getByTestId('terminal-container')).toBeInTheDocument();
});

it('should display initial placeholder in the input field', async () => {
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
expect(inputField).toBeInTheDocument();
expect(screen.getByTestId('query-input')).toBeInTheDocument();
});

it('should update query state on input change', async () => {
Expand All @@ -40,16 +39,29 @@ describe('SQLTerminal', () => {
expect(inputField).toHaveValue('select * from bkpr_accountevents');
});

it('should call executeSql and display result in the output area', async () => {
it('should call executeSql and display result as table by default', async () => {
spyOnExecuteSql();
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
const executeButton = screen.getByText('Execute');
fireEvent.change(inputField, { target: { value: 'select * from bkpr_accountevents' } });
fireEvent.click(executeButton);
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).toBeInTheDocument();
});
});

it('should display result as JSON when switched to JSON view', async () => {
spyOnExecuteSql();
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
fireEvent.change(inputField, { target: { value: 'select * from bkpr_accountevents' } });
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).toBeInTheDocument();
});
fireEvent.click(screen.getByTestId('toggle-switch'));
await waitFor(() => {
const output = screen.getByTestId('terminal-container').textContent;
expect(output).toContain('select * from bkpr_accountevents');
expect(output).toContain(JSON.stringify(mockSQLResponse.rows, null, 2));
});
});
Expand All @@ -58,39 +70,55 @@ describe('SQLTerminal', () => {
spyOnExecuteSql();
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
const executeButton = screen.getByText('Execute');
fireEvent.change(inputField, { target: { value: 'select * from non_existing_table' } });
fireEvent.click(executeButton);
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
const output = screen.getByTestId('terminal-container').textContent;
expect(output).not.toContain(JSON.stringify(mockSQLResponse.rows, null, 2));
});
});

it('should open the help link when Help button is clicked', async () => {
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const helpButton = screen.getByText('Help');
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const windowOpenSpy = jest.spyOn(window, 'open').mockImplementation(() => null);
fireEvent.click(helpButton);
fireEvent.click(screen.getByText('Help'));
expect(windowOpenSpy).toHaveBeenCalledWith('https://docs.corelightning.org/reference/sql', '_blank');
});

it('should clear the output when Clear button is clicked', async () => {
it('should clear the query and output when Clear button is clicked', async () => {
spyOnExecuteSql();
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
const executeButton = screen.getByText('Execute');
const clearButton = screen.getByText('Clear');
fireEvent.change(inputField, { target: { value: 'select * from bkpr_accountevents' } });
fireEvent.click(executeButton);
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
const output = screen.getByTestId('terminal-container').textContent;
expect(output).toContain('select * from bkpr_accountevents');
expect(output).toContain(JSON.stringify(mockSQLResponse.rows, null, 2));
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).toBeInTheDocument();
});
fireEvent.click(clearButton);
fireEvent.click(screen.getByText('Clear'));
await waitFor(() => {
expect(screen.getByTestId('query-input')).toHaveValue('');
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).not.toBeInTheDocument();
});
});

const outputAfterClear = screen.getByTestId('terminal-container').textContent;
expect(outputAfterClear).not.toContain('select * from bkpr_accountevents');
it('should reset to Table view when Clear button is clicked', async () => {
spyOnExecuteSql();
await renderWithProviders(<SQLTerminal />, { preloadedState: customMockStore });
const inputField = screen.getByTestId('query-input');
fireEvent.change(inputField, { target: { value: 'select * from bkpr_accountevents' } });
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).toBeInTheDocument();
});
fireEvent.click(screen.getByTestId('toggle-switch'));
await waitFor(() => {
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).not.toBeInTheDocument();
});
fireEvent.click(screen.getByText('Clear'));
fireEvent.change(inputField, { target: { value: 'select * from bkpr_accountevents' } });
fireEvent.click(screen.getByText('Execute'));
await waitFor(() => {
expect(screen.getByTestId('terminal-container').querySelector('.sql-table')).toBeInTheDocument();
});
});
});
Loading
Loading