Skip to content

Commit

Permalink
fea: allow adding repositories and auth methods
Browse files Browse the repository at this point in the history
  • Loading branch information
SychO9 committed Dec 15, 2023
1 parent 361f795 commit 616206e
Show file tree
Hide file tree
Showing 12 changed files with 596 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import Modal, { IInternalModalAttrs } from 'flarum/common/components/Modal';
import Mithril from 'mithril';
import app from 'flarum/admin/app';
import Select from 'flarum/common/components/Select';
import Stream from 'flarum/common/utils/Stream';
import Button from 'flarum/common/components/Button';
import extractText from 'flarum/common/utils/extractText';

export interface IAuthMethodModalAttrs extends IInternalModalAttrs {
onsubmit: (type: string, host: string, token: string) => void;
type?: string;
host?: string;
token?: string;
}

export default class AuthMethodModal<CustomAttrs extends IAuthMethodModalAttrs = IAuthMethodModalAttrs> extends Modal<CustomAttrs> {
protected type!: Stream<string>;
protected host!: Stream<string>;
protected token!: Stream<string>;

oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
super.oninit(vnode);

this.type = Stream(this.attrs.type || 'bearer');
this.host = Stream(this.attrs.host || '');
this.token = Stream(this.attrs.token || '');
}

className(): string {
return 'AuthMethodModal Modal--small';
}

title(): Mithril.Children {
return app.translator.trans('flarum-package-manager.admin.auth_config.add_button_label');
}

