Merge branch 'main' into feature/media-types
This commit is contained in:
@@ -5,20 +5,22 @@ import { UmbContextConsumer } from './context-consumer.js';
|
||||
import { UmbContextRequestEventImplementation, UMB_CONTENT_REQUEST_EVENT_TYPE } from './context-request.event.js';
|
||||
|
||||
const testContextAlias = 'my-test-context';
|
||||
const testContextAliasAndApiAlias = 'my-test-context#testApi';
|
||||
const testContextAliasAndNotExstingApiAlias = 'my-test-context#notExistingTestApi';
|
||||
|
||||
class UmbTestContextConsumerClass {
|
||||
public prop: string = 'value from provider';
|
||||
}
|
||||
|
||||
describe('UmbContextConsumer', () => {
|
||||
let consumer: UmbContextConsumer;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
consumer = new UmbContextConsumer(document.body, testContextAlias, () => {});
|
||||
});
|
||||
|
||||
describe('Public API', () => {
|
||||
let consumer: UmbContextConsumer;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
consumer = new UmbContextConsumer(document.body, testContextAlias, () => {});
|
||||
});
|
||||
|
||||
describe('properties', () => {
|
||||
it('has a instance property', () => {
|
||||
expect(consumer).to.have.property('instance').that.is.undefined;
|
||||
@@ -45,128 +47,178 @@ describe('UmbContextConsumer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('works with UmbContextProvider', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
describe('Simple implementation', () => {
|
||||
it('works with UmbContextProvider', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextConsumerClass | undefined) => {
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextConsumerClass | undefined) => {
|
||||
if (_instance) {
|
||||
expect(_instance.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
}
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
/*
|
||||
Unprovided feature is out commented currently. I'm not sure there is a use case. So lets leave the code around until we know for sure.
|
||||
it('acts to Context API disconnected', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
let callbackNum = 0;
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextConsumerClass | undefined) => {
|
||||
callbackNum++;
|
||||
if (callbackNum === 1) {
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
// unregister.
|
||||
provider.hostDisconnected();
|
||||
} else if (callbackNum === 2) {
|
||||
expect(_instance?.prop).to.be.undefined;
|
||||
done();
|
||||
}
|
||||
}
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
describe('Implementation with Api Alias', () => {
|
||||
it('responds when api alias matches', (done) => {
|
||||
const provider = new UmbContextProvider(
|
||||
document.body,
|
||||
testContextAliasAndApiAlias,
|
||||
new UmbTestContextConsumerClass(),
|
||||
);
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(element, testContextAliasAndApiAlias, (_instance) => {
|
||||
if (_instance) {
|
||||
expect((_instance as UmbTestContextConsumerClass).prop).to.eq('value from provider');
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
done();
|
||||
}
|
||||
});
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('does not respond to a non existing api alias', (done) => {
|
||||
const provider = new UmbContextProvider(
|
||||
document.body,
|
||||
testContextAliasAndApiAlias,
|
||||
new UmbTestContextConsumerClass(),
|
||||
);
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(element, testContextAliasAndNotExstingApiAlias, () => {
|
||||
expect(false).to.be.true;
|
||||
});
|
||||
localConsumer.hostConnected();
|
||||
|
||||
// Delayed check to make sure the callback is not called.
|
||||
Promise.resolve().then(() => {
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Implementation with discriminator method', () => {
|
||||
type A = { prop: string };
|
||||
|
||||
function discriminator(instance: unknown): instance is A {
|
||||
return typeof (instance as any).prop === 'string';
|
||||
}
|
||||
|
||||
function badDiscriminator(instance: unknown): instance is A {
|
||||
return typeof (instance as any).notExistingProp === 'string';
|
||||
}
|
||||
|
||||
it('discriminator determines the instance type', async () => {
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
document.body,
|
||||
new UmbContextToken(testContextAlias, undefined, discriminator),
|
||||
(instance: A) => {
|
||||
console.log(instance);
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
|
||||
// This bit of code is not really a test but it serves as a TypeScript type test, making sure the given type is matches the one given from the Discriminator method.
|
||||
type TestType = Exclude<typeof localConsumer.instance, undefined> extends A ? true : never;
|
||||
const test: TestType = true;
|
||||
expect(test).to.be.true;
|
||||
|
||||
localConsumer.destroy();
|
||||
});
|
||||
|
||||
it('approving discriminator still fires callback', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
new UmbContextToken(testContextAlias, undefined, discriminator),
|
||||
(_instance) => {
|
||||
expect(_instance.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
}
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
/*
|
||||
Unprovided feature is out commented currently. I'm not sure there is a use case. So lets leave the code around until we know for sure.
|
||||
it('acts to Context API disconnected', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
it('disapproving discriminator does not fire callback', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
let callbackNum = 0;
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
new UmbContextToken(testContextAlias, undefined, badDiscriminator),
|
||||
(_instance) => {
|
||||
expect(_instance.prop).to.eq('this must not happen!');
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextConsumerClass | undefined) => {
|
||||
callbackNum++;
|
||||
if (callbackNum === 1) {
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
// unregister.
|
||||
provider.hostDisconnected();
|
||||
} else if (callbackNum === 2) {
|
||||
expect(_instance?.prop).to.be.undefined;
|
||||
done();
|
||||
}
|
||||
}
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
describe('UmbContextConsumer with discriminator test', () => {
|
||||
type A = { prop: string };
|
||||
|
||||
function discriminator(instance: unknown): instance is A {
|
||||
return typeof (instance as any).prop === 'string';
|
||||
}
|
||||
|
||||
function badDiscriminator(instance: unknown): instance is A {
|
||||
return typeof (instance as any).notExistingProp === 'string';
|
||||
}
|
||||
|
||||
it('discriminator determines the instance type', async () => {
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
document.body,
|
||||
new UmbContextToken(testContextAlias, discriminator),
|
||||
(instance: A) => {
|
||||
console.log(instance);
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
|
||||
// This bit of code is not really a test but it serves as a TypeScript type test, making sure the given type is matches the one given from the Discriminator method.
|
||||
type TestType = Exclude<typeof localConsumer.instance, undefined> extends A ? true : never;
|
||||
const test: TestType = true;
|
||||
expect(test).to.be.true;
|
||||
|
||||
localConsumer.destroy();
|
||||
});
|
||||
|
||||
it('approving discriminator still fires callback', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
new UmbContextToken(testContextAlias, discriminator),
|
||||
(_instance) => {
|
||||
expect(_instance.prop).to.eq('value from provider');
|
||||
Promise.resolve().then(() => {
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('disapproving discriminator does not fire callback', (done) => {
|
||||
const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass());
|
||||
provider.hostConnected();
|
||||
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
new UmbContextToken(testContextAlias, badDiscriminator),
|
||||
(_instance) => {
|
||||
expect(_instance.prop).to.eq('this must not happen!');
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
provider.hostDisconnected();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,29 +22,32 @@ export class UmbContextConsumer<BaseType = unknown, ResultType extends BaseType
|
||||
}
|
||||
|
||||
#contextAlias: string;
|
||||
#apiAlias: string;
|
||||
|
||||
#discriminator?: UmbContextDiscriminator<BaseType, ResultType>;
|
||||
|
||||
/**
|
||||
* Creates an instance of UmbContextConsumer.
|
||||
* @param {EventTarget} hostElement
|
||||
* @param {string} contextAlias
|
||||
* @param {string} contextIdentifier
|
||||
* @param {UmbContextCallback} callback
|
||||
* @memberof UmbContextConsumer
|
||||
*/
|
||||
constructor(
|
||||
protected hostElement: EventTarget,
|
||||
contextAlias: string | UmbContextToken<BaseType, ResultType>,
|
||||
contextIdentifier: string | UmbContextToken<BaseType, ResultType>,
|
||||
callback?: UmbContextCallback<ResultType>,
|
||||
) {
|
||||
this.#contextAlias = contextAlias.toString();
|
||||
const idSplit = contextIdentifier.toString().split('#');
|
||||
this.#contextAlias = idSplit[0];
|
||||
this.#apiAlias = idSplit[1] ?? 'default';
|
||||
this.#callback = callback;
|
||||
this.#discriminator = (contextAlias as UmbContextToken<BaseType, ResultType>).getDiscriminator?.();
|
||||
this.#discriminator = (contextIdentifier as UmbContextToken<BaseType, ResultType>).getDiscriminator?.();
|
||||
}
|
||||
|
||||
protected _onResponse = (instance: BaseType): boolean => {
|
||||
if (this.#instance === instance) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if (this.#discriminator) {
|
||||
// Notice if discriminator returns false, we do not want to setInstance.
|
||||
@@ -68,6 +71,11 @@ export class UmbContextConsumer<BaseType = unknown, ResultType extends BaseType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @memberof UmbContextConsumer
|
||||
* @description Get the context as a promise.
|
||||
*/
|
||||
public asPromise() {
|
||||
return (
|
||||
this.#promise ??
|
||||
@@ -78,10 +86,12 @@ export class UmbContextConsumer<BaseType = unknown, ResultType extends BaseType
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @memberof UmbContextConsumer
|
||||
* @description Request the context from the host element.
|
||||
*/
|
||||
public request() {
|
||||
const event = new UmbContextRequestEventImplementation(this.#contextAlias, this._onResponse);
|
||||
const event = new UmbContextRequestEventImplementation(this.#contextAlias, this.#apiAlias, this._onResponse);
|
||||
this.hostElement.dispatchEvent(event);
|
||||
}
|
||||
|
||||
@@ -126,7 +136,6 @@ export class UmbContextConsumer<BaseType = unknown, ResultType extends BaseType
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Test destroy scenarios:
|
||||
public destroy() {
|
||||
this.hostDisconnected();
|
||||
this.#callback = undefined;
|
||||
|
||||
@@ -9,13 +9,18 @@ describe('UmbContextRequestEvent', () => {
|
||||
|
||||
const event: UmbContextRequestEvent = new UmbContextRequestEventImplementation(
|
||||
'my-test-context-alias',
|
||||
contextRequestCallback
|
||||
'my-test-api-alias',
|
||||
contextRequestCallback,
|
||||
);
|
||||
|
||||
it('has context', () => {
|
||||
it('has context alias', () => {
|
||||
expect(event.contextAlias).to.eq('my-test-context-alias');
|
||||
});
|
||||
|
||||
it('has api alias', () => {
|
||||
expect(event.apiAlias).to.eq('my-test-api-alias');
|
||||
});
|
||||
|
||||
it('has a callback', () => {
|
||||
expect(event.callback).to.eq(contextRequestCallback);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { UmbContextToken } from '../token/context-token.js';
|
||||
|
||||
export const UMB_CONTENT_REQUEST_EVENT_TYPE = 'umb:context-request';
|
||||
export const UMB_DEBUG_CONTEXT_EVENT_TYPE = 'umb:debug-contexts';
|
||||
|
||||
@@ -10,7 +8,8 @@ export type UmbContextCallback<T> = (instance: T) => void;
|
||||
* @interface UmbContextRequestEvent
|
||||
*/
|
||||
export interface UmbContextRequestEvent<ResultType = unknown> extends Event {
|
||||
readonly contextAlias: string | UmbContextToken<unknown, ResultType>;
|
||||
readonly contextAlias: string;
|
||||
readonly apiAlias: string;
|
||||
readonly callback: (context: ResultType) => boolean;
|
||||
}
|
||||
|
||||
@@ -25,7 +24,8 @@ export class UmbContextRequestEventImplementation<ResultType = unknown>
|
||||
implements UmbContextRequestEvent<ResultType>
|
||||
{
|
||||
public constructor(
|
||||
public readonly contextAlias: string | UmbContextToken<any, ResultType>,
|
||||
public readonly contextAlias: string,
|
||||
public readonly apiAlias: string,
|
||||
public readonly callback: (context: ResultType) => boolean,
|
||||
) {
|
||||
super(UMB_CONTENT_REQUEST_EVENT_TYPE, { bubbles: true, composed: true, cancelable: true });
|
||||
|
||||
@@ -42,11 +42,12 @@ describe('UmbContextProvider', () => {
|
||||
it('handles context request events', (done) => {
|
||||
const event = new UmbContextRequestEventImplementation(
|
||||
'my-test-context',
|
||||
'default',
|
||||
(_instance: UmbTestContextProviderClass) => {
|
||||
expect(_instance.prop).to.eq('value from provider');
|
||||
done();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
document.body.dispatchEvent(event);
|
||||
@@ -63,7 +64,7 @@ describe('UmbContextProvider', () => {
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
}
|
||||
},
|
||||
);
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ export class UmbContextProvider<BaseType = unknown, ResultType extends BaseType
|
||||
protected hostElement: EventTarget;
|
||||
|
||||
protected _contextAlias: string;
|
||||
protected _apiAlias: string;
|
||||
#instance: unknown;
|
||||
|
||||
/**
|
||||
@@ -31,17 +32,20 @@ export class UmbContextProvider<BaseType = unknown, ResultType extends BaseType
|
||||
/**
|
||||
* Creates an instance of UmbContextProvider.
|
||||
* @param {EventTarget} host
|
||||
* @param {string} contextAlias
|
||||
* @param {string | UmbContextToken} contextIdentifier
|
||||
* @param {*} instance
|
||||
* @memberof UmbContextProvider
|
||||
*/
|
||||
constructor(
|
||||
hostElement: EventTarget,
|
||||
contextAlias: string | UmbContextToken<BaseType, ResultType>,
|
||||
contextIdentifier: string | UmbContextToken<BaseType, ResultType>,
|
||||
instance: ResultType,
|
||||
) {
|
||||
this.hostElement = hostElement;
|
||||
this._contextAlias = contextAlias.toString();
|
||||
|
||||
const idSplit = contextIdentifier.toString().split('#');
|
||||
this._contextAlias = idSplit[0];
|
||||
this._apiAlias = idSplit[1] ?? 'default';
|
||||
this.#instance = instance;
|
||||
}
|
||||
|
||||
@@ -56,7 +60,8 @@ export class UmbContextProvider<BaseType = unknown, ResultType extends BaseType
|
||||
// Since the alias matches, we will stop it from bubbling further up. But we still allow it to ask the other Contexts of the element. Hence not calling `event.stopImmediatePropagation();`
|
||||
event.stopPropagation();
|
||||
|
||||
if (event.callback(this.#instance)) {
|
||||
// First and importantly, check that the apiAlias matches and then call the callback. If that returns true then we can stop the event completely.
|
||||
if (this._apiAlias === event.apiAlias && event.callback(this.#instance)) {
|
||||
// Make sure the event not hits any more Contexts as we have found a match.
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
@@ -4,57 +4,164 @@ import { UmbContextProvider } from '../provide/context-provider.js';
|
||||
import { UmbContextToken } from './context-token.js';
|
||||
|
||||
const testContextAlias = 'my-test-context';
|
||||
const testApiAlias = 'my-test-api';
|
||||
|
||||
class UmbTestContextTokenClass {
|
||||
prop = 'value from provider';
|
||||
}
|
||||
|
||||
describe('UmbContextToken', () => {
|
||||
const contextToken = new UmbContextToken<UmbTestContextTokenClass>(testContextAlias);
|
||||
const typedProvider = new UmbContextProvider(document.body, contextToken, new UmbTestContextTokenClass());
|
||||
typedProvider.hostConnected();
|
||||
describe('Simple context token', () => {
|
||||
const contextToken = new UmbContextToken<UmbTestContextTokenClass>(testContextAlias);
|
||||
const typedProvider = new UmbContextProvider(document.body, contextToken, new UmbTestContextTokenClass());
|
||||
typedProvider.hostConnected();
|
||||
|
||||
after(() => {
|
||||
typedProvider.hostDisconnected();
|
||||
after(() => {
|
||||
typedProvider.hostDisconnected();
|
||||
});
|
||||
|
||||
it('toString returns the alias', () => {
|
||||
expect(contextToken.toString()).to.eq(testContextAlias + '#' + 'default');
|
||||
});
|
||||
|
||||
it('can be used to consume a context API', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
contextToken,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('gives the same result when using the string alias', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
});
|
||||
|
||||
it('toString returns the alias', () => {
|
||||
expect(contextToken.toString()).to.eq(testContextAlias);
|
||||
describe('Context Token with alternative api alias', () => {
|
||||
const contextToken = new UmbContextToken<UmbTestContextTokenClass>(testContextAlias, testApiAlias);
|
||||
const typedProvider = new UmbContextProvider(document.body, contextToken, new UmbTestContextTokenClass());
|
||||
typedProvider.hostConnected();
|
||||
|
||||
after(() => {
|
||||
typedProvider.hostDisconnected();
|
||||
});
|
||||
|
||||
it('toString returns the alias', () => {
|
||||
expect(contextToken.toString()).to.eq(testContextAlias + '#' + testApiAlias);
|
||||
});
|
||||
|
||||
it('can be used to consume a context API', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
contextToken,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('gives the same result when using the string alias', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
});
|
||||
|
||||
it('can be used to consume a context API', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
contextToken,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
}
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('gives the same result when using the string alias', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
describe('Context Token with discriminator method', () => {
|
||||
const contextToken = new UmbContextToken<UmbTestContextTokenClass>(
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
}
|
||||
undefined,
|
||||
(instance): instance is UmbTestContextTokenClass => instance.prop === 'value from provider',
|
||||
);
|
||||
const typedProvider = new UmbContextProvider(document.body, contextToken, new UmbTestContextTokenClass());
|
||||
typedProvider.hostConnected();
|
||||
|
||||
localConsumer.hostConnected();
|
||||
after(() => {
|
||||
typedProvider.hostDisconnected();
|
||||
});
|
||||
|
||||
it('toString returns the alias', () => {
|
||||
expect(contextToken.toString()).to.eq(testContextAlias + '#' + 'default');
|
||||
});
|
||||
|
||||
it('can be used to consume a context API', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
contextToken,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('gives the same result when using the string alias', (done) => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const localConsumer = new UmbContextConsumer(
|
||||
element,
|
||||
testContextAlias,
|
||||
(_instance: UmbTestContextTokenClass | undefined) => {
|
||||
expect(_instance).to.be.instanceOf(UmbTestContextTokenClass);
|
||||
expect(_instance?.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.destroy(); // We do not want to react to when the provider is disconnected.
|
||||
},
|
||||
);
|
||||
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
export type UmbContextDiscriminator<BaseType, DiscriminatorResult extends BaseType> = (
|
||||
instance: BaseType,
|
||||
) => instance is DiscriminatorResult;
|
||||
|
||||
export type UmbContextDiscriminator<BaseType, DiscriminatorResult extends BaseType> = (instance: BaseType) => instance is DiscriminatorResult;
|
||||
|
||||
export class UmbContextToken<
|
||||
BaseType = unknown,
|
||||
ResultType extends BaseType = BaseType> {
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbContextToken
|
||||
* @template BaseType - A generic type of the API before decimated.
|
||||
* @template ResultType - A concrete type of the API after decimation, use this when you apply a discriminator method. Note this is optional and defaults to the BaseType.
|
||||
*/
|
||||
export class UmbContextToken<BaseType = unknown, ResultType extends BaseType = BaseType> {
|
||||
#discriminator: UmbContextDiscriminator<BaseType, ResultType> | undefined;
|
||||
/**
|
||||
* Get the type of the token
|
||||
@@ -18,12 +22,23 @@ ResultType extends BaseType = BaseType> {
|
||||
readonly TYPE: ResultType = undefined as never;
|
||||
|
||||
/**
|
||||
* @param alias Unique identifier for the token
|
||||
* @param contextAlias Unique identifier for the context
|
||||
* @param apiAlias Unique identifier for the api
|
||||
* @param discriminator A discriminator that will be used to discriminate the API — testing if the API lives up to a certain requirement. If the API does not meet the requirement then the consumer will not receive this API.
|
||||
*/
|
||||
constructor(protected alias: string, discriminator?: UmbContextDiscriminator<BaseType, ResultType>) {
|
||||
constructor(
|
||||
protected contextAlias: string,
|
||||
protected apiAlias: string = 'default',
|
||||
discriminator?: UmbContextDiscriminator<BaseType, ResultType>,
|
||||
) {
|
||||
this.#discriminator = discriminator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the discriminator method for the token
|
||||
*
|
||||
* @returns the discriminator method
|
||||
*/
|
||||
getDiscriminator(): UmbContextDiscriminator<BaseType, ResultType> | undefined {
|
||||
return this.#discriminator;
|
||||
}
|
||||
@@ -35,8 +50,6 @@ ResultType extends BaseType = BaseType> {
|
||||
* @returns the unique alias of the token
|
||||
*/
|
||||
toString(): string {
|
||||
return this.alias;
|
||||
return this.contextAlias + '#' + this.apiAlias;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ export class UmbCollectionViewBundleElement extends UmbLitElement {
|
||||
@state()
|
||||
_currentView?: ManifestCollectionView;
|
||||
|
||||
@state()
|
||||
private _isOpen = false;
|
||||
|
||||
@state()
|
||||
private _collectionRootPathname = '';
|
||||
|
||||
@@ -33,56 +30,65 @@ export class UmbCollectionViewBundleElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
#observeCurrentView() {
|
||||
this.observe(this.#collectionContext!.currentView, (view) => {
|
||||
this._currentView = view;
|
||||
}, 'umbCurrentCollectionViewObserver');
|
||||
this.observe(
|
||||
this.#collectionContext!.currentView,
|
||||
(view) => {
|
||||
//TODO: This is not called when the view is changed
|
||||
this._currentView = view;
|
||||
},
|
||||
'umbCurrentCollectionViewObserver',
|
||||
);
|
||||
}
|
||||
|
||||
#observeViews() {
|
||||
this.observe(this.#collectionContext!.views, (views) => {
|
||||
this._views = views;
|
||||
}, 'umbCollectionViewsObserver');
|
||||
this.observe(
|
||||
this.#collectionContext!.views,
|
||||
(views) => {
|
||||
this._views = views;
|
||||
},
|
||||
'umbCollectionViewsObserver',
|
||||
);
|
||||
}
|
||||
|
||||
#toggleDropdown() {
|
||||
this._isOpen = !this._isOpen;
|
||||
}
|
||||
|
||||
#closeDropdown() {
|
||||
this._isOpen = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this.#renderLayoutButton()}`;
|
||||
}
|
||||
|
||||
#renderLayoutButton() {
|
||||
if (!this._currentView) return nothing;
|
||||
|
||||
return html` <umb-dropdown .open="${this._isOpen}" @close=${this.#closeDropdown}>
|
||||
<uui-button slot="trigger" label="status" @click=${this.#toggleDropdown}
|
||||
>${this.#renderItemDisplay(this._currentView)}</uui-button
|
||||
>
|
||||
<div slot="dropdown" class="filter-dropdown">${this._views.map((view) => this.#renderItem(view))}</div>
|
||||
</umb-dropdown>`;
|
||||
return html`
|
||||
<uui-button compact popovertarget="collection-view-bundle-popover" label="status">
|
||||
${this.#renderItemDisplay(this._currentView)}
|
||||
</uui-button>
|
||||
<uui-popover-container id="collection-view-bundle-popover" popover placement="bottom">
|
||||
<umb-popover-layout>
|
||||
<div class="filter-dropdown">${this._views.map((view) => this.#renderItem(view))}</div>
|
||||
</umb-popover-layout>
|
||||
</uui-popover-container>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItem(view: ManifestCollectionView) {
|
||||
return html`<a href="${this._collectionRootPathname}/${view.meta.pathName}">${this.#renderItemDisplay(view)}</a>`;
|
||||
return html`
|
||||
<uui-button compact href="${this._collectionRootPathname}/${view.meta.pathName}">
|
||||
${this.#renderItemDisplay(view)} <span class="label">${view.meta.label}</span>
|
||||
</uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItemDisplay(view: ManifestCollectionView) {
|
||||
return html`<span class="item"><uui-icon name=${view.meta.icon}></uui-icon> ${view.meta.label}</span>`;
|
||||
return html`<uui-icon name=${view.meta.icon}></uui-icon>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
.item {
|
||||
:host {
|
||||
--uui-button-content-align: left;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
.label {
|
||||
margin-left: var(--uui-size-space-1);
|
||||
}
|
||||
.filter-dropdown {
|
||||
display: flex;
|
||||
gap: var(--uui-size-space-3);
|
||||
flex-direction: column;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -33,3 +33,4 @@ export * from './ref-property-editor-ui/index.js';
|
||||
export * from './table/index.js';
|
||||
export * from './tooltip-menu/index.js';
|
||||
export * from './variant-selector/index.js';
|
||||
export * from './popover-layout/index.js';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import './popover-layout.element.js';
|
||||
|
||||
export * from './popover-layout.element.js';
|
||||
@@ -0,0 +1,33 @@
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
// TODO: maybe move this to UI Library.
|
||||
// TODO: add overwrites for customization.
|
||||
@customElement('umb-popover-layout')
|
||||
export class UmbPopoverLayoutElement extends UmbLitElement {
|
||||
render() {
|
||||
return html`<slot></slot>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
background-color: var(--uui-color-surface);
|
||||
display: block;
|
||||
border: 1px solid var(--uui-color-border);
|
||||
border-radius: var(--uui-border-radius);
|
||||
box-shadow: var(--uui-shadow-depth-3);
|
||||
padding: var(--uui-size-space-3);
|
||||
overflow: clip;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-popover-layout': UmbPopoverLayoutElement;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import type { UmbDataTypeVariantContext } from "./data-type-variant-context.js";
|
||||
import { UmbVariantContext } from "@umbraco-cms/backoffice/workspace";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
import type { UmbDataTypeVariantContext } from './data-type-variant-context.js';
|
||||
import { UmbVariantContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export const isDataTypeVariantContext = (context: UmbVariantContext): context is UmbDataTypeVariantContext => ('properties' in context && context.getType() === 'data-type');
|
||||
export const isDataTypeVariantContext = (context: UmbVariantContext): context is UmbDataTypeVariantContext =>
|
||||
'properties' in context && context.getType() === 'data-type';
|
||||
|
||||
export const UMB_DATA_TYPE_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbDataTypeVariantContext>(
|
||||
"UmbVariantContext", isDataTypeVariantContext);
|
||||
'UmbVariantContext',
|
||||
undefined,
|
||||
isDataTypeVariantContext,
|
||||
);
|
||||
|
||||
@@ -28,17 +28,17 @@ export class UmbDataTypeWorkspaceContext
|
||||
{
|
||||
// TODO: revisit. temp solution because the create and response models are different.
|
||||
#data = new UmbObjectState<DataTypeResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
readonly data = this.#data.asObservable();
|
||||
#getDataPromise?: Promise<any>;
|
||||
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
id = this.#data.asObservablePart((data) => data?.id);
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name);
|
||||
readonly id = this.#data.asObservablePart((data) => data?.id);
|
||||
|
||||
propertyEditorUiAlias = this.#data.asObservablePart((data) => data?.propertyEditorUiAlias);
|
||||
propertyEditorSchemaAlias = this.#data.asObservablePart((data) => data?.propertyEditorAlias);
|
||||
readonly propertyEditorUiAlias = this.#data.asObservablePart((data) => data?.propertyEditorUiAlias);
|
||||
readonly propertyEditorSchemaAlias = this.#data.asObservablePart((data) => data?.propertyEditorAlias);
|
||||
|
||||
#properties = new UmbObjectState<Array<PropertyEditorConfigProperty> | undefined>(undefined);
|
||||
properties: Observable<Array<PropertyEditorConfigProperty> | undefined> = this.#properties.asObservable();
|
||||
readonly properties: Observable<Array<PropertyEditorConfigProperty> | undefined> = this.#properties.asObservable();
|
||||
|
||||
private _propertyEditorSchemaConfigDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
private _propertyEditorUISettingsDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
@@ -53,13 +53,13 @@ export class UmbDataTypeWorkspaceContext
|
||||
private _propertyEditorUISettingsSchemaAlias?: string;
|
||||
|
||||
#defaults = new UmbArrayState<PropertyEditorConfigDefaultData>([], (entry) => entry.alias);
|
||||
defaults = this.#defaults.asObservable();
|
||||
readonly defaults = this.#defaults.asObservable();
|
||||
|
||||
#propertyEditorUiIcon = new UmbStringState<string | null>(null);
|
||||
propertyEditorUiIcon = this.#propertyEditorUiIcon.asObservable();
|
||||
readonly propertyEditorUiIcon = this.#propertyEditorUiIcon.asObservable();
|
||||
|
||||
#propertyEditorUiName = new UmbStringState<string | null>(null);
|
||||
propertyEditorUiName = this.#propertyEditorUiName.asObservable();
|
||||
readonly propertyEditorUiName = this.#propertyEditorUiName.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.DataType', new UmbDataTypeDetailRepository(host));
|
||||
@@ -265,5 +265,6 @@ export const UMB_DATA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbDataTypeWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbDataTypeWorkspaceContext => context.getEntityType?.() === 'data-type',
|
||||
);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { type UmbVariantContext } from "./variant-context.interface.js";
|
||||
import { UmbNameableVariantContext } from "./nameable-variant-context.interface.js";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
import { type UmbVariantContext } from './variant-context.interface.js';
|
||||
import { UmbNameableVariantContext } from './nameable-variant-context.interface.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export const isNameablePropertySetContext = (context: UmbVariantContext): context is UmbNameableVariantContext => 'setName' in context;
|
||||
export const isNameablePropertySetContext = (context: UmbVariantContext): context is UmbNameableVariantContext =>
|
||||
'setName' in context;
|
||||
|
||||
export const UMB_NAMEABLE_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbNameableVariantContext>(
|
||||
"UmbVariantContext",
|
||||
isNameablePropertySetContext);
|
||||
'UmbVariantContext',
|
||||
undefined,
|
||||
isNameablePropertySetContext,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type UmbVariantContext } from "./variant-context.interface.js";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
import { type UmbVariantContext } from './variant-context.interface.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export const UMB_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext>("UmbVariantContext");
|
||||
export const UMB_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext>('UmbVariantContext');
|
||||
|
||||
@@ -6,4 +6,8 @@ import type { UmbEntityBase } from '@umbraco-cms/backoffice/models';
|
||||
export const UMB_VARIANT_WORKSPACE_CONTEXT_TOKEN = new UmbContextToken<
|
||||
UmbWorkspaceContextInterface,
|
||||
UmbVariantableWorkspaceContextInterface<UmbEntityBase>
|
||||
>('UmbWorkspaceContext', (context): context is UmbVariantableWorkspaceContextInterface => 'variants' in context);
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbVariantableWorkspaceContextInterface => 'variants' in context,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export interface UmbWorkspaceContextInterface {
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface UmbWorkspaceContextInterface extends UmbApi {
|
||||
readonly workspaceAlias: string;
|
||||
// TODO: should we consider another name than entity type. File system files are not entities but still have this type.
|
||||
getEntityType(): string;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { UmbDictionaryRepository } from '../repository/dictionary.repository.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -10,10 +13,10 @@ export class UmbDictionaryWorkspaceContext
|
||||
implements UmbSaveableWorkspaceContextInterface<DictionaryItemResponseModel | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<DictionaryItemResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
readonly data = this.#data.asObservable();
|
||||
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
dictionary = this.#data.asObservablePart((data) => data);
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name);
|
||||
readonly dictionary = this.#data.asObservablePart((data) => data);
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.Dictionary', new UmbDictionaryRepository(host));
|
||||
@@ -97,5 +100,6 @@ export const UMB_DICTIONARY_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbDictionaryWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbDictionaryWorkspaceContext => context.getEntityType?.() === 'dictionary-item',
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbDocumentTypeWorkspaceContext } from './document-type-workspace.context.js';
|
||||
import { UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT } from './document-type-workspace.context.js';
|
||||
import { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
UMB_ICON_PICKER_MODAL,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { generateAlias } from '@umbraco-cms/backoffice/utils';
|
||||
@customElement('umb-document-type-workspace-editor')
|
||||
export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement {
|
||||
@@ -27,15 +26,15 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement {
|
||||
private _iconColorAlias?: string;
|
||||
// TODO: Color should be using an alias, and look up in some dictionary/key/value) of project-colors.
|
||||
|
||||
#workspaceContext?: UmbDocumentTypeWorkspaceContext;
|
||||
#workspaceContext?: typeof UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT.TYPE;
|
||||
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_WORKSPACE_CONTEXT, (instance) => {
|
||||
this.#workspaceContext = instance as UmbDocumentTypeWorkspaceContext;
|
||||
this.consumeContext(UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT, (instance) => {
|
||||
this.#workspaceContext = instance;
|
||||
this.#observeDocumentType();
|
||||
});
|
||||
|
||||
|
||||
@@ -176,5 +176,6 @@ export const UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbDocumentTypeWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbDocumentTypeWorkspaceContext => context.getEntityType?.() === 'document-type',
|
||||
);
|
||||
|
||||
@@ -8,5 +8,6 @@ export const IsDocumentVariantContext = (context: UmbVariantContext): context is
|
||||
|
||||
export const UMB_DOCUMENT_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbDocumentVariantContext>(
|
||||
'UmbVariantContext',
|
||||
undefined,
|
||||
IsDocumentVariantContext,
|
||||
);
|
||||
|
||||
@@ -235,6 +235,6 @@ export const UMB_DOCUMENT_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbDocumentWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
// TODO: Refactor: make a better generic way to identify workspaces, maybe workspaceType or workspaceAlias?.
|
||||
undefined,
|
||||
(context): context is UmbDocumentWorkspaceContext => context.getEntityType?.() === UMB_DOCUMENT_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { UmbDocumentWorkspaceContext } from './document-workspace.context.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@@ -11,26 +11,18 @@ import { ManifestWorkspace, umbExtensionsRegistry } from '@umbraco-cms/backoffic
|
||||
|
||||
@customElement('umb-document-workspace')
|
||||
export class UmbDocumentWorkspaceElement extends UmbLitElement {
|
||||
|
||||
|
||||
#workspaceContext?: UmbDocumentWorkspaceContext;
|
||||
|
||||
|
||||
@state()
|
||||
_routes: UmbRoute[] = [];
|
||||
|
||||
public set manifest(manifest: ManifestWorkspace) {
|
||||
|
||||
console.log("got manifest", manifest.alias)
|
||||
// TODO: Make context declaration.
|
||||
|
||||
createExtensionApi(manifest, [this]).then( (context) => {
|
||||
if(context) {
|
||||
createExtensionApi(manifest, [this]).then((context) => {
|
||||
if (context) {
|
||||
this.#gotWorkspaceContext(context);
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#gotWorkspaceContext(context: UmbApi) {
|
||||
this.#workspaceContext = context as UmbDocumentWorkspaceContext;
|
||||
@@ -44,11 +36,11 @@ export class UmbDocumentWorkspaceElement extends UmbLitElement {
|
||||
const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId;
|
||||
const documentTypeKey = info.match.params.documentTypeKey;
|
||||
this.#workspaceContext!.create(documentTypeKey, parentId);
|
||||
|
||||
|
||||
new UmbWorkspaceIsNewRedirectController(
|
||||
this,
|
||||
this.#workspaceContext!,
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!,
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -121,5 +121,6 @@ export const UMB_MEDIA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbMediaTypeWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbMediaTypeWorkspaceContext => context.getEntityType?.() === UMB_MEDIA_TYPE_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -11,7 +11,8 @@ const workspace: ManifestWorkspace = {
|
||||
type: 'workspace',
|
||||
alias: 'Umb.Workspace.Media',
|
||||
name: 'Media Workspace',
|
||||
js: () => import('./media-workspace.element.js'),
|
||||
element: () => import('./media-workspace.element.js'),
|
||||
api: () => import('./media-workspace.context.js'),
|
||||
meta: {
|
||||
entityType: 'media',
|
||||
},
|
||||
|
||||
@@ -7,11 +7,12 @@ import {
|
||||
import { appendToFrozenArray, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
type EntityType = UmbMediaDetailModel;
|
||||
export class UmbMediaWorkspaceContext
|
||||
extends UmbEditableWorkspaceContextBase<UmbMediaRepository, EntityType>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>, UmbApi
|
||||
{
|
||||
#data = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -85,8 +86,13 @@ export class UmbMediaWorkspaceContext
|
||||
this.#data.destroy();
|
||||
}
|
||||
}
|
||||
export const api = UmbMediaWorkspaceContext;
|
||||
|
||||
export const UMB_MEDIA_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbMediaWorkspaceContext
|
||||
>('UmbWorkspaceContext', (context): context is UmbMediaWorkspaceContext => context.getEntityType?.() === 'media');
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbMediaWorkspaceContext => context.getEntityType?.() === 'media',
|
||||
);
|
||||
|
||||
@@ -1,28 +1,59 @@
|
||||
import { UmbMediaWorkspaceContext } from './media-workspace.context.js';
|
||||
import { UmbMediaWorkspaceEditorElement } from './media-workspace-editor.element.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { type UmbMediaWorkspaceContext } from './media-workspace.context.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { type UmbApi, createExtensionApi, UmbExtensionsApiInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry, type ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace';
|
||||
|
||||
@customElement('umb-media-workspace')
|
||||
export class UmbMediaWorkspaceElement extends UmbLitElement {
|
||||
public readonly workspaceAlias = 'Umb.Workspace.Media';
|
||||
|
||||
#workspaceContext = new UmbMediaWorkspaceContext(this);
|
||||
#element = new UmbMediaWorkspaceEditorElement();
|
||||
#workspaceContext?: UmbMediaWorkspaceContext;
|
||||
|
||||
@state()
|
||||
_routes: UmbRoute[] = [
|
||||
{
|
||||
path: 'edit/:id',
|
||||
component: () => this.#element,
|
||||
setup: (_component, info) => {
|
||||
const id = info.match.params.id;
|
||||
this.#workspaceContext.load(id);
|
||||
_routes: UmbRoute[] = [];
|
||||
|
||||
public set manifest(manifest: ManifestWorkspace) {
|
||||
createExtensionApi(manifest, [this]).then((context) => {
|
||||
if (context) {
|
||||
this.#gotWorkspaceContext(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#gotWorkspaceContext(context: UmbApi) {
|
||||
this.#workspaceContext = context as UmbMediaWorkspaceContext;
|
||||
|
||||
this._routes = [
|
||||
{
|
||||
path: 'create/:parentId', // /:mediaTypeKey
|
||||
component: import('./media-workspace-editor.element.js'),
|
||||
setup: async (_component, info) => {
|
||||
// TODO: Remember the perspective of permissions here, we need to check if the user has access to create a document of this type under this parent?
|
||||
const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId;
|
||||
//const mediaTypeKey = info.match.params.mediaTypeKey;
|
||||
this.#workspaceContext!.create(parentId /** , mediaTypeKey */);
|
||||
|
||||
new UmbWorkspaceIsNewRedirectController(
|
||||
this,
|
||||
this.#workspaceContext!,
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!,
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
path: 'edit/:id',
|
||||
component: import('./media-workspace-editor.element.js'),
|
||||
setup: (_component, info) => {
|
||||
const id = info.match.params.id;
|
||||
this.#workspaceContext!.load(id);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [this, this.#workspaceContext]);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-router-slot .routes=${this._routes}></umb-router-slot>`;
|
||||
|
||||
@@ -3,10 +3,10 @@ import type { UmbMemberGroupDetailModel } from '../types.js';
|
||||
import { UMB_MEMBER_GROUP_ENTITY_TYPE } from '../entity.js';
|
||||
import { UMB_MEMBER_GROUP_WORKSPACE_ALIAS } from './manifests.js';
|
||||
import {
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbMemberGroupWorkspaceContext
|
||||
@@ -47,5 +47,6 @@ export const UMB_MEMBER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbMemberGroupWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbMemberGroupWorkspaceContext => context.getEntityType?.() === UMB_MEMBER_GROUP_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { UmbMemberTypeRepository } from '../repository/member-type.repository.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import {
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
// TODO => use correct tpye
|
||||
@@ -75,7 +78,11 @@ export class UmbMemberTypeWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEMBER_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMemberTypeWorkspaceContext>(
|
||||
export const UMB_MEMBER_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbMemberTypeWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMemberTypeWorkspaceContext => context.getEntityType?.() === 'member-type'
|
||||
undefined,
|
||||
(context): context is UmbMemberTypeWorkspaceContext => context.getEntityType?.() === 'member-type',
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { UmbMemberDetailModel } from '../types.js';
|
||||
import { UMB_MEMBER_ENTITY_TYPE } from '../entity.js';
|
||||
import { UMB_MEMBER_WORKSPACE_ALIAS } from './manifests.js';
|
||||
import {
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -47,5 +47,6 @@ export const UMB_MEMBER_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbMemberWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbMemberWorkspaceContext => context.getEntityType?.() === UMB_MEMBER_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { UmbLanguageRepository } from '../../repository/language.repository.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import { ApiError, LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import {
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { ApiError, type LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -10,11 +13,11 @@ export class UmbLanguageWorkspaceContext
|
||||
implements UmbSaveableWorkspaceContextInterface
|
||||
{
|
||||
#data = new UmbObjectState<LanguageResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
readonly data = this.#data.asObservable();
|
||||
|
||||
// TODO: this is a temp solution to bubble validation errors to the UI
|
||||
#validationErrors = new UmbObjectState<any | undefined>(undefined);
|
||||
validationErrors = this.#validationErrors.asObservable();
|
||||
readonly validationErrors = this.#validationErrors.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.Language', new UmbLanguageRepository(host));
|
||||
@@ -102,8 +105,11 @@ export class UmbLanguageWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const UMB_LANGUAGE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbLanguageWorkspaceContext>(
|
||||
export const UMB_LANGUAGE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbLanguageWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbLanguageWorkspaceContext => context.getEntityType?.() === 'language'
|
||||
undefined,
|
||||
(context): context is UmbLanguageWorkspaceContext => context.getEntityType?.() === 'language',
|
||||
);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { UmbRelationTypeRepository } from '../repository/relation-type.repository.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import {
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import type { RelationTypeBaseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbRelationTypeWorkspaceContext
|
||||
@@ -10,9 +13,9 @@ export class UmbRelationTypeWorkspaceContext
|
||||
implements UmbSaveableWorkspaceContextInterface<RelationTypeResponseModel | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<RelationTypeResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
id = this.#data.asObservablePart((data) => data?.id);
|
||||
readonly data = this.#data.asObservable();
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name);
|
||||
readonly id = this.#data.asObservablePart((data) => data?.id);
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.RelationType', new UmbRelationTypeRepository(host));
|
||||
@@ -77,9 +80,11 @@ export class UmbRelationTypeWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbRelationTypeWorkspaceContext>(
|
||||
export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbRelationTypeWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbRelationTypeWorkspaceContext => context.getEntityType?.() === 'relation-type'
|
||||
undefined,
|
||||
(context): context is UmbRelationTypeWorkspaceContext => context.getEntityType?.() === 'relation-type',
|
||||
);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { UmbPartialViewRepository } from '../repository/partial-view.repository.js';
|
||||
import { UmbPartialViewDetailModel } from '../types.js';
|
||||
import type { UmbPartialViewDetailModel } from '../types.js';
|
||||
import { UMB_PARTIAL_VIEW_ENTITY_TYPE } from '../entity.js';
|
||||
import { UmbBooleanState, UmbDeepState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { UpdatePartialViewRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import type { UpdatePartialViewRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbPartialViewWorkspaceContext
|
||||
@@ -47,13 +47,13 @@ export class UmbPartialViewWorkspaceContext
|
||||
}
|
||||
|
||||
#data = new UmbDeepState<UmbPartialViewDetailModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
content = this.#data.asObservablePart((data) => data?.content);
|
||||
path = this.#data.asObservablePart((data) => data?.path);
|
||||
readonly data = this.#data.asObservable();
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name);
|
||||
readonly content = this.#data.asObservablePart((data) => data?.content);
|
||||
readonly path = this.#data.asObservablePart((data) => data?.path);
|
||||
|
||||
#isCodeEditorReady = new UmbBooleanState(false);
|
||||
isCodeEditorReady = this.#isCodeEditorReady.asObservable();
|
||||
readonly isCodeEditorReady = this.#isCodeEditorReady.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.PartialView', new UmbPartialViewRepository(host));
|
||||
@@ -107,5 +107,6 @@ export const UMB_PARTIAL_VIEW_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbPartialViewWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbPartialViewWorkspaceContext => context.getEntityType?.() === UMB_PARTIAL_VIEW_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -7,6 +7,11 @@ export class UmbCreateScriptAction<T extends { copy(): Promise<void> }> extends
|
||||
}
|
||||
|
||||
async execute() {
|
||||
if (this.unique !== null) {
|
||||
// Note: %2F is a slash (/)
|
||||
this.unique = this.unique.replace(/\//g, '%2F');
|
||||
}
|
||||
|
||||
history.pushState(null, '', `section/settings/workspace/script/create/${this.unique ?? 'null'}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@ export class UmbScriptWorkspaceEditElement extends UmbLitElement {
|
||||
@state()
|
||||
private _path?: string | null = '';
|
||||
|
||||
@state()
|
||||
private _dirName?: string | null = '';
|
||||
|
||||
@state()
|
||||
private _ready?: boolean = false;
|
||||
|
||||
@@ -60,8 +57,7 @@ export class UmbScriptWorkspaceEditElement extends UmbLitElement {
|
||||
});
|
||||
|
||||
this.observe(this.#scriptsWorkspaceContext.path, (path) => {
|
||||
this._path = path;
|
||||
this._dirName = this._path?.substring(0, this._path?.lastIndexOf('\\'))?.replace(/\\/g, '/');
|
||||
this._path = path?.replace(/\\/g, '/');
|
||||
});
|
||||
|
||||
this.observe(this.#scriptsWorkspaceContext.isNew, (isNew) => {
|
||||
@@ -106,7 +102,7 @@ export class UmbScriptWorkspaceEditElement extends UmbLitElement {
|
||||
.value=${this._name}
|
||||
@input=${this.#onNameInput}
|
||||
label="template name"></uui-input>
|
||||
<small>Scripts/${this._dirName}${this._name}.js</small>
|
||||
<small>Scripts/${this._path}</small>
|
||||
</div>
|
||||
<uui-box>
|
||||
<!-- the div below in the header is to make the box display nicely with code editor -->
|
||||
|
||||
@@ -64,8 +64,12 @@ export class UmbScriptWorkspaceContext extends UmbEditableWorkspaceContextBase<
|
||||
this.setIsNew(true);
|
||||
}
|
||||
|
||||
getEntityId(): string | undefined {
|
||||
return this.getData()?.path;
|
||||
getEntityId() {
|
||||
const path = this.getData()?.path?.replace(/\//g, '%2F');
|
||||
const name = this.getData()?.name;
|
||||
|
||||
// Note: %2F is a slash (/)
|
||||
return path && name ? `${path}%2F${name}` : name || '';
|
||||
}
|
||||
|
||||
public async save() {
|
||||
@@ -81,7 +85,10 @@ export class UmbScriptWorkspaceContext extends UmbEditableWorkspaceContextBase<
|
||||
parentPath: script.path + '/',
|
||||
};
|
||||
|
||||
this.repository.create(createRequestBody);
|
||||
const { error } = await this.repository.create(createRequestBody);
|
||||
if (!error) {
|
||||
this.setIsNew(false);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!script.path) return Promise.reject('There is no path');
|
||||
@@ -90,7 +97,10 @@ export class UmbScriptWorkspaceContext extends UmbEditableWorkspaceContextBase<
|
||||
existingPath: script.path,
|
||||
content: script.content,
|
||||
};
|
||||
this.repository.save(script.path, updateRequestBody);
|
||||
const { error } = await this.repository.save(script.path, updateRequestBody);
|
||||
if (!error) {
|
||||
//TODO Update the URL to the new name
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,20 +7,20 @@ import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/wor
|
||||
|
||||
@customElement('umb-script-workspace')
|
||||
export class UmbScriptWorkspaceElement extends UmbLitElement {
|
||||
#scriptWorkspaceContext = new UmbScriptWorkspaceContext(this);
|
||||
#workspaceContext = new UmbScriptWorkspaceContext(this);
|
||||
@state()
|
||||
_routes: UmbRoute[] = [
|
||||
{
|
||||
path: 'create/:parentKey',
|
||||
component: import('./script-workspace-edit.element.js'),
|
||||
setup: async (component: PageComponent, info: IRoutingInfo) => {
|
||||
setup: async (_component: PageComponent, info: IRoutingInfo) => {
|
||||
const parentKey = info.match.params.parentKey;
|
||||
const decodePath = decodeURIComponent(parentKey);
|
||||
this.#scriptWorkspaceContext.create(decodePath === 'null' ? '' : decodePath);
|
||||
this.#workspaceContext.create(decodePath === 'null' ? '' : decodePath);
|
||||
|
||||
new UmbWorkspaceIsNewRedirectController(
|
||||
this,
|
||||
this.#scriptWorkspaceContext,
|
||||
this.#workspaceContext,
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!,
|
||||
);
|
||||
},
|
||||
@@ -31,7 +31,7 @@ export class UmbScriptWorkspaceElement extends UmbLitElement {
|
||||
setup: (component: PageComponent, info: IRoutingInfo) => {
|
||||
const key = info.match.params.key;
|
||||
const decodePath = decodeURIComponent(key).replace('-js', '.js');
|
||||
this.#scriptWorkspaceContext.load(decodePath);
|
||||
this.#workspaceContext.load(decodePath);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbStylesheetWorkspaceContext } from './stylesheet-workspace.context.js';
|
||||
import { UUIInputElement, UUIInputEvent, UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, html, customElement, state, PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { Subject, debounceTime } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
@@ -23,9 +23,6 @@ export class UmbStylesheetWorkspaceEditorElement extends UmbLitElement {
|
||||
@state()
|
||||
private _path?: string;
|
||||
|
||||
@state()
|
||||
private _dirName?: string;
|
||||
|
||||
private inputQuery$ = new Subject<string>();
|
||||
|
||||
constructor() {
|
||||
@@ -46,14 +43,7 @@ export class UmbStylesheetWorkspaceEditorElement extends UmbLitElement {
|
||||
if (!this.#workspaceContext) return;
|
||||
this.observe(
|
||||
this.#workspaceContext.path,
|
||||
(path) => {
|
||||
this._path = path;
|
||||
if (this._path?.includes('.css')) {
|
||||
this._dirName = this._path?.substring(0, this._path?.lastIndexOf('\\') + 1)?.replace(/\\/g, '/');
|
||||
} else {
|
||||
this._dirName = path + '/';
|
||||
}
|
||||
},
|
||||
(path) => (this._path = path?.replace(/\\/g, '/')),
|
||||
'_observeStylesheetPath',
|
||||
);
|
||||
this.observe(this.#workspaceContext.name, (name) => (this._name = name), '_observeStylesheetName');
|
||||
@@ -76,7 +66,7 @@ export class UmbStylesheetWorkspaceEditorElement extends UmbLitElement {
|
||||
.value=${this._name}
|
||||
@input="${this.#onNameChange}">
|
||||
</uui-input>
|
||||
<small>/css/${this._dirName}${this._name}.css</small>
|
||||
<small>/css/${this._path}</small>
|
||||
</div>
|
||||
|
||||
<div slot="footer-info">
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { UmbStylesheetRepository } from '../repository/stylesheet.repository.js';
|
||||
import { StylesheetDetails } from '../index.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { StylesheetDetails } from '../index.js';
|
||||
import {
|
||||
type UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState, UmbBooleanState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { RichTextRuleModel, UpdateStylesheetRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import type { RichTextRuleModel, UpdateStylesheetRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export type RichTextRuleModelSortable = RichTextRuleModel & { sortOrder?: number };
|
||||
@@ -15,14 +18,14 @@ export class UmbStylesheetWorkspaceContext
|
||||
{
|
||||
#data = new UmbObjectState<StylesheetDetails | undefined>(undefined);
|
||||
#rules = new UmbArrayState<RichTextRuleModelSortable>([], (rule) => rule.name);
|
||||
data = this.#data.asObservable();
|
||||
rules = this.#rules.asObservable();
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
content = this.#data.asObservablePart((data) => data?.content);
|
||||
path = this.#data.asObservablePart((data) => data?.path);
|
||||
readonly data = this.#data.asObservable();
|
||||
readonly rules = this.#rules.asObservable();
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name);
|
||||
readonly content = this.#data.asObservablePart((data) => data?.content);
|
||||
readonly path = this.#data.asObservablePart((data) => data?.path);
|
||||
|
||||
#isCodeEditorReady = new UmbBooleanState(false);
|
||||
isCodeEditorReady = this.#isCodeEditorReady.asObservable();
|
||||
readonly isCodeEditorReady = this.#isCodeEditorReady.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.StyleSheet', new UmbStylesheetRepository(host));
|
||||
@@ -148,7 +151,6 @@ export class UmbStylesheetWorkspaceContext
|
||||
if (!error) {
|
||||
this.setIsNew(false);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
if (!stylesheet.path) return Promise.reject('There is no path');
|
||||
@@ -157,8 +159,11 @@ export class UmbStylesheetWorkspaceContext
|
||||
existingPath: stylesheet.path,
|
||||
content: stylesheet.content,
|
||||
};
|
||||
this.repository.save(stylesheet.path, updateRequestBody);
|
||||
|
||||
const { error } = await this.repository.save(stylesheet.path, updateRequestBody);
|
||||
if (!error) {
|
||||
//TODO Update the URL to the new name
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -184,5 +189,6 @@ export const UMB_STYLESHEET_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbStylesheetWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbStylesheetWorkspaceContext => context.getEntityType?.() === 'stylesheet',
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { serverFilePathFromUrlFriendlyPath } from '../../utils.js';
|
||||
import { UmbStylesheetWorkspaceContext } from './stylesheet-workspace.context.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace';
|
||||
import { decodeFilePath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
@customElement('umb-stylesheet-workspace')
|
||||
export class UmbStylesheetWorkspaceElement extends UmbLitElement {
|
||||
@@ -17,7 +17,7 @@ export class UmbStylesheetWorkspaceElement extends UmbLitElement {
|
||||
component: import('./stylesheet-workspace-editor.element.js'),
|
||||
setup: async (_component, info) => {
|
||||
const path = info.match.params.path === 'null' ? null : info.match.params.path;
|
||||
const serverPath = path === null ? null : serverFilePathFromUrlFriendlyPath(path);
|
||||
const serverPath = path === null ? null : decodeFilePath(path);
|
||||
await this.#workspaceContext.create(serverPath);
|
||||
await this.#workspaceContext.setRules([]);
|
||||
|
||||
@@ -34,7 +34,7 @@ export class UmbStylesheetWorkspaceElement extends UmbLitElement {
|
||||
setup: (_component, info) => {
|
||||
this.removeControllerByAlias('_observeIsNew');
|
||||
const path = info.match.params.path;
|
||||
const serverPath = serverFilePathFromUrlFriendlyPath(path);
|
||||
const serverPath = decodeFilePath(path);
|
||||
this.#workspaceContext.load(serverPath);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -176,4 +176,8 @@ ${currentContent}`;
|
||||
export const UMB_TEMPLATE_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbTemplateWorkspaceContext
|
||||
>('UmbWorkspaceContext', (context): context is UmbTemplateWorkspaceContext => context.getEntityType?.() === 'template');
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbTemplateWorkspaceContext => context.getEntityType?.() === 'template',
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbTemplateWorkspaceContext } from './template-workspace.context.js';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { IRoutingInfo, PageComponent, UmbRoute, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
|
||||
import type { IRoutingInfo, PageComponent, UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
import '../../components/insert-menu/templating-insert-menu.element.js';
|
||||
@@ -9,10 +9,6 @@ import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/wor
|
||||
|
||||
@customElement('umb-template-workspace')
|
||||
export class UmbTemplateWorkspaceElement extends UmbLitElement {
|
||||
public load(entityId: string) {
|
||||
this.#templateWorkspaceContext.load(entityId);
|
||||
}
|
||||
|
||||
#templateWorkspaceContext = new UmbTemplateWorkspaceContext(this);
|
||||
|
||||
#element = document.createElement('umb-template-workspace-editor');
|
||||
@@ -29,7 +25,7 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
|
||||
new UmbWorkspaceIsNewRedirectController(
|
||||
this,
|
||||
this.#templateWorkspaceContext,
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!
|
||||
this.shadowRoot!.querySelector('umb-router-slot')!,
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
// TODO: we can try and make pretty urls if we want to
|
||||
export const urlFriendlyPathFromServerFilePath = (path: string) => encodeURIComponent(path).replace('.', '-');
|
||||
|
||||
// TODO: we can try and make pretty urls if we want to
|
||||
export const serverFilePathFromUrlFriendlyPath = (unique: string) => decodeURIComponent(unique.replace('-', '.'));
|
||||
|
||||
//Below are a copy of
|
||||
export const getInsertDictionarySnippet = (nodeName: string) => {
|
||||
return `@Umbraco.GetDictionaryValue("${nodeName}")`;
|
||||
@@ -31,10 +25,10 @@ export const getRenderBodySnippet = () => '@RenderBody()';
|
||||
export const getRenderSectionSnippet = (sectionName: string, isMandatory: boolean) =>
|
||||
`@RenderSection("${sectionName}", ${isMandatory})`;
|
||||
|
||||
export const getAddSectionSnippet = (sectionName: string) => `@section ${sectionName}
|
||||
export const getAddSectionSnippet = (sectionName: string) => `@section ${sectionName}
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
}`;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { UmbUserGroupRepository } from '../repository/user-group.repository.js';
|
||||
import { UmbUserRepository } from '../../user/repository/user.repository.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import {
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbEditableWorkspaceContextBase,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import type { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -153,5 +156,6 @@ export const UMB_USER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbUserGroupWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbUserGroupWorkspaceContext => context.getEntityType?.() === 'user-group',
|
||||
);
|
||||
|
||||
@@ -69,15 +69,6 @@ export class UmbUserCollectionHeaderElement extends UmbLitElement {
|
||||
}
|
||||
}
|
||||
|
||||
#onDropdownClick(event: PointerEvent) {
|
||||
const composedPath = event.composedPath();
|
||||
|
||||
const dropdown = composedPath.find((el) => el instanceof UmbDropdownElement) as UmbDropdownElement;
|
||||
if (dropdown) {
|
||||
dropdown.open = !dropdown.open;
|
||||
}
|
||||
}
|
||||
|
||||
private _updateSearch(event: InputEvent) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const filter = target.value || '';
|
||||
@@ -118,8 +109,9 @@ export class UmbUserCollectionHeaderElement extends UmbLitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this.#renderCollectionActions()} ${this.#renderSearch()} ${this.#renderFilters()}
|
||||
${this.#renderCollectionViews()}
|
||||
<div style="display: flex; gap: var(--uui-size-space-4)">${this.#renderCollectionActions()}</div>
|
||||
${this.#renderSearch()}
|
||||
<div>${this.#renderFilters()} ${this.#renderCollectionViews()}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -162,9 +154,27 @@ export class UmbUserCollectionHeaderElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
#getUserGroupFilterLabel() {
|
||||
return this._userGroupFilterSelection.length === 0
|
||||
const length = this._userGroupFilterSelection.length;
|
||||
const max = 2;
|
||||
//TODO: Temp solution to limit the amount of states shown
|
||||
return length === 0
|
||||
? this.localize.term('general_all')
|
||||
: this._userGroupFilterSelection.map((group) => group.name).join(', ');
|
||||
: this._userGroupFilterSelection
|
||||
.slice(0, max)
|
||||
.map((group) => group.name)
|
||||
.join(', ') + (length > max ? ' + ' + (length - max) : '');
|
||||
}
|
||||
|
||||
#getStatusFilterLabel() {
|
||||
const length = this._stateFilterSelection.length;
|
||||
const max = 2;
|
||||
//TODO: Temp solution to limit the amount of states shown
|
||||
return length === 0
|
||||
? this.localize.term('general_all')
|
||||
: this._stateFilterSelection
|
||||
.slice(0, max)
|
||||
.map((state) => this.localize.term('user_state' + state))
|
||||
.join(', ') + (length > max ? ' + ' + (length - max) : '');
|
||||
}
|
||||
|
||||
#renderFilters() {
|
||||
@@ -173,45 +183,47 @@ export class UmbUserCollectionHeaderElement extends UmbLitElement {
|
||||
|
||||
#renderStatusFilter() {
|
||||
return html`
|
||||
<umb-dropdown class="filter">
|
||||
<uui-button @click=${this.#onDropdownClick} slot="trigger" label="status">
|
||||
<umb-localize key="general_status"></umb-localize>:
|
||||
<umb-localize key=${'user_state' + this._stateFilterSelection}></umb-localize>
|
||||
</uui-button>
|
||||
|
||||
<div slot="dropdown" class="filter-dropdown">
|
||||
${this._stateFilterOptions.map(
|
||||
(option) =>
|
||||
html`<uui-checkbox
|
||||
label=${this.localize.term('user_state' + option)}
|
||||
@change=${this.#onStateFilterChange}
|
||||
name="state"
|
||||
value=${option}></uui-checkbox>`,
|
||||
)}
|
||||
</div>
|
||||
</umb-dropdown>
|
||||
<uui-button popovertarget="popover-user-status-filter" label="status">
|
||||
<umb-localize key="general_status"></umb-localize>: <b>${this.#getStatusFilterLabel()}</b>
|
||||
</uui-button>
|
||||
<uui-popover-container id="popover-user-status-filter" popover placement="bottom">
|
||||
<umb-popover-layout>
|
||||
<div class="filter-dropdown">
|
||||
${this._stateFilterOptions.map(
|
||||
(option) =>
|
||||
html`<uui-checkbox
|
||||
label=${this.localize.term('user_state' + option)}
|
||||
@change=${this.#onStateFilterChange}
|
||||
name="state"
|
||||
value=${option}></uui-checkbox>`,
|
||||
)}
|
||||
</div>
|
||||
</umb-popover-layout>
|
||||
</uui-popover-container>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderUserGroupFilter() {
|
||||
return html`
|
||||
<umb-dropdown class="filter">
|
||||
<uui-button @click=${this.#onDropdownClick} slot="trigger" label=${this.localize.term('general_groups')}>
|
||||
<umb-localize key="general_groups"></umb-localize>: ${this.#getUserGroupFilterLabel()}
|
||||
</uui-button>
|
||||
<div slot="dropdown" class="filter-dropdown">
|
||||
${repeat(
|
||||
this._userGroups,
|
||||
(group) => group.id,
|
||||
(group) => html`
|
||||
<uui-checkbox
|
||||
label=${ifDefined(group.name)}
|
||||
value=${ifDefined(group.id)}
|
||||
@change=${this.#onUserGroupFilterChange}></uui-checkbox>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</umb-dropdown>
|
||||
<uui-button popovertarget="popover-user-group-filter" label=${this.localize.term('general_groups')}>
|
||||
<umb-localize key="general_groups"></umb-localize>: <b>${this.#getUserGroupFilterLabel()}</b>
|
||||
</uui-button>
|
||||
<uui-popover-container id="popover-user-group-filter" popover placement="bottom">
|
||||
<umb-popover-layout>
|
||||
<div class="filter-dropdown">
|
||||
${repeat(
|
||||
this._userGroups,
|
||||
(group) => group.id,
|
||||
(group) => html`
|
||||
<uui-checkbox
|
||||
label=${ifDefined(group.name)}
|
||||
value=${ifDefined(group.id)}
|
||||
@change=${this.#onUserGroupFilterChange}></uui-checkbox>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</umb-popover-layout>
|
||||
</uui-popover-container>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -243,7 +255,6 @@ export class UmbUserCollectionHeaderElement extends UmbLitElement {
|
||||
display: flex;
|
||||
gap: var(--uui-size-space-3);
|
||||
flex-direction: column;
|
||||
width: fit-content;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -115,5 +115,6 @@ export const UMB_USER_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbUserWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
(context): context is UmbUserWorkspaceContext => context.getEntityType?.() === UMB_USER_ENTITY_TYPE,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
type FilterKeys<T, U> = {
|
||||
type _FilterKeys<T, U> = {
|
||||
[K in keyof T]: K extends keyof U ? never : K;
|
||||
};
|
||||
|
||||
export type Diff<U, T> = Pick<T, FilterKeys<T, U>[keyof T]>;
|
||||
export type Diff<U, T> = Pick<T, _FilterKeys<T, U>[keyof T]>;
|
||||
|
||||
@@ -4,11 +4,13 @@ export * from './ensure-path-ends-with-slash.function.js';
|
||||
export * from './generate-umbraco-alias.function.js';
|
||||
export * from './increment-string.function.js';
|
||||
export * from './media-helper.service.js';
|
||||
export * from './pagination-manager/pagination.manager.js';
|
||||
export * from './path-decode.function.js';
|
||||
export * from './path-encode.function.js';
|
||||
export * from './path-folder-name.function.js';
|
||||
export * from './selection-manager.js';
|
||||
export * from './udi-service.js';
|
||||
export * from './umbraco-path.function.js';
|
||||
export * from './pagination-manager/pagination.manager.js';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const decodeFilePath = (unique: string) => decodeURIComponent(unique.replace('-', '.'));
|
||||
@@ -0,0 +1 @@
|
||||
export const encodeFilePath = (path: string) => encodeURIComponent(path).replace('.', '-');
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO: Rename to something more obvious, naming wise this can mean anything. I suggest: umbracoManagementApiPath()
|
||||
export function umbracoPath(path: string) {
|
||||
return `/umbraco/management/api/v1${path}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user