Merge pull request #7 from kaermorchen/keys

Keys
This commit is contained in:
Stanislav Romanov 2022-09-19 14:04:57 +03:00 committed by GitHub
commit 222b5eaf8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 312 additions and 45 deletions

View file

@ -0,0 +1,26 @@
import Controller from '@ember/controller';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
export default class AdminKeysKeyDeleteController extends Controller {
@service router;
@service meilisearch;
@service toasts;
@action
delete() {
return this.meilisearch.deleteKey(this.model.uid).then(() => {
// TODO: add toast
return this.router.transitionTo('admin.keys');
});
}
@action
cancel() {
const newRouteName = this.router.currentRouteName.replace(
/\.(new|edit|delete)$/,
''
);
this.router.transitionTo(newRouteName);
}
}

View file

@ -0,0 +1,49 @@
import Controller from '@ember/controller';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import ActionInvoker from 'meiliadmin/lib/action-invoker';
export default class AdminKeysKeyEditController extends Controller {
@service router;
@service toasts;
@tracked error;
@tracked isSaving;
constructor() {
super(...arguments);
this.invoker = new ActionInvoker();
}
@action
async save(value) {
this.error = null;
this.isSaving = true;
try {
const key = await this.model.save(value);
if (this.router.isActive('admin.keys.key')) {
await this.router.refresh('admin.keys.key', key.uid);
}
await this.router.transitionTo('admin.keys.key.index', key.uid);
} catch (error) {
this.error = error.error || error;
} finally {
this.isSaving = false;
}
}
@action
cancel() {
const newRouteName = this.router.currentRouteName.replace(
/\.(new|edit|delete)$/,
''
);
this.router.transitionTo(newRouteName);
}
}

49
app/models/key.js Normal file
View file

@ -0,0 +1,49 @@
import query from '../utils/query';
export default class Key {
actions = ['*'];
indexes = ['*'];
expiresAt = null;
name = '';
description = '';
constructor(data = {}) {
for (const key in data) {
this[key] = data[key];
}
}
get path() {
return `keys/${this.uid}`;
}
get isNew() {
return Boolean(!this.uid);
}
get editablePayload() {
let keys = ['name', 'description'];
if (this.isNew) {
keys = keys.concat(['actions', 'indexes', 'expiresAt', 'uid']);
}
return Object.fromEntries(
Object.entries(this).filter(([key]) => keys.includes(key))
);
}
save(data) {
const path = this.isNew ? 'keys' : this.path;
const method = this.isNew ? 'POST' : 'PATCH';
if (typeof data === 'object') {
data = JSON.stringify(data);
}
return query(path, {
method: method,
body: data,
});
}
}

View file

