Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
feat: create projects without explicit path (#605)
Browse files Browse the repository at this point in the history
* feat: create projects without explicit path

* fix: assume draft status for all files in app path

* chore: update testing deps

* fix: determine draft save location correctly
  • Loading branch information
marionebl authored and Palmaswell committed Sep 17, 2018
1 parent 7a7186b commit 9612f21
Show file tree
Hide file tree
Showing 26 changed files with 913 additions and 968 deletions.
1,421 changes: 569 additions & 852 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"@types/webpack-env": "1.13.6",
"@types/ws": "5.1.0",
"babel-core": "6.26.3",
"babel-jest": "23.4.2",
"babel-jest": "23.6.0",
"concurrently": "3.5.1",
"css-loader": "1.0.0",
"devtron": "1.4.0",
Expand Down Expand Up @@ -174,6 +174,7 @@
"fuse.js": "3.2.0",
"get-port": "3.2.0",
"import-fresh": "2.0.0",
"is-path-inside": "2.0.0",
"is-plain-object": "2.0.4",
"js-yaml": "3.11.0",
"loader-utils": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/view-switch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const ViewSwitch: React.SFC<ViewSwitchProps> = (props): JSX.Element => (
size={IconSize.XS}
visible={props.leftVisible}
/>
<StyledTitle>{props.children}</StyledTitle>
<StyledTitle grow>{props.children}</StyledTitle>
<StyledChevron
color={Color.Grey60}
is={ChevronRight}
Expand Down
9 changes: 9 additions & 0 deletions src/container/chrome/chrome-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const ChromeContainer = MobxReact.inject('store')(
onLeftClick={toPreviousPage}
onRightClick={toNextPage}
>
<ProjectName name={project.getName()} draft={project.getDraft()} />{' '}
{page.getName()}
</ViewSwitch>
<div style={{ display: 'flex', justifySelf: 'right', alignItems: 'center' }}>
Expand Down Expand Up @@ -94,3 +95,11 @@ export const ChromeContainer = MobxReact.inject('store')(
);
})
);

export interface ProjectNameProps {
draft: boolean;
name: string;
}

const ProjectName: React.SFC<ProjectNameProps> = props =>
props.draft ? <i>{props.name}</i> : <>{props.name}</>;
95 changes: 64 additions & 31 deletions src/electron/create-file-message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import * as Fs from 'fs';
import * as Message from '../message';
import * as MimeTypes from 'mime-types';
import * as Model from '../model';
import { Persistence, PersistenceState } from '../persistence';
import * as Path from 'path';
import { Persistence } from '../persistence';
import { showOpenDialog } from './show-open-dialog';
import { showSaveDialog } from './show-save-dialog';
import * as Types from '../types';
import * as Util from 'util';
import * as uuid from 'uuid';

import {
ServerMessageHandlerContext,
ServerMessageHandlerInjection
} from './create-server-message-handler';

const isPathInside = require('is-path-inside');
const readFile = Util.promisify(Fs.readFile);

