@webx-ui/module-vacancies 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/VacanciesPage.d.ts +22 -0
- package/dist/VacancyCreateDialog.d.ts +4 -0
- package/dist/VacancyEditorPage.d.ts +21 -0
- package/dist/VacancyHistory.d.ts +2 -0
- package/dist/api.d.ts +47 -0
- package/dist/days.d.ts +22 -0
- package/dist/editor.d.ts +19 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1296 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +13 -0
- package/dist/module.d.ts +22 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +104 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 webx-ui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @webx-ui/module-vacancies
|
|
2
|
+
|
|
3
|
+
The front end of the vacancies section of the [WebX UI](https://github.com/webx-ui/webx-ui) admin
|
|
4
|
+
panel: who the organisation is looking for — where and how, the terms and the pay, the duties, the
|
|
5
|
+
requirements and what is offered — and the categories they are grouped under.
|
|
6
|
+
|
|
7
|
+
The other half is the Composer package `webx-ui/module-vacancies`, which owns the vacancies, their
|
|
8
|
+
pages and addresses, the `JobPosting` markup, `vacancies()` for templates and the API. A section
|
|
9
|
+
appears in the panel when both halves are installed.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @webx-ui/module-vacancies
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createAdmin } from '@webx-ui/module-admin'
|
|
19
|
+
import { vacancies } from '@webx-ui/module-vacancies'
|
|
20
|
+
import '@webx-ui/module-vacancies/style.css'
|
|
21
|
+
|
|
22
|
+
createAdmin({
|
|
23
|
+
basePath: '/cms',
|
|
24
|
+
modules: [...vacancies()],
|
|
25
|
+
}).mount()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`vacancies()` answers with two sections — the vacancies and their categories — because the panel
|
|
29
|
+
draws one entry per module. The server puts both in the `vacancies` group.
|
|
30
|
+
`vacancies({ path: '/careers' })` puts them somewhere else inside the panel.
|
|
31
|
+
|
|
32
|
+
## What is here
|
|
33
|
+
|
|
34
|
+
- **The list** — every vacancy at once, in the order the site lists them, with tabs: the open ones
|
|
35
|
+
(the default), the closed ones, all — the closed ones dimmed, marked «Closed» or «Expired» — and
|
|
36
|
+
the bin. The order is dragged by a handle, or with the keyboard on it, on «Open» and «All» while
|
|
37
|
+
nothing narrows the list; the line under the rows says why when it cannot be. The category and
|
|
38
|
+
the state are behind the funnel. «Duplicate» and «Close the hiring» / «Reopen» are in the row
|
|
39
|
+
menu.
|
|
40
|
+
- **The editor** — the described screen `vacancies.form` with the tabs Vacancy · Settings · SEO ·
|
|
41
|
+
History, autosaved into a draft and guarded by a revision. «Open until» and «Posted on» are
|
|
42
|
+
calendar days (`YYYY-MM-DD`) and read the same day in every zone. «Duplicate» in the bar saves,
|
|
43
|
+
copies and opens the copy. The categories, the application form and «closed» wait in the draft and
|
|
44
|
+
reach the site on «Publish». A project adds its own fields with a patch into the
|
|
45
|
+
`project-fields` card.
|
|
46
|
+
- **Categories** — the panel's shared category screens (`categoryRoutes`): groups with a key for
|
|
47
|
+
the site's filter, no page of their own. `vacancyCategoriesOptions()` is exported for a panel
|
|
48
|
+
that mounts them elsewhere.
|
|
49
|
+
|
|
50
|
+
The words are English by default and come from the server in the panel's language
|
|
51
|
+
(`webx-vacancies::`).
|
|
52
|
+
|
|
53
|
+
Documentation: https://webx-ui.github.io/webx-ui/guide/vacancies.html
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every vacancy at once, in the order the site lists them (§4.10).
|
|
3
|
+
*
|
|
4
|
+
* The shape of the recipes, with the tabs of the events: no paginator, because this is where the
|
|
5
|
+
* order is dragged and a drag cannot cross a page — a site has tens of vacancies, not thousands.
|
|
6
|
+
* The tabs are *open or closed*, not the state: the open ones are what the site lists and what an
|
|
7
|
+
* editor comes here for, so they are the list with nothing chosen. "All" draws the closed ones
|
|
8
|
+
* muted, so the line between the two can be seen at a glance; the category, the state and the
|
|
9
|
+
* search narrow any of them.
|
|
10
|
+
*
|
|
11
|
+
* One order, and only one (§4.11). The grips are there on "Open" and "All" while nothing narrows
|
|
12
|
+
* the list — a selection has invisible gaps in it, and a closed vacancy is on no list of the site,
|
|
13
|
+
* so ordering the "Closed" tab would be ordering nothing. The line under the rows says which of
|
|
14
|
+
* the three it is.
|
|
15
|
+
*/
|
|
16
|
+
type __VLS_Props = {
|
|
17
|
+
base?: string;
|
|
18
|
+
};
|
|
19
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
20
|
+
base: string;
|
|
21
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
22
|
+
export default _default;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {
|
|
2
|
+
field: HTMLDivElement;
|
|
3
|
+
}, any>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor of one vacancy: a head that stays put, the described screen under it, and the bar
|
|
3
|
+
* along the bottom where it is saved, duplicated and published (§4.10).
|
|
4
|
+
*
|
|
5
|
+
* Everything between the head and the bar is `vacancies.form` — the vacancy, its settings, the SEO
|
|
6
|
+
* card `module-seo` patches on and the history — so a project adds its own field with a patch
|
|
7
|
+
* rather than a fork of this file. Saving is by autosave into the draft, and the draft carries
|
|
8
|
+
* the categories, the form and "closed" too: the site changes, all of it at once, only on
|
|
9
|
+
* "Publish". Edits are guarded by a revision: a save over somebody else's is refused with a 409
|
|
10
|
+
* and the question of which version the site gets.
|
|
11
|
+
*
|
|
12
|
+
* The two dates are calendar days, not moments (decision 13): the pickers hold `YYYY-MM-DD` as
|
|
13
|
+
* written, and the head prints them from their parts (`days.ts`), so no zone moves them.
|
|
14
|
+
*/
|
|
15
|
+
type __VLS_Props = {
|
|
16
|
+
base?: string;
|
|
17
|
+
};
|
|
18
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
19
|
+
base: string;
|
|
20
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
2
|
+
export default _default;
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AdminContext } from '@webx-ui/module-admin';
|
|
2
|
+
import { VacanciesList, VacancyDetail, VacancyInput, VacancyQuery, VacancyRow, VacancySave, VacancyVersion } from './types';
|
|
3
|
+
export interface VacanciesApi {
|
|
4
|
+
/** Every vacancy the query asks for, with what the list can be narrowed by. */
|
|
5
|
+
list(query?: VacancyQuery): Promise<VacanciesList>;
|
|
6
|
+
/** One vacancy as its editor opens it: the record, the screen's values and the revision. */
|
|
7
|
+
get(id: number): Promise<VacancyDetail>;
|
|
8
|
+
/** A new vacancy, made in one transaction: a refused address leaves no bare row behind. */
|
|
9
|
+
create(input: VacancyInput): Promise<VacancyDetail>;
|
|
10
|
+
/**
|
|
11
|
+
* Save the draft. Refused with a 409 when the revision is stale — the body is a
|
|
12
|
+
* {@link VacancyConflict} with the vacancy as it now is.
|
|
13
|
+
*/
|
|
14
|
+
save(id: number, input: VacancySave): Promise<VacancyDetail>;
|
|
15
|
+
/** Throw away what is waiting and keep what the site is showing. */
|
|
16
|
+
discard(id: number): Promise<VacancyDetail>;
|
|
17
|
+
/**
|
|
18
|
+
* A copy as a draft that was never published (decision 20): every field, the categories and
|
|
19
|
+
* the form, the same title and an address with the next free suffix, right after the original.
|
|
20
|
+
* The answer is the copy's form, so the editor can open it straight away.
|
|
21
|
+
*/
|
|
22
|
+
duplicate(id: number): Promise<VacancyDetail>;
|
|
23
|
+
publish(id: number): Promise<VacancyRow>;
|
|
24
|
+
unpublish(id: number): Promise<VacancyRow>;
|
|
25
|
+
/**
|
|
26
|
+
* The hiring is over, before its last day — or it is on again. A publication of its own on the
|
|
27
|
+
* server (`is_closed` is published with everything else), so it is refused with a 409 while
|
|
28
|
+
* edits are waiting: closing would put them on the site too.
|
|
29
|
+
*/
|
|
30
|
+
close(id: number): Promise<VacancyRow>;
|
|
31
|
+
reopen(id: number): Promise<VacancyRow>;
|
|
32
|
+
remove(id: number): Promise<void>;
|
|
33
|
+
restore(id: number): Promise<VacancyRow>;
|
|
34
|
+
/** The order on screen, written as a whole. There is one order and only one. */
|
|
35
|
+
reorder(ids: number[]): Promise<void>;
|
|
36
|
+
/** The publications, newest first. */
|
|
37
|
+
versions(id: number): Promise<VacancyVersion[]>;
|
|
38
|
+
/** An old publication becomes the draft; putting it on the site is a separate step. */
|
|
39
|
+
restoreVersion(id: number, number: number): Promise<VacancyDetail>;
|
|
40
|
+
}
|
|
41
|
+
/** The path of the list under the panel's API. */
|
|
42
|
+
export declare const VACANCIES_API = "vacancies";
|
|
43
|
+
/**
|
|
44
|
+
* Everything under `/vacancies`, below the panel's API path (§4.11) — except the categories, which
|
|
45
|
+
* are the panel's shared category API under `vacancies/categories`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createVacanciesApi(admin: AdminContext): VacanciesApi;
|
package/dist/days.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A vacancy's dates are calendar days (decision 13): `valid_through` is the last day it is open,
|
|
3
|
+
* `posted_at` the day it was first put up, both `YYYY-MM-DD` with no time and no zone.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here may turn such a day into a moment. `new Date('2026-11-30')` is midnight *UTC*, and
|
|
6
|
+
* west of Greenwich that is still the 29th — the column would print the day before the one the
|
|
7
|
+
* editor picked, and the site (which reads the day as written) would disagree with the panel. So
|
|
8
|
+
* the day is built from its parts, at local midnight, and formatted from there: the same three
|
|
9
|
+
* numbers in every zone.
|
|
10
|
+
*
|
|
11
|
+
* The pickers of `vacancies.form` do the same by themselves: `valueFormat: "yyyy-MM-dd"` parses
|
|
12
|
+
* and formats in the browser's own zone, so a day goes in and comes out unchanged.
|
|
13
|
+
*/
|
|
14
|
+
/** The day as a local date, or `null` for anything that is not a `YYYY-MM-DD`. */
|
|
15
|
+
export declare function dayOf(value: string | null | undefined): Date | null;
|
|
16
|
+
/**
|
|
17
|
+
* The day in the panel's language — "30 Nov", and with the year when it is not this one. Empty
|
|
18
|
+
* for no day at all.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatDay(value: string | null | undefined, locale: string, now?: Date): string;
|
|
21
|
+
/** The same day, in full — for a tip and for the head of the editor. */
|
|
22
|
+
export declare function longDay(value: string | null | undefined, locale: string): string;
|
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { InjectionKey, Ref } from 'vue';
|
|
2
|
+
import { VacancyRow } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* What the editor knows and the nodes of `vacancies.form` do not: the vacancy being edited, and a
|
|
5
|
+
* way to read it again. The history needs both — its list is keyed by the vacancy, and a restored
|
|
6
|
+
* version has to reach the fields the form is bound to.
|
|
7
|
+
*/
|
|
8
|
+
export interface VacancyEditorContext {
|
|
9
|
+
/** The vacancy as the server last answered it, or `null` while the first request is out. */
|
|
10
|
+
vacancy: Ref<VacancyRow | null>;
|
|
11
|
+
/** Whether this administrator may write at all. */
|
|
12
|
+
canManage: boolean;
|
|
13
|
+
/** Ask the server for the vacancy again — after a restore, a publication, a discard. */
|
|
14
|
+
reload(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare const vacancyEditorKey: InjectionKey<VacancyEditorContext>;
|
|
17
|
+
export declare function provideVacancyEditor(editor: VacancyEditorContext): void;
|
|
18
|
+
/** The editor above this node, or `null` outside one — a demo or a test draws nothing. */
|
|
19
|
+
export declare function useVacancyEditor(): VacancyEditorContext | null;
|
package/dist/i18n.d.ts
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { vacancies, vacancyCategoriesOptions, type VacanciesOptions } from './module';
|
|
2
|
+
export { createVacanciesApi, VACANCIES_API, type VacanciesApi } from './api';
|
|
3
|
+
export { vacanciesMessages } from './messages';
|
|
4
|
+
export { provideVacancyEditor, vacancyEditorKey, useVacancyEditor, type VacancyEditorContext, } from './editor';
|
|
5
|
+
export { default as WxVacanciesPage } from './VacanciesPage';
|
|
6
|
+
export { default as WxVacancyCreateDialog } from './VacancyCreateDialog';
|
|
7
|
+
export { default as WxVacancyEditorPage } from './VacancyEditorPage';
|
|
8
|
+
export { default as WxVacancyHistory } from './VacancyHistory';
|
|
9
|
+
export type { VacanciesList, VacancyClosedReason, VacancyConflict, VacancyDetail, VacancyInput, VacancyQuery, VacancyRow, VacancySave, VacancyState, VacancyStatus, VacancyTermRef, VacancyVersion, VacancyWorkplace, } from './types';
|