Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release Candidate v1.16.3 #997

Merged
merged 28 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ca6bf38
fix: E2E tests - trigger tests fixed for Cloud runs (#969)
tkonieczny Dec 4, 2023
bd845dd
fix: downgrade bugs improvements (#970)
topliceanurazvan Dec 5, 2023
e401d7d
feat: free org empty entities (#971)
haneabogdan Dec 6, 2023
af2044d
feat: add entity list promo component with plugin slot (#972)
topliceanurazvan Dec 7, 2023
e18c7ca
feat: confirm disabled for configuration card (#973)
topliceanurazvan Dec 7, 2023
3a7e07e
chore: add color to palette (#974)
haneabogdan Dec 11, 2023
f9639a7
feat: create InstallationInfoItem atom component (#975)
topliceanurazvan Dec 13, 2023
57c31d9
fix: executions bar chart popover alignment (#977)
topliceanurazvan Dec 14, 2023
df55203
refactor: rename EntityListContent to EntityView (#959)
topliceanurazvan Dec 15, 2023
b7ac8a1
feat: Log Output modifications (#976)
rangoo94 Dec 15, 2023
d180c07
refactor: add pending status (#978)
topliceanurazvan Dec 18, 2023
f1d945a
feat: add syncSubscribe() method for plugins (#979)
rangoo94 Dec 18, 2023
eb85a68
refactor: remove isListLoading prop (#980)
topliceanurazvan Dec 18, 2023
1057bf3
fix: avoid using external Babel replacement in the worker function (#…
rangoo94 Dec 20, 2023
eaddbf8
feat: environment dashboard (#983)
haneabogdan Jan 5, 2024
e202f8f
fix: escape arguments containing spaces (#982)
topliceanurazvan Jan 5, 2024
e4af435
feat: on log click (#984)
topliceanurazvan Jan 10, 2024
2296ad9
feat: multi log line selection (#985)
topliceanurazvan Jan 12, 2024
ae29abe
feat: add search + status executions filters (#986)
topliceanurazvan Jan 15, 2024
03b7ae7
chore: add circleci url constant (#987)
devcatalin Jan 15, 2024
4ac5628
feat: add prefix & suffix to HelpCard (#988)
devcatalin Jan 16, 2024
816d43e
feat: enhance executions model (#989)
haneabogdan Jan 16, 2024
25a9d74
fix: download artifacts archive (#991)
topliceanurazvan Jan 17, 2024
3ef3a6b
refactor: executions timestamp filter (#992)
topliceanurazvan Jan 19, 2024
c585f0f
refactor: handle artifacts new status (#993)
topliceanurazvan Jan 19, 2024
b979f0e
fix: logs rendering when switching drawer tabs (#994)
topliceanurazvan Jan 22, 2024
4462450
fix: missing artifacts tab (#995)
haneabogdan Jan 23, 2024
33252a4
feat: slack migration (#996)
haneabogdan Jan 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<a href="https://testkube.io">Website</a> |
<a href="https://kubeshop.github.io/testkube">Documentation</a> |
<a href="https://twitter.com/testkube_io">Twitter</a> |
<a href="https://discord.gg/hfq44wtR6Q">Discord</a> |
<a href="https://join.slack.com/t/testkubeworkspace/shared_invite/zt-2arhz5vmu-U2r3WZ69iPya5Fw0hMhRDg">Slack</a> |
<a href="https://kubeshop.io/category/testkube">Blog</a>
</p>

Expand Down
22 changes: 5 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/e2e-tests/fixtures/triggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
concurrencyPolicy: '',
testSelector: {
name: 'postman-executor-smoke',
...(config.cloudContext ? {} : {namespace: config.namespace}),
namespace: config.namespace,
},
resourceSelector: {
name: 'non-existant-resource',
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/helpers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ export function validateWebhook(webhookData: Partial<WebhookData>, createdWebhoo
}

export function validateTrigger(triggerData: Partial<TriggerData>, createdTriggerData: TriggerData): void {
expect(triggerData).toEqual(createdTriggerData);
expect(createdTriggerData).toEqual(triggerData);
}
6 changes: 6 additions & 0 deletions packages/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ export default createPlugin('some-plugin-name')
// Using .provider() is more convenient though.
const isLoading = tk.sync(() => useSomeStoreData('loading'));
tk.slots.somePluginStub.someOtherSlot.add(<>Loading...</>, {enabled: isLoading});

// When you need to ensure that the slot usage will be updated immediately after .sync() change,
// you may use .syncSubscribe() function instead.
// It's a bit slower, as it will emit the change to all scopes.
const isLoadingAsap = tk.syncSubscribe(() => useSomeStoreData('loading'));
tk.slots.somePluginStub.someOtherSlot.add(<>Loading...</>, {enabled: isLoadingAsap});
});
```

Expand Down
97 changes: 97 additions & 0 deletions packages/plugins/src/internal/PluginScope.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,103 @@ describe('plugins', () => {
);
});

it('should return default value before synchronization (syncSubscribe)', () => {
const scope = create({});
const fn1 = jest.fn(() => Math.random());
const fn2 = jest.fn(() => Math.random());
const fnSync1 = scope.syncSubscribe(fn1);
const fnSync2 = scope.syncSubscribe(fn2, 1.5);
expect(fn1).not.toHaveBeenCalled();
expect(fn2).not.toHaveBeenCalled();
expect(fnSync1()).toBe(undefined);
expect(fnSync2()).toBe(1.5);
});

it('should return cached value after synchronization (syncSubscribe)', () => {
const scope = create({});
const fn1 = jest.fn(() => Math.random());
const fn2 = jest.fn(() => Math.random());
const fnSync1 = scope.syncSubscribe(fn1);
const fnSync2 = scope.syncSubscribe(fn2, 1.5);
scope[PluginScopeCallSync]();
expect(fn1).toHaveBeenCalledTimes(1);
expect(fn2).toHaveBeenCalledTimes(1);
expect(fnSync1()).toBe(fn1.mock.results[0].value);
expect(fnSync2()).toBe(fn2.mock.results[0].value);
});

it('should replace value after multiple synchronizations (syncSubscribe)', () => {
const scope = create({});
const fn = jest.fn(() => Math.random());
const fnSync = scope.syncSubscribe(fn);
scope[PluginScopeCallSync]();
scope[PluginScopeCallSync]();
expect(fn).toHaveBeenCalledTimes(2);
expect(fnSync()).toBe(fn.mock.results[1].value);
});

it('should emit change in root scope on initial run when its different than default (syncSubscribe)', async () => {
const root = create({});
const middle = create({}, root);
const scope = create({}, middle);
const listener = jest.fn();
root[PluginScopeSubscribeChange](listener);
scope.syncSubscribe(() => 10);
scope[PluginScopeCallSync]();
await frame();
expect(listener).toHaveBeenCalledTimes(1);
});

it('should not emit change in root scope on initial run when its same as default (syncSubscribe)', async () => {
const root = create({});
const middle = create({}, root);
const scope = create({}, middle);
const listener = jest.fn();
root[PluginScopeSubscribeChange](listener);
scope.syncSubscribe(() => 10, 10);
scope[PluginScopeCallSync]();
await frame();
expect(listener).toHaveBeenCalledTimes(0);
});

it('should not emit change in root scope when there is no change (syncSubscribe)', async () => {
const root = create({});
const middle = create({}, root);
const scope = create({}, middle);
const listener = jest.fn();
root[PluginScopeSubscribeChange](listener);
const value = 10;
const fn = jest.fn(() => value);
scope.syncSubscribe(fn, value);
scope[PluginScopeCallSync]();
scope[PluginScopeCallSync]();
await frame();
expect(listener).toHaveBeenCalledTimes(0);
});

it('should emit change in root scope when there is a change (syncSubscribe)', async () => {
const root = create({});
const middle = create({}, root);
const scope = create({}, middle);
const listener = jest.fn();
root[PluginScopeSubscribeChange](listener);
let value = 10;
scope.syncSubscribe(() => value, value);
scope[PluginScopeCallSync]();
value = 123;
scope[PluginScopeCallSync]();
await frame();
expect(listener).toHaveBeenCalledTimes(1);
});

it('should not allow synchronization after plugin initialization (syncSubscribe)', () => {
const scope = create({});
scope[PluginScopeDisableNewSync]();
expect(() => scope.syncSubscribe(() => {})).toThrow(
new Error('The syncSubscribe() factory may be executed only during initialization.')
);
});

it('should allow destroying items produced by specific scope or its children', () => {
const root = create({slots: ['slot1']});
const separate = create({inheritedSlots: ['slot1']}, root);
Expand Down
32 changes: 31 additions & 1 deletion packages/plugins/src/internal/PluginScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class PluginScope<T extends PluginScopeState> {

public [PluginScopeCallSync](): void {
Array.from(this[PluginScopeSyncData].keys()).forEach(fn => {
this[PluginScopeSyncData].set(fn, fn());
this[PluginScopeSyncData].set(fn, fn(this[PluginScopeSyncData].get(fn)));
});
}

Expand Down Expand Up @@ -189,6 +189,36 @@ export class PluginScope<T extends PluginScopeState> {
return () => this[PluginScopeSyncData].get(wrappedFn) ?? defaultValue;
}

/**
* Transfer data from React to the plugin context.
*
* The difference from sync() is, that it will emit change in the scope when the value is different.
* It's a bit slower, as it's trigger a change on the root scope afterward.
*
* TODO: Consider using Observables instead, that could be passed to Slot.enabled?
*/
public syncSubscribe<U>(fn: () => U, defaultValue: U): () => U;
public syncSubscribe<U>(fn: () => U, defaultValue?: undefined): () => U | undefined;
public syncSubscribe<U>(fn: () => U, defaultValue?: U): () => U | undefined {
if (this[PluginScopeDisableNewSyncStatus]) {
throw new Error('The syncSubscribe() factory may be executed only during initialization.');
}

const wrappedFn = (prevValue: U | undefined = defaultValue) => {
const nextValue = fn();
let root: PluginScope<any> = this;
while (root[PluginScopeParentScope]) {
root = root[PluginScopeParentScope];
}
if (prevValue !== nextValue) {
root[PluginScopeEmitChange]();
}
return nextValue;
};
this[PluginScopeSyncData].set(wrappedFn, undefined);
return () => this[PluginScopeSyncData].get(wrappedFn) ?? defaultValue;
}

public children<U extends Plugin<any>>(plugin: U): PluginScope<PluginScopeStateFor<GetPluginState<U>>> {
const scope = new PluginScope(this, {
data: [],
Expand Down
3 changes: 2 additions & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@
"@sentry/integrations": "^7.64.0",
"@sentry/react": "^7.64.0",
"@testkube/plugins": "*",
"ansi-to-react": "^6.1.6",
"anser": "^2.1.1",
"antd": "^4.24.12",
"axios": "0.27.2",
"classnames": "2.3.1",
"cron-parser": "^4.8.1",
"date-fns": "^2.28.0",
"escape-carriage": "^1.3.1",
"file-saver": "^2.0.5",
"framer-motion": "^4.1.17",
"lodash.debounce": "^4.0.8",
Expand Down
2 changes: 1 addition & 1 deletion packages/web/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="preload"
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&family=Roboto+Mono&display=swap"
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&family=IBM+Plex+Mono&display=swap"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/AppRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const AppRoot: React.FC = () => {
() => [
...basePlugins,
ClusterStatusPlugin,
ConfigPlugin.configure({discordUrl: externalLinks.discord}),
ConfigPlugin.configure({slackUrl: externalLinks.slack}),
RouterPlugin.configure({baseUrl: env.basename || ''}),
PermissionsPlugin.configure({resolver: new BasePermissionsResolver()}),
RtkResetOnApiChangePlugin,
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/antd-theme/my-antd-theme.less
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@layout-body-background: #111827;
@layout-header-background: #111827;
@font-family: 'Roboto', sans-serif;
@code-family: 'Roboto Mono', sans-serif;
@code-family: 'IBM Plex Mono', monospace;
// button
@btn-height-base: 40px;
@btn-default-bg: rgba(255, 255, 255, 0.05);
Expand Down
204 changes: 110 additions & 94 deletions packages/web/src/assets/images/status-pages-mock-1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import styled from 'styled-components';

export const StyledExecutorIcon = styled.div<{$noWidth: boolean}>`
width: ${({$noWidth}) => ($noWidth ? 'unset' : '28px')};
height: ${({$noWidth}) => ($noWidth ? 'unset' : '28px')};
export const StyledExecutorIcon = styled.div<{$size: 'large' | 'small'}>`
width: ${({$size}) => ($size === 'large' ? '28px' : '16px')};
height: ${({$size}) => ($size === 'large' ? '28px' : '16px')};

svg {
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import {ReactComponent as TracetestIcon} from '@assets/tracetestIcon.svg';
import {StyledExecutorIcon} from './ExecutorIcon.styled';

type ExecutorIconProps = {
size?: 'large' | 'small';
type?: string;
noWidth?: boolean;
};

export const executorIcons: Record<string, JSX.Element> = {
Expand All @@ -39,15 +39,15 @@ export const executorIcons: Record<string, JSX.Element> = {
};

const ExecutorIcon: React.FC<ExecutorIconProps> = props => {
const {type, noWidth = false} = props;
const {size = 'large', type} = props;

const icon = type ? executorIcons[type] : <DefaultIcon />;

if (!icon) {
return <DefaultIcon />;
}
return (
<StyledExecutorIcon $noWidth={noWidth} className="dashboard-test-runner">
<StyledExecutorIcon $size={size} className="dashboard-test-runner">
{icon || <DefaultIcon />}
</StyledExecutorIcon>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/components/atoms/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {IconProps} from './types';
const {
CogIcon,
DocumentationIcon,
DiscordIcon,
SlackIcon,
GitHubIcon,
PassedStatusIcon,
FailedStatusIcon,
Expand All @@ -25,7 +25,7 @@ const {
const iconsMap: Record<IconProps['name'], IconComponentProps['component']> = {
cog: CogIcon,
documentation: DocumentationIcon,
discord: DiscordIcon,
slack: SlackIcon,
github: GitHubIcon,
passed: PassedStatusIcon,
failed: FailedStatusIcon,
Expand Down
15 changes: 11 additions & 4 deletions packages/web/src/components/atoms/Icon/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,17 @@ const GitHubIcon: React.FC = () => {
);
};

const DiscordIcon: React.FC = () => {
const SlackIcon: React.FC = () => {
return (
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.28889 7.6C9.27534 7.75846 9.21596 7.90955 9.11799 8.03482C9.02002 8.1601 8.88769 8.25414 8.73717 8.30548C8.58665 8.35682 8.42444 8.36323 8.27033 8.32393C8.11623 8.28462 7.9769 8.20131 7.86935 8.08415C7.7618 7.967 7.69068 7.82106 7.66467 7.66417C7.63867 7.50727 7.6589 7.3462 7.7229 7.20061C7.78689 7.05501 7.89189 6.9312 8.02507 6.84428C8.15825 6.75736 8.31386 6.71109 8.47289 6.71111C8.58487 6.7158 8.69483 6.74252 8.79647 6.78974C8.89811 6.83697 8.98943 6.90378 9.06523 6.98634C9.14102 7.0689 9.19979 7.1656 9.23816 7.2709C9.27654 7.3762 9.29378 7.48803 9.28889 7.6ZM5.55289 6.71111C5.328 6.72702 5.11751 6.82758 4.96382 6.99253C4.81013 7.15748 4.72467 7.37455 4.72467 7.6C4.72467 7.82545 4.81013 8.04252 4.96382 8.20747C5.11751 8.37241 5.328 8.47298 5.55289 8.48889C5.66487 8.4842 5.77483 8.45748 5.87646 8.41026C5.9781 8.36303 6.06943 8.29622 6.14523 8.21366C6.22102 8.1311 6.27979 8.0344 6.31816 7.9291C6.35654 7.8238 6.37378 7.71197 6.36889 7.6C6.3745 7.48779 6.35773 7.37559 6.31956 7.26992C6.28139 7.16426 6.22258 7.06724 6.14656 6.98452C6.07054 6.90179 5.97882 6.83502 5.87675 6.78808C5.77468 6.74114 5.66429 6.71498 5.552 6.71111H5.55289ZM14 1.648V16C11.9844 14.2191 12.6293 14.8084 10.288 12.632L10.712 14.112H1.64C1.20402 14.1108 0.786355 13.9366 0.478821 13.6275C0.171286 13.3185 -0.00094039 12.9 3.86232e-06 12.464V1.648C-0.00094039 1.21202 0.171286 0.793508 0.478821 0.484473C0.786355 0.175439 1.20402 0.00117731 1.64 0L12.36 0C12.796 0.00117731 13.2137 0.175439 13.5212 0.484473C13.8287 0.793508 14.0009 1.21202 14 1.648ZM11.72 9.232C11.6941 7.61016 11.3002 6.01539 10.568 4.568C9.92374 4.06196 9.13824 3.76845 8.32 3.728L8.208 3.856C8.93644 4.04983 9.61542 4.39614 10.2 4.872C9.2873 4.37995 8.27412 4.10324 7.23801 4.06303C6.2019 4.02281 5.17032 4.22017 4.22223 4.64C3.92623 4.776 3.75023 4.872 3.75023 4.872C4.3664 4.37146 5.08541 4.01301 5.856 3.82222L5.77778 3.728C4.95954 3.76845 4.17405 4.06196 3.52978 4.568C2.79697 6.01524 2.40245 7.61002 2.376 9.232C2.65192 9.61913 3.01875 9.9325 3.44423 10.1445C3.86971 10.3566 4.34079 10.4608 4.816 10.448C4.816 10.448 5.112 10.088 5.352 9.784C4.78959 9.64208 4.29441 9.30819 3.952 8.84C4.06978 8.92222 4.26311 9.02933 4.28 9.04C5.03927 9.45388 5.88109 9.69371 6.74447 9.74214C7.60786 9.79057 8.47121 9.64637 9.272 9.32C9.59551 9.19792 9.90415 9.03957 10.192 8.848C9.83679 9.32625 9.32388 9.66346 8.744 9.8C8.984 10.104 9.272 10.448 9.272 10.448C9.74823 10.46 10.2202 10.3555 10.6468 10.1436C11.0735 9.93168 11.4419 9.61874 11.72 9.232Z" />
<svg fill="#000000" width="16" height="16" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path d="M126.12,315.1A47.06,47.06,0,1,1,79.06,268h47.06Z" />
<path d="M149.84,315.1a47.06,47.06,0,0,1,94.12,0V432.94a47.06,47.06,0,1,1-94.12,0Z" />
<path d="M196.9,126.12A47.06,47.06,0,1,1,244,79.06v47.06Z" />
<path d="M196.9,149.84a47.06,47.06,0,0,1,0,94.12H79.06a47.06,47.06,0,0,1,0-94.12Z" />
<path d="M385.88,196.9A47.06,47.06,0,1,1,432.94,244H385.88Z" />
<path d="M362.16,196.9a47.06,47.06,0,0,1-94.12,0V79.06a47.06,47.06,0,1,1,94.12,0Z" />
<path d="M315.1,385.88A47.06,47.06,0,1,1,268,432.94V385.88Z" />
<path d="M315.1,362.16a47.06,47.06,0,0,1,0-94.12H432.94a47.06,47.06,0,1,1,0,94.12Z" />
</svg>
);
};
Expand Down Expand Up @@ -114,7 +121,7 @@ export default {
CogIcon,
DocumentationIcon,
GitHubIcon,
DiscordIcon,
SlackIcon,
FailedStatusIcon,
PassedStatusIcon,
RunningStatusIcon,
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/atoms/Icon/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export type IconProps = {
name:
| 'cog'
| 'documentation'
| 'discord'
| 'slack'
| 'github'
| 'passed'
| 'failed'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from 'styled-components';

export const Container = styled.div`
display: flex;
flex-direction: column;
gap: 10px;
`;
Loading
Loading