Skip to content

Commit

Permalink
Merge pull request mermaid-js#113 from mermaid-js/gists
Browse files Browse the repository at this point in the history
Load data from gists
  • Loading branch information
sidharthv96 authored Aug 15, 2021
2 parents f50d202 + 76aef33 commit c5de0dc
Show file tree
Hide file tree
Showing 17 changed files with 414 additions and 40 deletions.
10 changes: 9 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ module.exports = {
'prettier'
],
plugins: ['svelte3', 'tailwindcss', '@typescript-eslint'],
ignorePatterns: ['docs/*', '*.cjs', '*.md', 'snapshots.js', 'svelte.config.js', 'package.json'],
ignorePatterns: [
'docs/*',
'*.cjs',
'*.md',
'snapshots.js',
'svelte.config.js',
'package.json',
'tsconfig.json'
],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
Expand Down
6 changes: 6 additions & 0 deletions cypress/integration/actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ describe('Check actions', () => {
});
});
});

it('should load gists from URL', () => {
cy.get('#gist').type('https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a');
cy.contains('Load Gist').click();
cy.contains('Go shopping!!');
});
});
27 changes: 27 additions & 0 deletions cypress/integration/loadSite.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,33 @@ describe('Site Loads', () => {
cy.contains('classDiagram');
});

it('should load diagram from gist', () => {
cy.visit(`/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a`);
cy.contains('Go shopping!!');
cy.contains('Revisions');
cy.contains('sidharthv96 v8f8f1e2');
cy.contains('sidharthv96 v7851e19');
cy.getLocalStorage('codeStore').snapshot();
});

it('should load diagram from gist revision', () => {
cy.visit(
'/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/ec9b4ab0e41e4ff6287326cd3cb47affd7851e19'
);
cy.contains('Party');
cy.contains('Revisions');
cy.contains('sidharthv96 v7851e19');
cy.getLocalStorage('codeStore').snapshot();
});

it('should load diagram from raw files', () => {
cy.visit(
'/edit?code=https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/code.mmd&config=https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/config.json'
);
cy.contains('Party');
cy.getLocalStorage('codeStore').snapshot();
});

