diff --git a/zero.Api/Endpoints/Integrations/IntegrationsController.cs b/zero.Api/Endpoints/Integrations/IntegrationsController.cs index ad84a171..89611c5f 100644 --- a/zero.Api/Endpoints/Integrations/IntegrationsController.cs +++ b/zero.Api/Endpoints/Integrations/IntegrationsController.cs @@ -1,43 +1,41 @@ //using Microsoft.AspNetCore.Mvc; -//using System.Collections.Generic; -//using System.Threading.Tasks; -//using zero.Core.Collections; -//using zero.Core.Entities; -//using zero.Core.Integrations; -//using zero.Web.Models; -//namespace zero.Web.Controllers +//namespace zero.Api.Endpoints.Integrations; + +//public class IntegrationsController : ZeroApiController //{ -// //[ZeroAuthorize(Permissions.Sections.PREFIX + "commerce", PermissionsValue.Read)] -// public class IntegrationsController : BackofficeController +// public IntegrationsController(IIntegrationService store) // { -// IIntegrationsCollection Collection; -// public IntegrationsController(IIntegrationsCollection collection) -// { -// Collection = collection; -// } - - -// public EditModel GetEmpty([FromQuery] string alias) => Edit(Collection.GetEmpty(alias)); - - -// public async Task> GetByAlias([FromQuery] string alias) => Edit(await Collection.GetByAlias(alias)); - - -// public async Task> Load([FromQuery] ListQuery query) => await Collection.Load(query); - - -// public async Task> GetTypes() => await Collection.GetTypesWithStatus(); - - -// [HttpPost] -// public async Task> Save([FromBody] Integration model) => await Collection.Save(model); - -// [HttpPost] -// public async Task> SaveActiveState([FromBody] Integration model) => model.IsActive ? await Collection.Activate(model.Alias) : await Collection.Deactivate(model.Alias); - -// [HttpDelete] -// public async Task> Delete([FromQuery] string alias) => await Collection.DeleteByAlias(alias); // } + + +// [HttpGet("empty")] +// [ZeroAuthorize(LanguagePermissions.Create)] +// public virtual Task> Empty(string flavor = null) => EmptyModel(flavor); + + +// [HttpGet("{id}")] +// [ZeroAuthorize(LanguagePermissions.Read)] +// public virtual Task> Get(string id, string changeVector = null) => GetModel(id, changeVector); + + +// [HttpGet("")] +// [ZeroAuthorize(LanguagePermissions.Read)] +// public virtual Task> Get([FromQuery] ListQuery query) => GetModelsByIndex(query); + + +// [HttpPost("")] +// [ZeroAuthorize(LanguagePermissions.Create)] +// public virtual Task> Create(Language saveModel) => CreateModel(saveModel); + + +// [HttpPut("{id}")] +// [ZeroAuthorize(LanguagePermissions.Update)] +// public virtual Task> Update(string id, Language updateModel, [FromQuery] string changeToken = null) => UpdateModel(id, updateModel, changeToken); + + +// [HttpDelete("{id}")] +// [ZeroAuthorize(LanguagePermissions.Delete)] +// public virtual Task> Delete(string id) => DeleteModel(id); //} \ No newline at end of file diff --git a/zero.Api/Endpoints/Integrations/_IntegrationsController.cs b/zero.Api/Endpoints/Integrations/_IntegrationsController.cs new file mode 100644 index 00000000..ad84a171 --- /dev/null +++ b/zero.Api/Endpoints/Integrations/_IntegrationsController.cs @@ -0,0 +1,43 @@ +//using Microsoft.AspNetCore.Mvc; +//using System.Collections.Generic; +//using System.Threading.Tasks; +//using zero.Core.Collections; +//using zero.Core.Entities; +//using zero.Core.Integrations; +//using zero.Web.Models; + +//namespace zero.Web.Controllers +//{ +// //[ZeroAuthorize(Permissions.Sections.PREFIX + "commerce", PermissionsValue.Read)] +// public class IntegrationsController : BackofficeController +// { +// IIntegrationsCollection Collection; + +// public IntegrationsController(IIntegrationsCollection collection) +// { +// Collection = collection; +// } + + +// public EditModel GetEmpty([FromQuery] string alias) => Edit(Collection.GetEmpty(alias)); + + +// public async Task> GetByAlias([FromQuery] string alias) => Edit(await Collection.GetByAlias(alias)); + + +// public async Task> Load([FromQuery] ListQuery query) => await Collection.Load(query); + + +// public async Task> GetTypes() => await Collection.GetTypesWithStatus(); + + +// [HttpPost] +// public async Task> Save([FromBody] Integration model) => await Collection.Save(model); + +// [HttpPost] +// public async Task> SaveActiveState([FromBody] Integration model) => model.IsActive ? await Collection.Activate(model.Alias) : await Collection.Deactivate(model.Alias); + +// [HttpDelete] +// public async Task> Delete([FromQuery] string alias) => await Collection.DeleteByAlias(alias); +// } +//} \ No newline at end of file diff --git a/zero.Api/Endpoints/Translations/Maps/TranslationBasic.cs b/zero.Api/Endpoints/Translations/Maps/TranslationBasic.cs index fa394ebd..b00a937c 100644 --- a/zero.Api/Endpoints/Translations/Maps/TranslationBasic.cs +++ b/zero.Api/Endpoints/Translations/Maps/TranslationBasic.cs @@ -1,7 +1,13 @@ namespace zero.Api.Endpoints.Translations; -public class TranslationBasic : BasicModel +public class TranslationBasic : ZeroIdEntity { + public string Key { get; set; } + + public DateTimeOffset CreatedDate { get; set; } + + public string Flavor { get; set; } + public string Value { get; set; } public TranslationDisplay Display { get; set; } diff --git a/zero.Api/Endpoints/Translations/Maps/LanguageMapperProfile.cs b/zero.Api/Endpoints/Translations/Maps/TranslationMapperProfile.cs similarity index 88% rename from zero.Api/Endpoints/Translations/Maps/LanguageMapperProfile.cs rename to zero.Api/Endpoints/Translations/Maps/TranslationMapperProfile.cs index c239f3ce..1804cb26 100644 --- a/zero.Api/Endpoints/Translations/Maps/LanguageMapperProfile.cs +++ b/zero.Api/Endpoints/Translations/Maps/TranslationMapperProfile.cs @@ -12,7 +12,10 @@ public class TranslationMapperProfile : ZeroMapperProfile protected virtual void Map(Translation source, TranslationBasic target, IZeroMapperContext ctx) { - this.MapBasicData(source, target); + target.Id = source.Id; + target.Key = source.Key; + target.Flavor = source.Flavor; + target.CreatedDate = source.CreatedDate; target.Value = source.Value; target.Display = source.Display; } diff --git a/zero.Api/Endpoints/Translations/TranslationsController.cs b/zero.Api/Endpoints/Translations/TranslationsController.cs index 107d9eb8..d3d5f031 100644 --- a/zero.Api/Endpoints/Translations/TranslationsController.cs +++ b/zero.Api/Endpoints/Translations/TranslationsController.cs @@ -25,7 +25,7 @@ public class TranslationsController : ZeroApiEntityStoreController> Get([FromQuery] ListQuery query) { query.SearchFor(x => x.Key, x => x.Value); - return GetModelsByIndex(query); + return GetModelsByIndex(query); } diff --git a/zero.Backoffice.UI/app/_about.vue b/zero.Backoffice.UI/app/_about.vue deleted file mode 100644 index 424aa40f..00000000 --- a/zero.Backoffice.UI/app/_about.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - - \ No newline at end of file diff --git a/zero.Backoffice.UI/app/_root.vue b/zero.Backoffice.UI/app/_root.vue deleted file mode 100644 index 54381473..00000000 --- a/zero.Backoffice.UI/app/_root.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/zero.Backoffice.UI/app/app.vue b/zero.Backoffice.UI/app/app.vue index 43b612c8..b014376d 100644 --- a/zero.Backoffice.UI/app/app.vue +++ b/zero.Backoffice.UI/app/app.vue @@ -22,6 +22,7 @@ import { useAccountStore } from './account/store'; import { useUiStore } from './ui/store'; import { useTranslationStore } from './stores/translations'; + import { useAppStore } from './modules/applications/store'; import accountApi from './account/api'; import { defineComponent } from 'vue'; @@ -44,6 +45,7 @@ if (userResponse.success) { this.accountStore.user = userResponse.data; + await useAppStore().setup(); await useUiStore().setup(); } else diff --git a/zero.Backoffice.UI/app/core/router/routerConfig.ts b/zero.Backoffice.UI/app/core/router/routerConfig.ts index 98099556..bcc02c98 100644 --- a/zero.Backoffice.UI/app/core/router/routerConfig.ts +++ b/zero.Backoffice.UI/app/core/router/routerConfig.ts @@ -18,21 +18,8 @@ export function getRouterConfig(basePath: string, zero: Zero): RouterOptions routes: [] } as RouterOptions; - //options.routes.push({ - // name: 'xroot', - // path: '/', - // component: () => import('../../_root.vue'), - // meta: { - // name: 'Root name', - // alias: 'rootalias', - // section: 'Root section' - // } - //} as RouteRecordRaw); - - options.routes.push({ path: '/', component: () => import('../../_root.vue') }); - options.routes.push({ path: '/about', component: () => import('../../_about.vue') }); - - // TODO add zero routes + options.routes.push({ name: 'dashboard', path: '/', redirect: { name: 'pages' } }); + options.routes.push({ name: '404', path: '/:pathMatch(.*)', component: () => import('../../notfound.vue') }); return options; } diff --git a/zero.Backoffice.UI/app/dashboard.vue b/zero.Backoffice.UI/app/dashboard.vue new file mode 100644 index 00000000..f2953a80 --- /dev/null +++ b/zero.Backoffice.UI/app/dashboard.vue @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/applications/store.ts b/zero.Backoffice.UI/app/modules/applications/store.ts new file mode 100644 index 00000000..41dfdc61 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/applications/store.ts @@ -0,0 +1,17 @@ + +import { defineStore } from 'pinia'; +import api from './api'; + +export const useAppStore = defineStore('zero.apps', { + state: () => ({ + applications: [] + }), + + actions: { + async setup() + { + const response = await api.getByQuery({ pageSize: 1000 }); + this.applications = response.data; + } + } +}); \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/api.ts b/zero.Backoffice.UI/app/modules/integrations/api.ts new file mode 100644 index 00000000..0dbc0644 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/api.ts @@ -0,0 +1,24 @@ +import { get, post, put, del, ApiRequestConfig, ApiRequestQuery } from '../../services/request'; + +export default { + + getEmpty: (flavor?: string, config?: ApiRequestConfig) => get("translations/empty", { ...config, params: { flavor } }), + + getById: (id: string, changeVector?: string, config?: ApiRequestConfig) => get('translations/' + id, { ...config, params: { changeVector } }), + + getByQuery: (query: ApiRequestQuery, config?: ApiRequestConfig) => get('translations', { ...config, params: { ...query } }), + + create: (model: any, config?: ApiRequestConfig) => post('translations', model, config), + + update: (model: any, config?: ApiRequestConfig) => put('translations/' + model.id, model, config), + + delete: (id: string, config?: ApiRequestConfig) => del('translations/' + id, null, config), + + //getEmpty: async alias => await get(base + 'getEmpty', { params: { alias } }), + //getTypes: async () => await get(base + 'getTypes'), + //getByAlias: async (alias, config) => await get(base + 'getByAlias', { ...config, params: { alias } }), + //getByQuery: async (query, config) => await get(base + 'getByQuery', { ...config, params: { query } }), + //save: async (model, config) => await post(base + 'save', model, { ...config }), + //saveActiveState: async (model, config) => await post(base + 'saveActiveState', model, { ...config }), + //delete: async alias => await del(base + 'delete', { params: { alias } }) +}; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/index.ts b/zero.Backoffice.UI/app/modules/integrations/index.ts new file mode 100644 index 00000000..5cf56925 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/index.ts @@ -0,0 +1,7 @@ +import api from './api'; +import plugin from './plugin'; + +export { + api as integrationApi, + plugin as integrationPlugin +}; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/integration.vue b/zero.Backoffice.UI/app/modules/integrations/integration.vue new file mode 100644 index 00000000..0ecc1002 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/integration.vue @@ -0,0 +1,49 @@ + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/integrations.vue b/zero.Backoffice.UI/app/modules/integrations/integrations.vue new file mode 100644 index 00000000..ee6166a0 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/integrations.vue @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/plugin.ts b/zero.Backoffice.UI/app/modules/integrations/plugin.ts new file mode 100644 index 00000000..c6423264 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/plugin.ts @@ -0,0 +1,17 @@ +import { ZeroPlugin, ZeroPluginOptions } from '../../core'; +import { defineAsyncComponent } from 'vue'; + +export default { + name: "zero.integrations", + + install(app: ZeroPluginOptions) + { + //app.vue.component('ui-languagepicker', defineAsyncComponent(() => import('./ui-languagepicker.vue'))); + + app.route({ name: 'integrations', path: '/settings/integrations', component: () => import('./integrations.vue') }); + app.route({ name: 'integrations-edit', path: '/settings/integrations/edit/:id?', component: () => import('./integration.vue'), props: true }); + + app.schema('integrations', () => import('./schemas/list')); + app.schema('integrations:edit', () => import('./schemas/editor')); + } +} as ZeroPlugin; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/schemas/editor.ts b/zero.Backoffice.UI/app/modules/integrations/schemas/editor.ts new file mode 100644 index 00000000..af6817f6 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/schemas/editor.ts @@ -0,0 +1,21 @@ + +import { ZeroEditor } from '../../../editor/editor'; + +const editor = new ZeroEditor(); + +editor.resourcePrefix = '@translation.fields.'; + +const set = editor.fieldset(); + +set.field('key').text({ maxLength: 300 }); +set.field('display').state({ + items: [ + { label: '@translation.display.text', value: 0 }, + { label: '@translation.display.html', value: 1 } + ] +}); + +editor.field('value').setHidden(x => x.display === 0).rte(); +editor.field('value').setHidden(x => x.display === 1).textarea(); + +export default editor; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/integrations/schemas/list.ts b/zero.Backoffice.UI/app/modules/integrations/schemas/list.ts new file mode 100644 index 00000000..f7990cff --- /dev/null +++ b/zero.Backoffice.UI/app/modules/integrations/schemas/list.ts @@ -0,0 +1,16 @@ + +import List from '../../../schemas/list/list'; +import api from '../api'; + +const list = new List('translations'); +const prefix = '@translation.fields.'; + +list.templateLabel = x => prefix + x; +list.link = 'translations-edit'; + +list.onFetch(filter => api.getByQuery(filter)); + +list.column('key', { width: 420 }).name(); +list.column('value').text(); + +export default list; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/settings/plugin.ts b/zero.Backoffice.UI/app/modules/settings/plugin.ts index 0f636527..513cf4cb 100644 --- a/zero.Backoffice.UI/app/modules/settings/plugin.ts +++ b/zero.Backoffice.UI/app/modules/settings/plugin.ts @@ -1,17 +1,10 @@ import { ZeroPlugin, ZeroPluginOptions } from '../../core'; -import { defineAsyncComponent } from 'vue'; - -const Page = () => import('./settings.vue'); export default { name: "zero.settings", install(app: ZeroPluginOptions) { - //app.vue.component('ui-countrypicker', defineAsyncComponent(Picker)); - app.route({ path: '/settings', component: Page }); - - //app.editor('country', null); - //app.editorField('') + app.route({ name: 'settings', path: '/settings', component: () => import('./settings.vue') }); } } as ZeroPlugin; \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/settings/settings.vue b/zero.Backoffice.UI/app/modules/settings/settings.vue index 3d8a3bfc..8e186524 100644 --- a/zero.Backoffice.UI/app/modules/settings/settings.vue +++ b/zero.Backoffice.UI/app/modules/settings/settings.vue @@ -6,6 +6,7 @@ + {{appCount}}

@@ -24,12 +25,14 @@ @@ -89,6 +93,7 @@ box-shadow: var(--shadow-short); color: var(--color-text); transition: color 0.2s ease; + position: relative; } a.settings-group-item:hover .settings-group-item-icon @@ -109,4 +114,22 @@ color: var(--color-text); } } + + .settings-group-item-count + { + display: inline-block; + font-size: 11px; + font-weight: 700; + background: var(--color-accent); + color: var(--color-accent-fg); + height: 22px; + width: 22px; + line-height: 22px; + padding: 0 0; + text-align: center; + border-radius: 16px; + position: absolute; + top: -4px; + right: -4px; + } \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/translations/translation.vue b/zero.Backoffice.UI/app/modules/translations/translation.vue index 0ecc1002..bd46422a 100644 --- a/zero.Backoffice.UI/app/modules/translations/translation.vue +++ b/zero.Backoffice.UI/app/modules/translations/translation.vue @@ -1,6 +1,6 @@