Skip to content

Commit

Permalink
Rearrange file manager again
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Aug 8, 2024
1 parent f4cdf93 commit d2c163b
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 96 deletions.
30 changes: 30 additions & 0 deletions src/lib/files/ExportFile.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts" generics="StateType">
import { type Writable } from "svelte/store";
import { ButtonGroup, SecondaryButton } from "govuk-svelte";
import downloadUrl from "$lib/assets/images/download.svg?url";
import { downloadGeneratedFile } from "./index";
export let currentFile: Writable<string>;
// eslint-disable-next-line no-undef
export let state: Writable<StateType>;
function exportFile() {
downloadGeneratedFile($currentFile + ".json", JSON.stringify($state));
}
</script>

<p><b>You are editing: {$currentFile}</b></p>

<ButtonGroup>
<SecondaryButton on:click={exportFile}>
<img src={downloadUrl} alt="Export .json" />
Export .json
</SecondaryButton>
<slot />
</ButtonGroup>

<style>
img {
vertical-align: middle;
}
</style>
161 changes: 71 additions & 90 deletions src/lib/files/FileManager.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
<script lang="ts" generics="StateType">
import editUrl from "$lib/assets/images/edit.svg?url";
import deleteUrl from "$lib/assets/images/delete.svg?url";
import downloadUrl from "$lib/assets/images/download.svg?url";
import { base } from "$app/paths";
import { LocalStorageFiles } from "./index";
import { LocalStorageFiles, downloadGeneratedFile } from "./index";
import {
ButtonGroup,
FileInput,
WarningButton,
SecondaryButton,
Radio,
AlphaBanner,
StartButton,
} from "govuk-svelte";
import { pairs, stripSuffix, ServiceHeader } from "$lib";
import { type Writable } from "svelte/store";
Expand All @@ -32,74 +29,49 @@
| ((buffer: ArrayBuffer) => Promise<StateType>)
| null = null;
let chosenFile = $currentFile;
let fileList = files.getFileList();
function loadChosenFile() {
if (!chosenFile) {
return;
}
openFile(chosenFile);
}
function renameFile() {
function renameFile(filename: string) {
// TODO Handle overwriting
let newName = window.prompt(
`Rename file ${$currentFile} to what?`,
$currentFile,
);
let newName = window.prompt(`Rename file ${filename} to what?`, filename);
if (newName) {
let oldKey = files.key($currentFile);
let oldKey = files.key(filename);
let contents = window.localStorage.getItem(oldKey)!;
window.localStorage.setItem(files.key(newName), contents);
window.localStorage.removeItem(oldKey);
$currentFile = newName;
chosenFile = $currentFile;
fileList = files.getFileList();
if ($currentFile == filename) {
$currentFile = newName;
}
}
}
function deleteFile() {
function deleteFile(filename: string) {
// TODO Use a full Modal
if (
!window.confirm(
`Really delete file ${$currentFile}? You can't undo this. (If you delete, a copy will still be downloaded to your browser's download folder, in case you make a mistake.)`,
`Really delete file ${filename}? You can't undo this. (If you delete, a copy will still be downloaded to your browser's download folder, in case you make a mistake.)`,
)
) {
return;
}
let key = files.key($currentFile);
let key = files.key(filename);
downloadGeneratedFile(
`${$currentFile}.json`,
`${filename}.json`,
window.localStorage.getItem(key)!,
);
window.localStorage.removeItem(key);
$currentFile = "";
chosenFile = "";
$state = files.emptyState();
fileList = files.getFileList();
// This is normally done in the LocalStorageFiles subscription, but it
// ignores the case when this value is empty. Since the last opened
// file is gone, we do need to clear this.
window.localStorage.setItem(files.key("last-opened-file"), "");
}
function exportFile() {
downloadGeneratedFile($currentFile + ".json", JSON.stringify($state));
}
function downloadGeneratedFile(filename: string, textInput: string) {
let element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(textInput),
);
element.setAttribute("download", filename);
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
if ($currentFile == filename) {
$currentFile = "";
$state = files.emptyState();
// This is normally done in the LocalStorageFiles subscription, but it
// ignores the case when this value is empty. Since the last opened
// file is gone, we do need to clear this.
window.localStorage.setItem(files.key("last-opened-file"), "");
}
fileList = files.getFileList();
}
function newFile() {
Expand All @@ -109,9 +81,9 @@
return;
}
$currentFile = name;
chosenFile = name;
$state = files.emptyState();
fileList = files.saveAndGetFileList($currentFile, $state);
goto(`${base}/${files.prefix}overview`);
}
function importJsonFile(rawFilename: string, contents: string) {
Expand All @@ -136,15 +108,18 @@
openFile(filename);
}
function openFile(file: string) {
function openFile(file: string): boolean {
try {
let x = files.loadFile(file);
chosenFile = file;
$currentFile = file;
$state = x;
goto(`${base}/${files.prefix}overview`);
} catch (error) {
window.alert(`Couldn't load ${file}: ${error}`);
}
// So this can be a callback on an <a>
return false;
}
</script>

Expand All @@ -168,30 +143,54 @@
{#if $currentFile}
<p>
<b>You are editing:</b>
{$currentFile}
<a href={`${base}/${files.prefix}overview`}>{$currentFile}</a>
</p>
<StartButton on:click={() => goto(`${base}/${files.prefix}overview`)} />

<ButtonGroup>
<SecondaryButton on:click={exportFile}>
<img src={downloadUrl} alt="Export .json" />
Export .json
</SecondaryButton>

<slot name="export" />

<SecondaryButton on:click={renameFile}>
<img src={editUrl} alt="Rename file" />
Rename file
</SecondaryButton>
<WarningButton on:click={deleteFile}>
<img src={deleteUrl} alt="Delete file" />
Delete file
</WarningButton>
</ButtonGroup>
{/if}

<h2>Create or import a file</h2>
{#if fileList.length > 0}
<h2>Manage existing files</h2>
<table>
<thead>
<tr>
<th>File name</th>
<th>Scheme name</th>
<th class="govuk-!-width-one-half">Action</th>
</tr>
</thead>
<tbody>
{#each fileList as filename}
<tr>
<td>
<!-- svelte-ignore a11y-invalid-attribute -->
<a
href="#"
on:click|preventDefault={() => openFile(filename)}
>
{filename}
</a>
</td>
<td>TODO</td>
<td>
<ButtonGroup>
<SecondaryButton on:click={() => renameFile(filename)}>
Rename
</SecondaryButton>
<WarningButton on:click={() => deleteFile(filename)}>
Delete
</WarningButton>
</ButtonGroup>
</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p>No saved files</p>
{/if}
</div>

<div class="govuk-grid-column-one-third">
<h2 class="green-bar">Create or import a file</h2>
<SecondaryButton on:click={newFile}>New blank file</SecondaryButton>
<hr />
<FileInput label="Import from a .json file" onLoad={importJsonFile} />
Expand All @@ -201,20 +200,6 @@
<ImportXlsx {xlsxImporter} on:imported={onXlsxImported} />
{/if}
</div>
<div class="govuk-grid-column-one-third">
<h2 class="green-bar">Manage existing files</h2>

{#if fileList.length > 0}
<Radio
label=""
choices={pairs(fileList)}
bind:value={chosenFile}
on:change={loadChosenFile}
/>
{:else}
<p>No saved files</p>
{/if}
</div>
</div>
</div>

Expand All @@ -223,8 +208,4 @@
border-top: 0.3rem solid #007161;
padding-top: 30px;
}
img {
vertical-align: middle;
}
</style>
13 changes: 13 additions & 0 deletions src/lib/files/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as FileManager } from "./FileManager.svelte";
export { default as ExportFile } from "./ExportFile.svelte";
import { get, type Writable } from "svelte/store";

export class LocalStorageFiles<StateType> {
Expand Down Expand Up @@ -128,3 +129,15 @@ export class LocalStorageFiles<StateType> {
console.log(`Not starting with any file`);
}
}

export function downloadGeneratedFile(filename: string, textInput: string) {
let element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(textInput),
);
element.setAttribute("download", filename);
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
6 changes: 6 additions & 0 deletions src/routes/area_check/overview/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { base } from "$app/paths";
import { ExternalLink } from "$lib";
import { currentFile, state } from "../data";
import { ExportFile } from "$lib/files";
</script>

<div class="govuk-width-container">
Expand All @@ -12,6 +14,10 @@
</ExternalLink>.
</p>

<ExportFile {currentFile} {state} />

<p>Check what you need to do to assess the design quality of a scheme.</p>

<ol>
<li><a href="{base}/area_check/summary">Summary of Scheme</a></li>
<li>
Expand Down
6 changes: 6 additions & 0 deletions src/routes/cross_section/overview/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { base } from "$app/paths";
import { ExternalLink } from "$lib";
import { currentFile, state } from "../data";
import { ExportFile } from "$lib/files";
</script>

<div class="govuk-width-container">
Expand All @@ -12,6 +14,10 @@
</ExternalLink>.
</p>

<ExportFile {currentFile} {state} />

<p>Check what you need to do to assess the design quality of a scheme.</p>

<ol>
<li><a href="{base}/cross_section/summary">Summary of Scheme</a></li>
<li><a href="{base}/cross_section/proposed">Proposed Cross-Sections</a></li>
Expand Down
8 changes: 8 additions & 0 deletions src/routes/planning/overview/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
<script lang="ts">
import { base } from "$app/paths";
import { currentFile, state } from "../data";
import { ExportFile } from "$lib/files";
</script>

<div class="govuk-width-container">
<p>This is an experimental version of an internal tool.</p>

<ExportFile {currentFile} {state} />

<p>
Check what you need to do to assess the design quality of an application.
</p>

<ol>
<li><a href="{base}/planning/app_details">Application details</a></li>
<li><a href="{base}/planning/scorecard">Scorecard</a></li>
Expand Down
5 changes: 0 additions & 5 deletions src/routes/route_check/+page@.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { files, currentFile, state, type State } from "./data";
import { getDalog, dalogToState } from "$lib/import";
import ExcelJS from "exceljs";
import ConvertToXlsx from "./results_export/ConvertToXlsx.svelte";
async function xlsxImporter(buffer: ArrayBuffer): Promise<State> {
let workbook = new ExcelJS.Workbook();
Expand All @@ -26,8 +25,4 @@
wishing to assess the design quality of schemes against ATE's quality
criteria.
</p>

<svelte:fragment slot="export">
<ConvertToXlsx />
</svelte:fragment>
</FileManager>
Loading

0 comments on commit d2c163b

Please sign in to comment.