Skip to content

Commit

Permalink
Plugins: Add support for file and directory selector in Settings API
Browse files Browse the repository at this point in the history
  • Loading branch information
laurent22 committed Apr 20, 2022
1 parent 8e5d862 commit fc09598
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 24 deletions.
7 changes: 7 additions & 0 deletions packages/app-cli/tests/support/plugins/settings/api/types.ts
Expand Up @@ -334,6 +334,12 @@ export enum SettingItemType {
Button = 6,
}

export enum SettingItemSubType {
FilePathAndArgs = 'file_path_and_args',
FilePath = 'file_path', // Not supported on mobile!
DirectoryPath = 'directory_path', // Not supported on mobile!
}

export enum AppType {
Desktop = 'desktop',
Mobile = 'mobile',
Expand All @@ -350,6 +356,7 @@ export enum SettingStorage {
export interface SettingItem {
value: any;
type: SettingItemType;
subType?: SettingItemSubType;

label: string;
description?: string;
Expand Down
29 changes: 28 additions & 1 deletion packages/app-cli/tests/support/plugins/settings/src/index.ts
@@ -1,5 +1,5 @@
import joplin from 'api';
import { SettingItemType, ToolbarButtonLocation } from 'api/types';
import { SettingItemSubType, SettingItemType, ToolbarButtonLocation } from 'api/types';

joplin.plugins.register({
onStart: async function() {
Expand Down Expand Up @@ -49,6 +49,33 @@ joplin.plugins.register({
description: 'This setting will be saved to settings.json',
['storage' as any]: 2, // Should be `storage: SettingStorage.File`
},

'myFilePathAndArgs': {
value: '',
type: SettingItemType.String,
subType: SettingItemSubType.FilePathAndArgs,
section: 'myCustomSection',
public: true,
label: 'File path and args',
},

'myFilePathOnly': {
value: '',
type: SettingItemType.String,
subType: SettingItemSubType.FilePath,
section: 'myCustomSection',
public: true,
label: 'File path',
},

'myDirectory': {
value: '',
type: SettingItemType.String,
subType: SettingItemSubType.DirectoryPath,
section: 'myCustomSection',
public: true,
label: 'Directory path',
},
});

await joplin.commands.register({
Expand Down
56 changes: 33 additions & 23 deletions packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx
Expand Up @@ -453,7 +453,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
});
const inputType = md.secure === true ? 'password' : 'text';

if (md.subType === 'file_path_and_args') {
if (md.subType === 'file_path_and_args' || md.subType === 'file_path' || md.subType === 'directory_path') {
inputStyle.marginBottom = subLabel.marginBottom;

const splitCmd = (cmdString: string) => {
Expand Down Expand Up @@ -483,15 +483,41 @@ class ConfigScreenComponent extends React.Component<any, any> {
};

const browseButtonClick = async () => {
const paths = await bridge().showOpenDialog();
if (!paths || !paths.length) return;
const cmd = splitCmd(this.state.settings[key]);
cmd[0] = paths[0];
updateSettingValue(key, joinCmd(cmd));
if (md.subType === 'directory_path') {
const paths = await bridge().showOpenDialog({
properties: ['openDirectory'],
});
if (!paths || !paths.length) return;
updateSettingValue(key, paths[0]);
} else {
const paths = await bridge().showOpenDialog();
if (!paths || !paths.length) return;
const cmd = splitCmd(this.state.settings[key]);
cmd[0] = paths[0];
updateSettingValue(key, joinCmd(cmd));
}
};

const cmd = splitCmd(this.state.settings[key]);

const argComp = md.subType !== 'file_path_and_args' ? null : (
<div style={{ ...rowStyle, marginBottom: 5 }}>
<div style={subLabel}>{_('Arguments:')}</div>
<input
type={inputType}
style={inputStyle}
onChange={(event: any) => {
onArgsChange(event);
}}
value={cmd[1]}
spellCheck={false}
/>
<div style={{ width: inputStyle.width, minWidth: inputStyle.minWidth }}>
{descriptionComp}
</div>
</div>
);

return (
<div key={key} style={rowStyle}>
<div style={labelStyle}>
Expand Down Expand Up @@ -519,25 +545,9 @@ class ConfigScreenComponent extends React.Component<any, any> {
/>
</div>
</div>
<div style={{ ...rowStyle, marginBottom: 5 }}>
<div style={subLabel}>{_('Arguments:')}</div>
<input
type={inputType}
style={inputStyle}
onChange={(event: any) => {
onArgsChange(event);
}}
value={cmd[1]}
spellCheck={false}
/>
<div style={{ width: inputStyle.width, minWidth: inputStyle.minWidth }}>
{descriptionComp}
</div>
</div>
</div>
</div>


{argComp}
</div>
);
} else {
Expand Down
6 changes: 6 additions & 0 deletions packages/lib/models/Setting.ts
Expand Up @@ -25,6 +25,12 @@ export enum SettingItemType {
Button = 6,
}

export enum SettingItemSubType {
FilePathAndArgs = 'file_path_and_args',
FilePath = 'file_path', // Not supported on mobile!
DirectoryPath = 'directory_path', // Not supported on mobile!
}

interface KeysOptions {
secureOnly?: boolean;
}
Expand Down
1 change: 1 addition & 0 deletions packages/lib/services/plugins/api/JoplinSettings.ts
Expand Up @@ -112,6 +112,7 @@ export default class JoplinSettings {
description: (_appType: string) => setting.description,
};

if ('subType' in setting) internalSettingItem.subType = setting.subType;
if ('isEnum' in setting) internalSettingItem.isEnum = setting.isEnum;
if ('section' in setting) internalSettingItem.section = this.namespacedKey(setting.section);
if ('options' in setting) internalSettingItem.options = () => setting.options;
Expand Down
12 changes: 12 additions & 0 deletions packages/lib/services/plugins/api/types.ts
Expand Up @@ -364,6 +364,12 @@ export enum SettingItemType {
Button = 6,
}

export enum SettingItemSubType {
FilePathAndArgs = 'file_path_and_args',
FilePath = 'file_path', // Not supported on mobile!
DirectoryPath = 'directory_path', // Not supported on mobile!
}

export enum AppType {
Desktop = 'desktop',
Mobile = 'mobile',
Expand All @@ -381,6 +387,12 @@ export interface SettingItem {
value: any;
type: SettingItemType;

/**
* Currently only used to display a file or directory selector. Always set
* `type` to `SettingItemType.String` when using this property.
*/
subType?: SettingItemSubType;

label: string;
description?: string;

Expand Down

0 comments on commit fc09598

Please sign in to comment.