Skip to content

Commit

Permalink
Merge pull request #2055 from DamnClin/modules-list
Browse files Browse the repository at this point in the history
Simple modules screen
  • Loading branch information
pascalgrimaud authored Jun 14, 2022
2 parents 88126bb + 57bcb28 commit f6519c5
Show file tree
Hide file tree
Showing 21 changed files with 446 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/main/webapp/app/loader/primary/Loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export class Loader<T> {
private assignedValue?: T;

private constructor(private loading: boolean) {}

public static loading<T>(): Loader<T> {
return new Loader(true);
}

public static loaded<T>(value: T): Loader<T> {
const result = this.loading<T>();

result.loaded(value);

return result;
}

isLoading(): boolean {
return this.loading;
}

loaded(value: T) {
this.assignedValue = value;

this.loading = false;
}

value(): T {
if (this.assignedValue === undefined) {
throw new Error('Trying to get the value of a loading item');
}

return this.assignedValue;
}
}
3 changes: 3 additions & 0 deletions src/main/webapp/app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import 'bootstrap-icons/font/bootstrap-icons.css';
import 'bootstrap';
import '../content/css/custom.css';
import { MittAlertListener } from '@/common/secondary/alert/MittAlertListener';
import { RestModulesRepository } from './module/secondary/RestModulesRepository';

const app = createApp(App);
const pinia = createPinia();
Expand All @@ -45,6 +46,7 @@ const reactRepository = new ReactRepository(axiosHttp, projectHistoryRepository)
const springBootRepository = new SpringBootRepository(axiosHttp, projectHistoryRepository);
const svelteRepository = new SvelteRepository(axiosHttp, projectHistoryRepository);
const vueRepository = new VueRepository(axiosHttp, projectHistoryRepository);
const modulesRepository = new RestModulesRepository(axiosHttp);

app.provide('alertBus', alertBus);
app.provide('alertListener', alertListener);
Expand All @@ -60,6 +62,7 @@ app.provide('reactService', reactRepository);
app.provide('springBootService', springBootRepository);
app.provide('vueService', vueRepository);
app.provide('svelteService', svelteRepository);
app.provide('modules', modulesRepository);
app.use(router);

app.mount('#app');
8 changes: 8 additions & 0 deletions src/main/webapp/app/module/domain/Category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from './Module';

type CategoryName = string;

export interface Category {
name: CategoryName;
modules: Module[];
}
8 changes: 8 additions & 0 deletions src/main/webapp/app/module/domain/Module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ModuleSlug } from './ModuleSlug';

type ModuleDescription = string;

export interface Module {
slug: ModuleSlug;
description: ModuleDescription;
}
5 changes: 5 additions & 0 deletions src/main/webapp/app/module/domain/ModuleProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ModuleProperty } from './ModuleProperty';

export interface ModuleProperties {
properties: ModuleProperty[];
}
12 changes: 12 additions & 0 deletions src/main/webapp/app/module/domain/ModuleProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ModulePropertyType = 'STRING' | 'INTEGER' | 'BOOLEAN';
export type ModulePropertyKey = string;
export type ModulePropertyDescription = string;
export type ModulePropertyExample = string;

export interface ModuleProperty {
type: ModulePropertyType;
mandatory: boolean;
key: ModulePropertyKey;
description?: ModulePropertyDescription;
example?: ModulePropertyExample;
}
1 change: 1 addition & 0 deletions src/main/webapp/app/module/domain/ModuleSlug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type ModuleSlug = string;
5 changes: 5 additions & 0 deletions src/main/webapp/app/module/domain/Modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Category } from './Category';

export interface Modules {
categories: Category[];
}
8 changes: 8 additions & 0 deletions src/main/webapp/app/module/domain/ModulesRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ModuleProperties } from './ModuleProperties';
import { Modules } from './Modules';
import { ModuleSlug } from './ModuleSlug';

