Skip to content

Commit

Permalink
update expandable component (#6920)
Browse files Browse the repository at this point in the history
  • Loading branch information
mirnawong1 authored Feb 20, 2025
2 parents 3fe6ca8 + 562b034 commit 7ba93eb
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 44 deletions.
25 changes: 14 additions & 11 deletions website/docs/docs/cloud/dbt-cloud-ide/develop-in-the-cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,24 @@ Nice job, you're ready to start developing and building models 🎉!
- The IDE's idle session timeout is one hour.
- <Expandable alt_header="About the start up process and work retention">

### Start-up process
There are three start-up states when using or launching the Cloud IDE:
- **Creation start &mdash;** This is the state where you are starting the IDE for the first time. You can also view this as a *cold start* (see below), and you can expect this state to take longer because the git repository is being cloned.
- **Cold start &mdash;** This is the process of starting a new develop session, which will be available for you for one hour. The environment automatically turns off one hour after the last activity. This includes compile, preview, or any dbt invocation, however, it *does not* include editing and saving a file.
- **Hot start &mdash;** This is the state of resuming an existing or active develop session within one hour of the last activity.
The following sections describe the start-up process and work retention in the Cloud IDE.

- #### Start-up process
There are three start-up states when using or launching the Cloud IDE:
- **Creation start &mdash;** This is the state where you are starting the IDE for the first time. You can also view this as a *cold start* (see below), and you can expect this state to take longer because the git repository is being cloned.
- **Cold start &mdash;** This is the process of starting a new develop session, which will be available for you for one hour. The environment automatically turns off one hour after the last activity. This includes compile, preview, or any dbt invocation, however, it *does not* include editing and saving a file.
- **Hot start &mdash;** This is the state of resuming an existing or active develop session within one hour of the last activity. <br /><br />

- #### Work retention

### Work retention
The Cloud IDE needs explicit action to save your changes. There are three ways your work is stored:
The Cloud IDE needs explicit action to save your changes. There are three ways your work is stored:

- **Unsaved, local code &mdash;** The browser stores your code only in its local storage. In this state, you might need to commit any unsaved changes in order to switch branches or browsers. If you have saved and committed changes, you can access the "Change branch" option even if there are unsaved changes. But if you attempt to switch branches without saving changes, a warning message will appear, notifying you that you will lose any unsaved changes.
- **Unsaved, local code &mdash;** The browser stores your code only in its local storage. In this state, you might need to commit any unsaved changes in order to switch branches or browsers. If you have saved and committed changes, you can access the "Change branch" option even if there are unsaved changes. But if you attempt to switch branches without saving changes, a warning message will appear, notifying you that you will lose any unsaved changes.

<Lightbox src="/img/docs/dbt-cloud/cloud-ide/ide-unsaved-modal.jpg" width="85%" title="If you attempt to switch branches without saving changes, a warning message will appear, telling you that you will lose your changes."/>
<Lightbox src="/img/docs/dbt-cloud/cloud-ide/ide-unsaved-modal.jpg" width="85%" title="If you attempt to switch branches without saving changes, a warning message will appear, telling you that you will lose your changes."/>

- **Saved but uncommitted code &mdash;** When you save a file, the data gets stored in durable, long-term storage, but isn't synced back to git. To switch branches using the **Change branch** option, you must "Commit and sync" or "Revert" changes. Changing branches isn't available for saved-but-uncommitted code. This is to ensure your uncommitted changes don't get lost.
- **Committed code &mdash;** This is stored in the branch with your git provider and you can check out other (remote) branches.
- **Saved but uncommitted code &mdash;** When you save a file, the data gets stored in durable, long-term storage, but isn't synced back to git. To switch branches using the **Change branch** option, you must "Commit and sync" or "Revert" changes. Changing branches isn't available for saved-but-uncommitted code. This is to ensure your uncommitted changes don't get lost.
- **Committed code &mdash;** This is stored in the branch with your git provider and you can check out other (remote) branches.

</Expandable>

Expand Down
78 changes: 48 additions & 30 deletions website/src/components/expandable/index.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,58 @@
/* eslint-disable */

import React, { useState, useEffect } from 'react';
/* eslint-disable */
import React, { useState, useEffect, useRef } from 'react';
import styles from './styles.module.css';
import Lifecycle from '../lifeCycle';

function slugify(text) {
return text.toString().toLowerCase()
.normalize('NFD') // normalize to nfd unicode form
.replace(/[\u0300-\u036f]/g, '') // remove diacritics
.replace(/\s+/g, '-') // replace spaces with -
.replace(/[^\w\-]+/g, '') // remove all non-word chars
.replace(/\-\-+/g, '-') // replace multiple - with a single -
.replace(/^-+/, '') // trim - from the start
.replace(/-+$/, ''); // trim - from the end
.normalize('NFD') // Normalize to NFD Unicode form
.replace(/[\u0300-\u036f]/g, '') // Remove diacritics
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with a single -
.replace(/^-+/, '') // Trim - from start
.replace(/-+$/, ''); // Trim - from end
}

function Expandable({ children, alt_header = null, lifecycle }) {
if (!alt_header) { return null; }
const [isOn, setOn] = useState(false);
if (!alt_header) return null;

const [isOpen, setIsOpen] = useState(false);
const detailsRef = useRef(null);
const anchorId = slugify(alt_header);

// Handles clicking on the header to expand/collapse
const handleToggleClick = (event) => {
event.preventDefault();
setOn(current => !current);
setIsOpen((prev) => !prev);
};

// Copy link function
const handleCopyClick = (event) => {
event.preventDefault();
event.stopPropagation();
const url = `${window.location.href.split('#')[0]}#${anchorId}`;
navigator.clipboard.writeText(url).then(() => {
showCopyPopup();
});
navigator.clipboard.writeText(url).then(() => showCopyPopup());
};

// Show "Link Copied!" popup
const showCopyPopup = () => {
const popup = document.createElement('div');
popup.classList.add('copy-popup');
popup.innerText = 'Link copied!';

// Add close button ('x')
// Close button ('x')
const closeButton = document.createElement('span');
closeButton.classList.add('close-button');
closeButton.innerHTML = ' &times;'; // '×' symbol for 'x'
closeButton.innerHTML = ' &times;';
closeButton.addEventListener('click', () => {
if (document.body.contains(popup)) {
document.body.removeChild(popup);
}
});
popup.appendChild(closeButton);

popup.appendChild(closeButton);
document.body.appendChild(popup);

setTimeout(() => {
Expand All @@ -59,20 +62,35 @@ function Expandable({ children, alt_header = null, lifecycle }) {
}, 3000);
};

// Auto-expand when linked via hash (URL fragment)
useEffect(() => {
if (window.location.hash === `#${anchorId}`) {
setOn(true);
const element = document.getElementById(anchorId);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
setIsOpen(true);
detailsRef.current?.scrollIntoView({ behavior: 'smooth' });
}
}, [anchorId]);

// Observe search highlight and auto-expand
useEffect(() => {
const observer = new MutationObserver(() => {
const details = detailsRef.current;
if (details && details.querySelector('mark')) {
details.open = true;
}
});

observer.observe(document.body, {
childList: true,
subtree: true,
});

return () => observer.disconnect();
}, []);

return (
<div id={anchorId} className={`${styles.expandableContainer}`}>
<div className={styles.header} onClick={handleToggleClick}>
<span className={`${styles.toggle} ${isOn ? styles.toggleDown : styles.toggleRight}`}></span>
<details ref={detailsRef} id={anchorId} className={styles.expandableContainer} open={isOpen}>
<summary className={styles.header} onClick={handleToggleClick}>
<span className={`${styles.toggle} ${isOpen ? styles.toggleDown : styles.toggleRight}`}></span>
&nbsp;
<span className={styles.headerText}>
{alt_header}
Expand All @@ -81,11 +99,11 @@ function Expandable({ children, alt_header = null, lifecycle }) {
</span>
</span>
<span onClick={handleCopyClick} className={styles.copyIcon}></span>
</div>
<div style={{ display: isOn ? 'block' : 'none' }} className={styles.body}>
</summary>
<div className={styles.body}>
{children}
</div>
</div>
</details>
);
}

Expand Down
9 changes: 6 additions & 3 deletions website/src/components/expandable/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
margin-right: 8px;
}

details[open] :local(.toggle)::before {
transform: rotate(225deg); /* this rotates the chevron down */
}

:local(.toggleDown)::before {
transform: rotate(225deg); /* Downward arrow */
}
Expand Down Expand Up @@ -113,8 +117,8 @@
}

:local(html[data-theme='dark'] details .headerText) {
color: rgba(18, 12, 12, 0.862); /* this adds black text inside details in dark mode */
}
color: rgba(255, 255, 255, 0.9); /* Change to white text in dark mode */
}

:local(.body > p:last-child) {
margin-bottom: 0px;
Expand Down Expand Up @@ -146,4 +150,3 @@
display: flex;
align-items: center;
}

0 comments on commit 7ba93eb

Please sign in to comment.