it('should prevent setting the "securityLevel" option via URL', () => {
const b64State = toBase64(
`{"code":"graph TD\\nA[\\"<img src='https://via.placeholder.com/64' width=64 />\\"]","mermaid":"{\\"securityLevel\\": \\"loose\\", \\"theme\\": \\"forest\\"}","updateEditor":true,"autoSync":true,"updateDiagram":true}`,
Expand Down
11 changes: 10 additions & 1 deletion cypress/snapshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ module.exports = {
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":true,\"autoSync\":true,\"updateDiagram\":true}"
},
"Check Redirect from old URL": {
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":false}"
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true}"
},
"should load diagram from gist": {
"1": "{\"code\":\"graph TD\\n A[Party] -->|Get money| B(Go shopping!!)\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"forest\\\",\\n \\\"test\\\": \\\"hello world\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true,\"loader\":{\"type\":\"gist\",\"config\":{\"url\":\"https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a\"}}}"
},
"should load diagram from gist revision": {
"1": "{\"code\":\"graph TD\\n A[Party] -->|Get money| B(Go shopping)\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"forest\\\",\\n \\\"test\\\": \\\"hello\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true,\"loader\":{\"type\":\"gist\",\"config\":{\"url\":\"https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/ec9b4ab0e41e4ff6287326cd3cb47affd7851e19\"}}}"
},
"should load diagram from raw files": {
"1": "{\"code\":\"graph TD\\n A[Party] -->|Get money| B(Go shopping!!)\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"forest\\\",\\n \\\"test\\\": \\\"hello world\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true,\"loader\":{\"type\":\"files\",\"config\":{\"codeURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/code.mmd\",\"configURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/config.json\"}}}"
}
},
"__version": "8.2.0",
Expand Down
4 changes: 4 additions & 0 deletions src/app.postcss
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
.action-btn {
@apply rounded p-2 bg-indigo-400 shadow flex-auto text-white hover:bg-indigo-500;
}

.input {
@apply flex-1 border-indigo-400 border-solid border-2 rounded;
}
37 changes: 33 additions & 4 deletions src/lib/components/actions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,26 @@
);
};
const onCopyMarkdown = (event: Event) => {
event.target.select();
const onCopyMarkdown = () => {
document.getElementById('markdown').select();
document.execCommand('Copy');
};
let gistURL = '';
codeStore.subscribe((state) => {
if (state.loader?.type === 'gist') {
// @ts-ignore Gist will have url
gistURL = state.loader.config.url;
}
});
const loadGist = () => {
if (!gistURL) {
alert('Please enter a Gist URL first');
}
window.location.href = `${window.location.pathname}?gist=${gistURL}`;
};
let iUrl: string;
let svgUrl: string;
let mdCode: string;
Expand Down Expand Up @@ -162,8 +177,22 @@
</div>

<div class="w-full flex gap-2 items-center">
<label for="markdown">Copy Markdown</label>
<input class="flex-1" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
<label for="markdown">
<button class="btn text-white flex-auto" on:click={onCopyMarkdown}> Copy Markdown </button>
</label>
</div>

<div class="w-full flex gap-2 items-center">
<input
class="input"
id="gist"
type="text"
bind:value={gistURL}
placeholder="Enter Gist URL" />
<label for="gist">
<button class="btn text-white flex-auto" on:click={loadGist}> Load Gist </button>
</label>
</div>
</div>
</Card>
2 changes: 1 addition & 1 deletion src/lib/components/card/tabs.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
export let title: string;
export let isOpen = false;
let activeTabID: string = tabs[0]?.id;
$: activeTabID = tabs[0]?.id;
const dispatch = createEventDispatcher<TabEvents>();
const toggleTabs = (tab: Tab) => {
Expand Down
65 changes: 46 additions & 19 deletions src/lib/components/history/history.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,30 @@
import { codeStore, getStateString } from '$lib/util/state';
import {
addHistoryEntry,
autoHistoryMode,
historyModeStore,
clearHistoryData,
getPreviousState,
historyStore
historyStore,
loaderHistoryStore
} from './history';
import { notify, prompt } from '$lib/util/notify';
import { onMount } from 'svelte';
import moment from 'moment';
import type { State, Tab } from '$lib/types';
import type { HistoryType, State, Tab } from '$lib/types';
const HISTORY_SAVE_INTERVAL = 60000;
const tabSelectHandler = (message: CustomEvent<Tab>) => {
autoHistoryMode.set('timeline' === message.detail.id);
historyModeStore.set(message.detail.id as HistoryType);
};
const tabs: Tab[] = [
let tabs: Tab[] = [
{
id: 'saved',
id: 'manual',
title: 'Saved',
icon: 'far fa-bookmark'
},
{
id: 'timeline',
id: 'auto',
title: 'Timeline',
icon: 'fas fa-history'
}
Expand All @@ -38,7 +39,7 @@
addHistoryEntry({
state: $codeStore,
time: Date.now(),
auto
type: auto ? 'auto' : 'manual'
});
} else if (!auto) {
notify('State already saved.');
Expand All @@ -62,12 +63,26 @@
};
onMount(() => {
autoHistoryMode.set(false);
historyModeStore.set('manual');
setInterval(() => {
saveHistory(true);
}, HISTORY_SAVE_INTERVAL);
});
loaderHistoryStore.subscribe((entries) => {
if (entries.length > 0 && tabs.length === 2) {
tabs = [
{
id: 'loader',
title: 'Revisions',
icon: 'fab fa-git-alt'
},
...tabs
];
historyModeStore.set('loader');
}
});
let isOpen = true;
</script>

Expand All @@ -78,30 +93,42 @@
class="btn"
on:click|stopPropagation={() => saveHistory()}
title="Save current state"><i class="far fa-save" /></button>
<button
id="clearHistory"
class="btn text-red-400"
on:click|stopPropagation={() => clearHistory()}
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
{#if $historyModeStore !== 'loader'}
<button
id="clearHistory"
class="btn text-red-400"
on:click|stopPropagation={() => clearHistory()}
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
{/if}
</div>
<ul class="p-2 space-y-2 overflow-auto h-56" id="historyList">
{#if $historyStore.length > 0}
{#each $historyStore as { state, time, name }}
{#each $historyStore as { state, time, name, url, type }}
<li class="rounded p-2 shadow flex-col">
<div class="flex">
<div class="flex-1">
<div class="flex flex-col">
<span>{name}</span>
{#if url}
<a
href={url}
target="_blank"
title="Open revision in new tab"
class="hover:underline text-blue-500">{name}</a>
{:else}
<span>{name}</span>
{/if}
<span class="text-gray-400 text-sm">{relativeTime(time)}</span>
</div>
</div>
<div class="flex gap-2 content-center">
<button
class="rounded px-2 w-24 bg-green-200 hover:bg-green-300"
on:click={() => restoreHistory(state)}><i class="fas fa-undo" /> Restore</button>
<button
class="rounded px-2 w-24 bg-red-200 hover:bg-red-300"
on:click={() => clearHistory(time)}><i class="fas fa-trash-alt" /> Delete</button>
{#if type !== 'loader'}
<button
class="rounded px-2 w-24 bg-red-200 hover:bg-red-300"
on:click={() => clearHistory(time)}><i class="fas fa-trash-alt" /> Delete</button>
{/if}
</div>
</div>
</li>
Expand Down
38 changes: 27 additions & 11 deletions src/lib/components/history/history.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { derived, Readable, Writable, writable, get } from 'svelte/store';
import { persist, localStorage } from '@macfja/svelte-persistent-store';
import { generateSlug } from 'random-word-slugs';
import type { HistoryEntry } from '../../types';
import type { HistoryEntry, HistoryType } from '$lib/types';

const MAX_AUTO_HISTORY_LENGTH = 30;

export const autoHistoryMode: Writable<boolean> = persist(
writable(true),
export const historyModeStore: Writable<HistoryType> = persist(
writable('manual'),
localStorage(),
'autoHistoryMode'
);
Expand All @@ -23,17 +23,30 @@ const manualHistoryStore: Writable<HistoryEntry[]> = persist(
'manualHistoryStore'
);

export const loaderHistoryStore: Writable<HistoryEntry[]> = writable([] as HistoryEntry[]);

export const historyStore: Readable<HistoryEntry[]> = derived(
[autoHistoryMode, autoHistoryStore, manualHistoryStore],
([autoMode, autoHistories, manualHistories], set) => {
set(autoMode ? autoHistories : manualHistories);
[historyModeStore, autoHistoryStore, manualHistoryStore, loaderHistoryStore],
([historyMode, autoHistories, manualHistories, loadedHistories], set) => {
if (historyMode === 'auto') {
set(autoHistories);
} else if (historyMode === 'manual') {
set(manualHistories);
} else if (historyMode === 'loader') {
set(loadedHistories);
} else {
set(autoHistories);
}
}
);

export const addHistoryEntry = (entry: HistoryEntry): void => {
if (entry.type === 'loader') {
loaderHistoryStore.update((entries) => [entry, ...entries]);
return;
}
entry.name = generateSlug(2);

if (!entry.auto) {
if (entry.type !== 'auto') {
manualHistoryStore.update((entries) => [entry, ...entries]);
return;
}
Expand All @@ -46,9 +59,12 @@ export const addHistoryEntry = (entry: HistoryEntry): void => {
};

export const clearHistoryData = (time?: number): void => {
(get(autoHistoryMode) ? autoHistoryStore : manualHistoryStore).update((entries) =>
entries.filter((entry) => time && entry.time != time)
);
(get(historyModeStore) === 'auto' ? autoHistoryStore : manualHistoryStore).update((entries) => {
if (get(historyModeStore) !== 'loader') {
entries = entries.filter((entry) => time && entry.time != time);
}
return entries;
});
};

export const getPreviousState = (auto: boolean): string => {
Expand Down
23 changes: 22 additions & 1 deletion src/lib/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,32 @@ export interface State {
updateEditor: boolean;
updateDiagram: boolean;
autoSync: boolean;
loader?: LoaderConfig;
}

export interface GistLoaderConfig {
url: string;
}

export interface LoadingState {
loading: boolean;
message?: string;
}
export interface FileLoaderConfig {
codeURL: string;
configURL?: string;
}
export interface LoaderConfig {
type: 'gist' | 'files';
config: GistLoaderConfig | FileLoaderConfig;
}
export type HistoryType = 'auto' | 'manual' | 'loader';
export interface HistoryEntry {
state: State;
time: number;
name?: string;
auto: boolean;
type: HistoryType;
url?: string;
}

type Loader = (url: string) => Promise<State>;
Loading

0 comments on commit c5de0dc

Please sign in to comment.