export interface ModulesRepository {
list(): Promise<Modules>;
get(slug: ModuleSlug): Promise<ModuleProperties>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Loader } from '@/loader/primary/Loader';
import { Modules } from '@/module/domain/Modules';
import { ModulesRepository } from '@/module/domain/ModulesRepository';
import { defineComponent, inject, onMounted, reactive } from 'vue';

export default defineComponent({
name: 'ModulesListVue',
setup() {
const modules = inject('modules') as ModulesRepository;

const modulesContent = reactive({
content: Loader.loading<Modules>(),
});

onMounted(() => {
modules.list().then(response => modulesContent.content.loaded(response));
});

return {
content: modulesContent.content,
};
},
});
16 changes: 16 additions & 0 deletions src/main/webapp/app/module/primary/modules-list/ModulesList.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="jhipster-modules-list">
<h1 data-selector="modules-title" class="jhister-modules-title">Modules</h1>

<div data-selector="modules-loader" v-if="content.isLoading()">Loading</div>
<div data-selector="modules-list" v-else>
<div v-for="category in content.value().categories">
<div class="jhipster-module-category">
<h2 class="jhipster-module-category--name">{{ category.name }}</h2>
<div v-for="module in category.modules" class="jhipster-module" :data-selector="`${module.slug}-module`">
<div class="jhipster-module--slug">{{ module.slug }}</div>
<div class="jhipster-module--description">{{ module.description}}</div>
</div>
</div>
</div>
</div>
</div>
50 changes: 50 additions & 0 deletions src/main/webapp/app/module/primary/modules-list/ModulesList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template src="./ModulesList.html"></template>

<script lang="ts" src="./ModulesList.component.ts"></script>

<style>
* {
color: #29293b;
}
.jhipster-modules-list {
max-width: 1200px;
margin: auto;
}
.jhister-modules-title {
font-size: 2em;
}
.jhipster-module {
border-radius: 2em;
border: 1px solid #29293b;
margin: 1em 0;
display: grid;
grid-template-columns: 25% auto;
grid-gap: 10px;
grid-auto-rows: minmax(2em, auto);
align-items: center;
}
.jhipster-module--slug {
grid-column: 1 / 2;
grid-row: 1;
border-radius: 2em;
padding: 0.5em 1.5em;
margin-right: 0.5em;
background-color: #29293b;
color: #fff;
font-weight: bold;
text-align: center;
}
.jhipster-module--description {
grid-column: 2 / 2;
grid-row: 1;
}
.jhipster-module-category--name {
font-size: 1.5em;
}
</style>
3 changes: 3 additions & 0 deletions src/main/webapp/app/module/primary/modules-list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ModulesListVue from './ModulesList.vue';

export { ModulesListVue };
73 changes: 73 additions & 0 deletions src/main/webapp/app/module/secondary/RestModulesRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { AxiosHttp } from '@/http/AxiosHttp';
import { AxiosResponse } from 'axios';
import { Modules } from '../domain/Modules';
import { Category } from '../domain/Category';
import { Module } from '../domain/Module';
import { ModulesRepository } from '../domain/ModulesRepository';
import { ModuleProperties } from '../domain/ModuleProperties';
import { ModuleSlug } from '../domain/ModuleSlug';
import { ModuleProperty, ModulePropertyType } from '../domain/ModuleProperty';

export interface RestModules {
categories: RestCategory[];
}

export interface RestCategory {
name: string;
modules: RestModule[];
}

export interface RestModule {
slug: string;
description: string;
}

export interface RestModuleProperties {
definitions: RestModuleProperty[];
}

export interface RestModuleProperty {
type: ModulePropertyType;
mandatory: boolean;
key: string;
description?: string;
example?: string;
}