@ -25,7 +25,11 @@ Router.map(function () {
this.route('new');
});
this.route('keys', function () {
this.route('key', { path: '/:uid' });
this.route('key', { path: '/:uid' }, function () {
this.route('edit');
this.route('delete');
});
this.route('new');
});
this.route('tasks', function () {
this.route('task', { path: '/:uid' });

View file

@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class AdminKeysKeyDeleteRoute extends Route {}

View file

@ -0,0 +1,12 @@
import Route from '@ember/routing/route';
// import { hash } from 'rsvp';
export default class AdminKeysKeyEditRoute extends Route {
// async model() {
// const key = this.modelFor('admin.admin.keys.key');
// return hash({
// key,
// // document:
// });
// }
}

View file

@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class AdminKeysKeyIndexRoute extends Route {}

View file

@ -0,0 +1,11 @@
import Route from '@ember/routing/route';
import Key from 'meiliadmin/models/key';
export default class AdminKeysNewRoute extends Route {
templateName = 'admin.keys.key.edit';
controllerName = 'admin.keys.key.edit';
model() {
return new Key();
}
}

View file

@ -1,5 +1,6 @@
import Service from '@ember/service';
import Index from '../models/index';
import Key from '../models/key';
import Task from '../models/task';
import query from '../utils/query';
@ -34,11 +35,20 @@ export default class MeilisearchService extends Service {
}
getKeys() {
return query('keys');
return query('keys').then((data) => {
data.results = data.results.map((item) => new Key(item));
return data;
});
}
getKey(uid) {
return query(`keys/${uid}`);
return query(`keys/${uid}`).then((item) => new Key(item));
}
deleteKey(uid) {
return query(`keys/${uid}`, {
method: 'DELETE',
});
}
getTasks(params, options = {}) {

View file

@ -1,11 +1,19 @@
<Headers::H1 @title='Keys' />
<LinkTo
@route='admin.keys.new'
class='inline-block mb-4'
>
Create new key
</LinkTo>
<SimpleTable @data={{@model.results}} class='w-full' as |Column data|>
<Column @prop='name'>
<Column @name="Name or uid">
<LinkTo @route='admin.keys.key' @model={{data.uid}}>
{{data.name}}
{{nu-co data.name data.uid}}
</LinkTo>
</Column>
<Column @prop='actions' />
<Column @prop='indexes' />
<Column @prop='expiresAt' />
</SimpleTable>

View file

@ -1,40 +1,9 @@
<Headers::H1 @title={{@model.name}} />
<Headers::H1 @title={{nu-co @model.name @model.uid}} />
<Form::Element @label='description' @value={{@model.description}} />
<Form::Element @label='key' @value={{@model.key}} />
<Form::Element @label='uid' @value={{@model.uid}} />
<Form::Element @label='actions' @value={{@model.actions}} />
<Form::Element @label='indexes' @value={{@model.indexes}} />
<Form::Element @label='expiresAt'>
{{date-time-format
@model.expiresAt
year='numeric'
month='numeric'
day='numeric'
hour='numeric'
minute='numeric'
second='numeric'
}}
</Form::Element>
<Form::Element @label='createdAt'>
{{date-time-format
@model.createdAt
year='numeric'
month='numeric'
day='numeric'
hour='numeric'
minute='numeric'
second='numeric'
}}
</Form::Element>
<Form::Element @label='updatedAt'>
{{date-time-format
@model.updatedAt
year='numeric'
month='numeric'
day='numeric'
hour='numeric'
minute='numeric'
second='numeric'
}}
</Form::Element>
<Tabs>
<Tab @route="admin.keys.key.index" @text="View" @model={{@model}} />
<Tab @route="admin.keys.key.edit" @text="Edit" @model={{@model}} />
<Tab @route="admin.keys.key.delete" @text="Delete" @model={{@model}} />
</Tabs>
{{outlet}}

View file

@ -0,0 +1,12 @@
<p>Are you sure you want to delete this key?</p>
<Button
@text='Yes'
@style='primary'
@onClick={{this.delete}}
/>
<Button
@text='No'
@onClick={{this.cancel}}
/>

View file

@ -0,0 +1,23 @@
{{#if @model.isNew}}
<Headers::H1 @title='Create new key' />
{{/if}}
<div class='mb-4'>
<Form::Element @errors={{array this.error}}>
<MonacoEditor
@value={{json-stringify @model.editablePayload}}
@language='json'
@sendValue={{this.save}}
@invoker={{this.invoker}}
/>
</Form::Element>
<Button
type='submit'
@text='Save'
@style='primary'
@onClick={{fn this.invoker.invoke 'invokeSendValue'}}
@state={{if this.isSaving 'pending'}}
/>
<Button @text='Cancel' @onClick={{this.cancel}} />
</div>

View file

@ -0,0 +1,17 @@
{{#each
(array
'description'
'key'
'uid'
'actions'
'indexes'
'expiresAt'
'createdAt'
'updatedAt'
)
as |key|
}}
{{#if (get @model key)}}
<Form::Element @label={{key}} @value={{get @model key}} />
{{/if}}
{{/each}}

View file

@ -0,0 +1 @@
{{outlet}}

View file

@ -16,7 +16,9 @@ export default function query(path, options = {}) {
);
return fetch(req).then((response) => {
if (response.ok) {
if (response.status === 204) {
return;
} else if (response.ok) {
return response.json();
} else {
throw new Error('Network response was not OK');

View file

@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Controller | admin/keys/key/delete', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let controller = this.owner.lookup('controller:admin/keys/key/delete');
assert.ok(controller);
});
});

View file

@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Controller | admin/keys/key/edit', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let controller = this.owner.lookup('controller:admin/keys/key/edit');
assert.ok(controller);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Route | admin/keys/key/delete', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:admin/keys/key/delete');
assert.ok(route);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Route | admin/keys/key/edit', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:admin/keys/key/edit');
assert.ok(route);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Route | admin/keys/key/index', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:admin/keys/key/index');
assert.ok(route);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'meiliadmin/tests/helpers';
module('Unit | Route | admin/keys/new', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:admin/keys/new');
assert.ok(route);
});
});