content(): Mithril.Children {
const types = {
'github-oauth': app.translator.trans('flarum-package-manager.admin.auth_config.types.github-oauth'),
'gitlab-oauth': app.translator.trans('flarum-package-manager.admin.auth_config.types.gitlab-oauth'),
'gitlab-token': app.translator.trans('flarum-package-manager.admin.auth_config.types.gitlab-token'),
bearer: app.translator.trans('flarum-package-manager.admin.auth_config.types.bearer'),
};

return (
<div className="Modal-body">
<div className="Form-group">
<label>{app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.type_label')}</label>
<Select options={types} value={this.type()} onchange={this.type} />
</div>
<div className="Form-group">
<label>{app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.host_label')}</label>
<input
className="FormControl"
bidi={this.host}
placeholder={app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.host_placeholder')}
/>
</div>
<div className="Form-group">
<label>{app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.token_label')}</label>
<textarea
className="FormControl"
oninput={(e: InputEvent) => this.token((e.target as HTMLTextAreaElement).value)}
rows="6"
placeholder={
this.token() === '***'
? extractText(app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.unchanged_token_placeholder'))
: ''
}
>
{this.token() === '***' ? '' : this.token()}
</textarea>
</div>
<div className="Form-group">
<Button className="Button Button--primary" onclick={this.submit.bind(this)}>
{app.translator.trans('flarum-package-manager.admin.auth_config.add_modal.submit_button')}
</Button>
</div>
</div>
);
}

submit() {
this.attrs.onsubmit(this.type(), this.host(), this.token());
this.hide();
}
}
105 changes: 105 additions & 0 deletions extensions/package-manager/js/src/admin/components/ConfigureAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import app from 'flarum/admin/app';
import type Mithril from 'mithril';
import ConfigureJson, { IConfigureJson } from './ConfigureJson';
import Button from 'flarum/common/components/Button';
import AuthMethodModal from './AuthMethodModal';
import extractText from 'flarum/common/utils/extractText';

export default class ConfigureAuth extends ConfigureJson<IConfigureJson> {
protected type = 'auth';

title(): Mithril.Children {
return app.translator.trans('flarum-package-manager.admin.auth_config.title');
}

className(): string {
return 'ConfigureAuth';
}

content(): Mithril.Children {
const authSettings = Object.keys(this.settings);

return (
<div className="SettingsGroups-content">
{authSettings.length ? (
authSettings.map((type) => {
const hosts = this.settings[type]();

return (
<div className="Form-group">
<label>{app.translator.trans(`flarum-package-manager.admin.auth_config.types.${type}`)}</label>
<div className="ConfigureAuth-hosts">
{Object.keys(hosts).map((host) => {
const data = hosts[host] as string | Record<string, string>;

return (
<div className="ButtonGroup ButtonGroup--full">
<Button
className="Button"
icon="fas fa-key"
onclick={() =>
app.modal.show(AuthMethodModal, {
type,
host,
token: data,
onsubmit: this.onchange.bind(this),
})
}
>
{host}
</Button>
<Button
className="Button Button--icon"
icon="fas fa-trash"
aria-label={app.translator.trans('flarum-package-manager.admin.auth_config.delete_label')}
onclick={() => {
if (confirm(extractText(app.translator.trans('flarum-package-manager.admin.auth_config.delete_confirmation')))) {
const newType = { ...this.setting(type)() };
delete newType[host];

if (Object.keys(newType).length) {
this.setting(type)(newType);
} else {
delete this.settings[type];
}
}
}}
/>
</div>
);
})}
</div>
</div>
);
})
) : (
<span className="helpText">{app.translator.trans('flarum-package-manager.admin.auth_config.no_auth_methods_configured')}</span>
)}
</div>
);
}

submitButton(): Mithril.Children[] {
const items = super.submitButton();

items.push(
<Button
className="Button"
loading={this.loading}
onclick={() =>
app.modal.show(AuthMethodModal, {
onsubmit: this.onchange.bind(this),
})
}
>
{app.translator.trans('flarum-package-manager.admin.auth_config.add_button_label')}
</Button>
);

return items;
}

onchange(type: string, host: string, token: string) {
this.setting(type)({ ...this.setting(type)(), [host]: token });
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
import app from 'flarum/admin/app';
import type Mithril from 'mithril';
import Component, { type ComponentAttrs } from 'flarum/common/Component';
import { CommonSettingsItemOptions, type SettingsComponentOptions } from '@flarum/core/src/admin/components/AdminPage';
import AdminPage from 'flarum/admin/components/AdminPage';
import type ItemList from 'flarum/common/utils/ItemList';
import Stream from 'flarum/common/utils/Stream';
import ConfigureJson, { type IConfigureJson } from './ConfigureJson';
import Button from 'flarum/common/components/Button';
import extractText from 'flarum/common/utils/extractText';
import RepositoryModal from './RepositoryModal';

export interface IConfigureComposer extends ComponentAttrs {
buildSettingComponent: (entry: ((this: this) => Mithril.Children) | SettingsComponentOptions) => Mithril.Children;
}
export type Repository = {
type: 'composer' | 'vcs' | 'path';
url: string;
};

export default class ConfigureComposer<CustomAttrs extends IConfigureComposer = IConfigureComposer> extends Component<CustomAttrs> {
protected settings: Record<string, Stream<any>> = {};
protected initialSettings: Record<string, any> | null = null;
protected loading: boolean = false;
export default class ConfigureComposer extends ConfigureJson<IConfigureJson> {
protected type = 'composer';

oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
super.oninit(vnode);
title(): Mithril.Children {
return app.translator.trans('flarum-package-manager.admin.composer.title');
}

this.submit();
className(): string {
return 'ConfigureComposer';
}

view(): Mithril.Children {
content(): Mithril.Children {
return (
<div className="Form">
<div className="SettingsGroups-content">
{this.attrs.buildSettingComponent.call(this, {
setting: 'minimum-stability',
label: app.translator.trans('flarum-package-manager.admin.composer.minimum_stability.label'),
Expand All @@ -38,53 +37,72 @@ export default class ConfigureComposer<CustomAttrs extends IConfigureComposer =
dev: app.translator.trans('flarum-package-manager.admin.composer.minimum_stability.options.dev'),
},
})}

<div className="Form-group">
<Button className="Button Button--primary" loading={this.loading} onclick={this.submit.bind(this)} disabled={!this.isDirty()}>
{app.translator.trans('core.admin.settings.submit_button')}
</Button>
<label>{app.translator.trans('flarum-package-manager.admin.composer.repositories.label')}</label>
<div className="helpText">{app.translator.trans('flarum-package-manager.admin.composer.repositories.help')}</div>
<div className="ConfigureComposer-repositories">
{Object.keys(this.setting('repositories')() || {}).map((key) => {
const repository = this.setting('repositories')()[key] as Repository;

return (
<div className="ButtonGroup ButtonGroup--full">
<Button
className="Button"
icon={
{
composer: 'fas fa-cubes',
vcs: 'fas fa-code-branch',
path: 'fas fa-folder',
}[repository.type]
}
onclick={() =>
app.modal.show(RepositoryModal, {
key,
repository,
onsubmit: this.onchange.bind(this),
})
}
>
{key} ({repository.type})
</Button>
<Button
className="Button Button--icon"
icon="fas fa-trash"
aria-label={app.translator.trans('flarum-package-manager.admin.composer.delete_repository_label')}
onclick={() => {
if (confirm(extractText(app.translator.trans('flarum-package-manager.admin.composer.delete_repository_confirmation')))) {
const repositories = { ...this.setting('repositories')() };
delete repositories[key];

this.setting('repositories')(repositories);
}
}}
/>
</div>
);
})}
</div>
</div>
</div>
);
}

customSettingComponents(): ItemList<(attributes: CommonSettingsItemOptions) => Mithril.Children> {
return AdminPage.prototype.customSettingComponents();
}

setting(key: string) {
return this.settings[key] ?? (() => null);
}

submit() {
this.loading = true;
submitButton(): Mithril.Children[] {
const items = super.submitButton();

const configuration: any = {};

Object.keys(this.settings).forEach((key) => {
configuration[key] = this.settings[key]();
});

app
.request({
method: 'POST',
url: app.forum.attribute('apiUrl') + '/package-manager/composer',
body: { data: configuration },
})
.then(({ data }: any) => {
Object.keys(data).forEach((key) => {
this.settings[key] = Stream(data[key]);
});
items.push(
<Button className="Button" onclick={() => app.modal.show(RepositoryModal, { onsubmit: this.onchange.bind(this) })}>
{app.translator.trans('flarum-package-manager.admin.composer.add_repository_label')}
</Button>
);

this.initialSettings = data;
})
.finally(() => {
this.loading = false;
m.redraw();
});
return items;
}

isDirty() {
return JSON.stringify(this.initialSettings) !== JSON.stringify(this.settings);
onchange(repository: Repository, key: string) {
this.setting('repositories')({
...this.setting('repositories')(),
[key]: repository,
});
}
}
Loading

0 comments on commit 616206e

Please sign in to comment.