export async function createFileMessageHandler(
Expand All @@ -22,38 +25,27 @@ export async function createFileMessageHandler(
return async function fileMessageHandler(message: Message.Message): Promise<void> {
switch (message.type) {
case Message.MessageType.CreateNewFileRequest: {
const path = await showSaveDialog({
title: 'Create New Alva File',
defaultPath: 'Untitled Project.alva',
filters: [
{
name: 'Alva File',
extensions: ['alva']
}
]
});
const draftPath = Path.join(ctx.appPath, `${uuid.v4()}.alva`);

if (path) {
const project = Model.Project.create({
name: 'Untitled Project',
path
});
ctx.project = Model.Project.create({
draft: true,
name: 'New Project',
path: draftPath
});

ctx.project = project;
await Persistence.persist(draftPath, ctx.project);
injection.ephemeralStore.setProjectPath(draftPath);

await Persistence.persist(path, project);
injection.ephemeralStore.setProjectPath(path);
injection.sender.send({
type: Message.MessageType.CreateNewFileResponse,
id: message.id,
payload: {
path: draftPath,
contents: ctx.project.toJSON(),
status: Types.ProjectPayloadStatus.Ok
}
});

injection.sender.send({
type: Message.MessageType.CreateNewFileResponse,
id: message.id,
payload: {
path,
contents: project.toJSON(),
status: Types.ProjectPayloadStatus.Ok
}
});
}
break;
}
case Message.MessageType.OpenFileRequest: {
Expand All @@ -66,7 +58,7 @@ export async function createFileMessageHandler(

const projectResult = await Persistence.read<Types.SavedProject>(path);

if (projectResult.state === PersistenceState.Error) {
if (projectResult.state === Types.PersistenceState.Error) {
if (!silent) {
injection.sender.send({
type: Message.MessageType.ShowError,
Expand Down Expand Up @@ -137,8 +129,49 @@ export async function createFileMessageHandler(
return;
}

const publish = message.payload ? message.payload.publish : false;

const getSelectedPath = () =>
showSaveDialog({
title: 'Save Alva File',
defaultPath: 'New Project.alva',
filters: [
{
name: 'Alva File',
extensions: ['alva']
}
]
});

const targetPath = !publish ? ctx.project.getPath() : await getSelectedPath();

if (!targetPath) {
return;
}

ctx.project.setPath(targetPath);
injection.ephemeralStore.setProjectPath(ctx.project.getPath());
await Persistence.persist(ctx.project.getPath(), ctx.project);

const result = await Persistence.persist(targetPath, ctx.project);

ctx.project.setName(
isPathInside(targetPath, ctx.appPath)
? 'New Project'
: Path.basename(ctx.project.getPath(), Path.extname(targetPath))
);

ctx.project.setDraft(ctx.project.getDraft() ? !publish : false);

injection.sender.send({
id: uuid.v4(),
transaction: message.transaction,
type: Message.MessageType.SaveResult,
payload: {
result,
draft: ctx.project.getDraft(),
name: ctx.project.getName()
}
});
}
}
};
Expand Down
33 changes: 29 additions & 4 deletions src/electron/create-main-menu/create-file-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MainMenuContext } from '.';
import { MessageType } from '../../message';
import { Sender } from '../../sender/server';
import * as uuid from 'uuid';
import * as Types from '../../types';

export interface FileMenuInjection {
sender: Sender;
Expand All @@ -13,6 +14,9 @@ export function createFileMenu(
injection: FileMenuInjection
): Electron.MenuItemConstructorOptions {
const activePage = ctx.project && ctx.project.getPages().find(p => p.getActive());
const hasPage = typeof activePage !== 'undefined';
const hasProject = typeof ctx.project !== 'undefined';
const onDetailView = ctx.app.getActiveView() !== Types.AlvaView.SplashScreen;

return {
label: '&File',
Expand Down Expand Up @@ -44,7 +48,7 @@ export function createFileMenu(
},
{
label: 'New &Page',
enabled: typeof ctx.project !== 'undefined',
enabled: hasProject && onDetailView,
accelerator: 'CmdOrCtrl+Shift+N',
click: () => {
injection.sender.send({
Expand All @@ -59,14 +63,35 @@ export function createFileMenu(
},
{
label: '&Save',
enabled: typeof ctx.project !== 'undefined',
enabled: hasProject && onDetailView,
accelerator: 'CmdOrCtrl+S',
role: 'save',
click: async () => {
if (!ctx.project) {
return;
}

injection.sender.send({
type: MessageType.Save,
id: uuid.v4(),
payload: undefined
payload: { publish: ctx.project.getDraft() }
});
}
},
{
label: '&Save As',
enabled: hasProject && onDetailView,
accelerator: 'CmdOrCtrl+Shift+S',
role: 'save',
click: async () => {
if (!ctx.project) {
return;
}

injection.sender.send({
type: MessageType.Save,
id: uuid.v4(),
payload: { publish: true }
});
}
},
Expand All @@ -75,7 +100,7 @@ export function createFileMenu(
},
{
label: 'Export Prototype as HTML',
enabled: Boolean(activePage),
enabled: hasPage && onDetailView,
accelerator: 'CmdOrCtrl+E',
click: async () => {
if (!ctx.project) {
Expand Down
11 changes: 7 additions & 4 deletions src/electron/create-main-menu/create-library-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ export function createLibraryMenu(
injection: LibraryMenuInjection
): Electron.MenuItemConstructorOptions {
const project = ctx.project;
const hasProject = typeof ctx.project !== 'undefined';
const onDetailView = ctx.app.getActiveView() !== Types.AlvaView.SplashScreen;
const libraries = project ? project.getPatternLibraries() : [];
const hasConnectedLibrary = libraries.some(
lib => lib.getState() === Types.PatternLibraryState.Connected
);

return {
label: '&Library',
submenu: [
{
label: '&Connect New Library',
enabled: typeof ctx.project !== 'undefined',
enabled: hasProject && onDetailView,
accelerator: 'CmdOrCtrl+Shift+C',
click: () => {
if (typeof ctx.project === 'undefined') {
Expand All @@ -37,9 +42,7 @@ export function createLibraryMenu(
},
{
label: '&Update All Libraries',
enabled:
typeof ctx.project !== 'undefined' &&
libraries.some(lib => lib.getState() === Types.PatternLibraryState.Connected),
enabled: hasProject && onDetailView && hasConnectedLibrary,
accelerator: 'CmdOrCtrl+U',
click: () => {
if (!project) {
Expand Down
1 change: 1 addition & 0 deletions src/electron/create-server-message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { createLibraryMessageHandler } from './create-library-message-handler';

export interface ServerMessageHandlerContext {
app: undefined | Model.AlvaApp;
appPath: string;
port: undefined | number;
project: undefined | Model.Project;
win: undefined | Electron.BrowserWindow;
Expand Down
1 change: 1 addition & 0 deletions src/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const importFresh = require('import-fresh');

const CONTEXT: AppContext = Mobx.observable({
app: undefined,
appPath: Electron.app.getPath('userData'),
base: '',
port: undefined,
project: undefined,
Expand Down
33 changes: 33 additions & 0 deletions src/electron/show-discard-dialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as Electron from 'electron';
import { Project } from '../model';

export enum DiscardDialogResult {
Save,
Cancel,
Discard
}

export async function showDiscardDialog(project: Project): Promise<DiscardDialogResult> {
return new Promise<DiscardDialogResult>(resolve => {
Electron.dialog.showMessageBox(
Electron.BrowserWindow.getFocusedWindow(),
{
type: 'warning',
message: `Do you want to save the changes you made to ${project.getName()}?`,
detail: "Your changes will be lost if you don't save them.",
buttons: ['Save', 'Cancel', "Don't Save"]
},
response => {
switch (response) {
case 0:
return resolve(DiscardDialogResult.Save);
case 2:
return resolve(DiscardDialogResult.Discard);
case 1:
default:
return resolve(DiscardDialogResult.Cancel);
}
}
);
});
}
Loading

0 comments on commit 9612f21

Please sign in to comment.