export class RestModulesRepository implements ModulesRepository {
constructor(private axiosInstance: AxiosHttp) {}

list(): Promise<Modules> {
return this.axiosInstance.get<RestModules>('/api/modules').then(mapToModules);
}

get(slug: ModuleSlug): Promise<ModuleProperties> {
return this.axiosInstance.get<RestModuleProperties>(`/api/modules/${slug}`).then(mapToModule);
}
}

const mapToModules = (response: AxiosResponse<RestModules>): Modules => ({
categories: response.data.categories.map(toCategory),
});

const toCategory = (restCategory: RestCategory): Category => ({
name: restCategory.name,
modules: restCategory.modules.map(toModule),
});

const toModule = (restModule: RestModule): Module => ({
slug: restModule.slug,
description: restModule.description,
});

const mapToModule = (response: AxiosResponse<RestModuleProperties>): ModuleProperties => ({
properties: response.data.definitions.map(toProperty),
});

const toProperty = (restProperty: RestModuleProperty): ModuleProperty => ({
type: restProperty.type,
mandatory: restProperty.mandatory,
key: restProperty.key,
description: restProperty.description,
example: restProperty.example,
});
6 changes: 6 additions & 0 deletions src/main/webapp/app/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ModulesListVue } from '@/module/primary/modules-list';
import { GeneratorVue } from '@/springboot/primary';
import { createRouter, createWebHistory } from 'vue-router';

Expand All @@ -11,6 +12,11 @@ const routes = [
name: 'Generator',
component: GeneratorVue,
},
{
path: '/modules',
name: 'ModulesList',
component: ModulesListVue,
},
];

const router = createRouter({
Expand Down
9 changes: 9 additions & 0 deletions src/test/javascript/cypress/integration/Modules.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { dataSelector } from '../support/selector';

describe('Modules', () => {
it('Should display modules', () => {
cy.visit('/modules');

cy.get(dataSelector('modules-title')).contains('Modules');
});
});
1 change: 1 addition & 0 deletions src/test/javascript/spec/WrappedElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const wrappedElement = (selector: string): string => `[data-selector="${selector}"]`;
27 changes: 27 additions & 0 deletions src/test/javascript/spec/loader/primary/Loader.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Loader } from '@/loader/primary/Loader';

describe('Loader', () => {
it('Should be loading for loading loader', () => {
expect(Loader.loading().isLoading()).toBe(true);
});

it('Should not get value for not loaded loader', () => {
expect(() => Loader.loading().value()).toThrow();
});

it('Should build loaded value', () => {
const loader = Loader.loaded('pouet');

expect(loader.isLoading()).toBe(false);
expect(loader.value()).toBe('pouet');
});

it('Should load value', () => {
const loader = Loader.loading();

loader.loaded('pouet');

expect(loader.isLoading()).toBe(false);
expect(loader.value()).toBe('pouet');
});
});
49 changes: 49 additions & 0 deletions src/test/javascript/spec/module/domain/Modules.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Modules } from '@/module/domain/Modules';
import { ModuleProperties } from '@/module/domain/ModuleProperties';
import { ModulesRepository } from '@/module/domain/ModulesRepository';
import sinon, { SinonStub } from 'sinon';

interface ModulesRepositoryStub extends ModulesRepository {
list: SinonStub;
}

export const stubModulesRepository = (): ModulesRepositoryStub =>
({
list: sinon.stub(),
} as ModulesRepositoryStub);

export const defaultModules = (): Modules => ({
categories: [
{
name: 'Spring',
modules: [
{
slug: 'spring-cucumber',
description: 'Add cucumber to the application',
},
],
},
],
});

export const defaultModuleProperties = (): ModuleProperties => ({
properties: [
{
type: 'STRING',
mandatory: true,
key: 'baseName',
description: 'Application base name',
example: 'jhipster',
},
{
type: 'BOOLEAN',
mandatory: false,
key: 'optionalBoolean',
},
{
type: 'INTEGER',
mandatory: false,
key: 'optionalInteger',
},
],
});
Loading

0 comments on commit f6519c5

Please sign in to comment.