Re[6]: Насколько ии повлиял на сферу?
От: Артём Австралия жж
Дата: 28.09.25 00:52
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Ну на форме там 300, сильно меньше вряд ли получится? 500 это в коммите всего. Вот, полный текст для формы.

bnk>Как по мне так норм, я бы сам примерно так же написал. Он же по образу и подобию того что есть в проекте работает
bnk>Если система строится более-менее логично, проект использует какие-нибудь более-менее попсовые либы, ему несложно разобраться.

bnk>
  здесь
bnk>
bnk>import React from 'react';
bnk>import {
bnk>  Dialog,
bnk>  DialogType,
bnk>  IDialogContentProps,
bnk>  DialogFooter,
bnk>  PrimaryButton,
bnk>  DefaultButton,
bnk>  Stack,
bnk>  Text,
bnk>  Icon,
bnk>  Spinner,
bnk>  SpinnerSize,
bnk>  MessageBar,
bnk>  MessageBarType,
bnk>  Separator
bnk>} from '@fluentui/react';
bnk>import { AuthService } from 'services/AuthService';
bnk>import { TokenKind } from 'shared/TokenKind';
bnk>import { TextService } from 'services/TextService';
bnk>import strings from 'VistoWebPartStrings';
bnk>import { useTheme } from '@fluentui/react';
bnk>import { trackClient } from 'services/trackClient';

bnk>export interface IConsentDialogProps {
bnk>  onDismiss: () => void;
bnk>}

bnk>interface IConsentItem {
bnk>  key: string;
bnk>  name: string;
bnk>  description: string;
bnk>  tokenKind: TokenKind;
bnk>  domain?: string;
bnk>  isGranted: boolean;
bnk>  isChecking: boolean;
bnk>  error?: string;
bnk>}

bnk>export const ConsentDialog: React.FC<IConsentDialogProps> = (props) => {
bnk>  const theme = useTheme();
bnk>  const [consentItems, setConsentItems] = React.useState<IConsentItem[]>([
bnk>    {
bnk>      key: 'default',
bnk>      name: TextService.format(strings.ConsentDialog_Default),
bnk>      description: TextService.format(strings.ConsentDialog_DefaultDescription),
bnk>      tokenKind: TokenKind.dashboard,
bnk>      domain: 'graph.microsoft.com',
bnk>      isGranted: false,
bnk>      isChecking: false
bnk>    },
bnk>    {
bnk>      key: 'sharepoint',
bnk>      name: TextService.format(strings.ConsentDialog_SharePoint),
bnk>      description: TextService.format(strings.ConsentDialog_SharePointDescription),
bnk>      tokenKind: TokenKind.sharepoint,
bnk>      isGranted: false,
bnk>      isChecking: false
bnk>    },
bnk>    {
bnk>      key: 'devops',
bnk>      name: TextService.format(strings.ConsentDialog_DevOps),
bnk>      description: TextService.format(strings.ConsentDialog_DevOpsDescription),
bnk>      tokenKind: TokenKind.devops,
bnk>      domain: 'dev.azure.com',
bnk>      isGranted: false,
bnk>      isChecking: false
bnk>    },
bnk>    {
bnk>      key: 'planner',
bnk>      name: TextService.format(strings.ConsentDialog_Planner),
bnk>      description: TextService.format(strings.ConsentDialog_PlannerDescription),
bnk>      tokenKind: TokenKind.planner,
bnk>      domain: 'graph.microsoft.com',
bnk>      isGranted: false,
bnk>      isChecking: false
bnk>    },
bnk>    {
bnk>      key: 'excel',
bnk>      name: TextService.format(strings.ConsentDialog_Excel),
bnk>      description: TextService.format(strings.ConsentDialog_ExcelDescription),
bnk>      tokenKind: TokenKind.excel,
bnk>      domain: 'graph.microsoft.com',
bnk>      isGranted: false,
bnk>      isChecking: false
bnk>    }
bnk>  ]);

bnk>  const [isInitializing, setIsInitializing] = React.useState(true);

bnk>  const formatErrorMessage = (error: any, item: IConsentItem): string => {
bnk>    const errorMessage = error?.message || error?.toString() || 'Unknown error';
    
bnk>    // Special handling for DevOps AADSTS650052 error
bnk>    if (item.key === 'devops' && errorMessage.includes('AADSTS650052')) {
bnk>      return "DevOps may not be available for your organization or user account. This is a common reason for this error.";
bnk>    }
    
bnk>    return errorMessage;
bnk>  };

bnk>  const checkConsentStatus = async (item: IConsentItem): Promise<boolean> => {
bnk>    try {
bnk>      // Try to get a token - if it succeeds, consent is granted
bnk>      const domain = item.domain || 'graph.microsoft.com';
bnk>      await AuthService.getAuthToken(item.tokenKind, domain);
bnk>      return true;
bnk>    } catch (error) {
bnk>      // If we get a consent error, consent is not granted
bnk>      trackClient.warn(`Consent check failed for ${TokenKind[item.tokenKind]}`, error);
bnk>      return false;
bnk>    }
bnk>  };

bnk>  const updateConsentItem = (key: string, updates: Partial<IConsentItem>) => {
bnk>    setConsentItems(prev => prev.map(item =>
bnk>      item.key === key ? { ...item, ...updates } : item
bnk>    ));
bnk>  };

bnk>  const checkAllConsents = async () => {
bnk>    setIsInitializing(true);

bnk>    const checkPromises = consentItems.map(async (item) => {
bnk>      updateConsentItem(item.key, { isChecking: true, error: undefined });

bnk>      try {
bnk>        const isGranted = await checkConsentStatus(item);
bnk>        updateConsentItem(item.key, {
bnk>          isGranted,
bnk>          isChecking: false,
bnk>          error: undefined
bnk>        });
bnk>      } catch (error) {
bnk>        updateConsentItem(item.key, {
bnk>          isGranted: false,
bnk>          isChecking: false,
bnk>          error: formatErrorMessage(error, item)
bnk>        });
bnk>      }
bnk>    });

bnk>    await Promise.all(checkPromises);
bnk>    setIsInitializing(false);
bnk>  };

bnk>  React.useEffect(() => {
bnk>    checkAllConsents();
bnk>  }, []);

bnk>  const requestConsent = async (item: IConsentItem) => {
bnk>    if (!AuthService.getConsent) {
bnk>      trackClient.error('getConsent provider not available');
bnk>      return;
bnk>    }

bnk>    updateConsentItem(item.key, { isChecking: true, error: undefined });

bnk>    try {
bnk>      const domain = item.domain || 'graph.microsoft.com';
bnk>      await AuthService.getConsent(item.tokenKind, async () => {
bnk>        // Test callback to verify consent was granted
bnk>        await AuthService.getAuthToken(item.tokenKind, domain);
bnk>      }, domain);

bnk>      // If we get here, consent was granted
bnk>      updateConsentItem(item.key, {
bnk>        isGranted: true,
bnk>        isChecking: false,
bnk>        error: undefined
bnk>      });
bnk>    } catch (error) {
bnk>      updateConsentItem(item.key, {
bnk>        isGranted: false,
bnk>        isChecking: false,
bnk>        error: formatErrorMessage(error, item)
bnk>      });
bnk>    }
bnk>  };

bnk>  const getStatusIcon = (item: IConsentItem) => {
bnk>    if (item.isChecking) {
bnk>      return <Spinner size={SpinnerSize.small} />;
bnk>    }

bnk>    if (item.isGranted) {
bnk>      return <Icon iconName="CheckMark" style={{ color: theme.palette.green }} />;
bnk>    }

bnk>    return <Icon iconName="ErrorBadge" style={{ color: theme.palette.red }} />;
bnk>  };

bnk>  const contentProps: IDialogContentProps = {
bnk>    type: DialogType.largeHeader,
bnk>    title: TextService.format(strings.ConsentDialog_Title),
bnk>    subText: TextService.format(strings.ConsentDialog_Description)
bnk>  };

bnk>  const grantedCount = consentItems.filter(item => item.isGranted).length;
bnk>  const totalCount = consentItems.length;

bnk>  return (
bnk>    <Dialog
bnk>      minWidth={400}
bnk>      maxWidth={600}
bnk>      isBlocking={false}
bnk>      dialogContentProps={contentProps}
bnk>      isOpen={true}
bnk>      onDismiss={props.onDismiss}
    >>
bnk>      <Stack tokens={{ childrenGap: 'l1' }} styles={{ root: { paddingBottom: '32px' } }}>
bnk>        {isInitializing && (
bnk>          <MessageBar messageBarType={MessageBarType.info}>
bnk>            <Stack horizontal verticalAlign="center" tokens={{ childrenGap: 's1' }}>
bnk>              <Spinner size={SpinnerSize.small} />
bnk>              <Text>{TextService.format(strings.ConsentDialog_CheckingAll)}</Text>
bnk>            </Stack>
bnk>          </MessageBar>
bnk>        )}

bnk>        {!isInitializing && (
bnk>          <MessageBar
bnk>            messageBarType={grantedCount === totalCount ? MessageBarType.success : MessageBarType.warning}
          >>
bnk>            <Text>
bnk>              {TextService.format(strings.ConsentDialog_Status, {
bnk>                granted: grantedCount.toString(),
bnk>                total: totalCount.toString()
bnk>              })}
bnk>            </Text>
bnk>          </MessageBar>
bnk>        )}

bnk>        <Stack tokens={{ childrenGap: 's1' }}>
bnk>          {consentItems.map((item, index) => (
bnk>            <div key={item.key}>
bnk>              <Stack horizontal verticalAlign="center" tokens={{ childrenGap: 'm' }}>
bnk>                <div style={{ width: 20, flexShrink: 0 }}>
bnk>                  {getStatusIcon(item)}
bnk>                </div>

bnk>                <Stack grow tokens={{ childrenGap: 'xs' }}>
bnk>                  <Stack horizontal verticalAlign="center" tokens={{ childrenGap: 's2' }}>
bnk>                    <Text variant="medium" style={{ fontWeight: 600 }}>
bnk>                      {item.name}
bnk>                    </Text>
bnk>                    {(!item.isGranted && !item.isChecking) && (
bnk>                      <Text variant="small" style={{
bnk>                        color: theme.palette.orange,
bnk>                        backgroundColor: theme.palette.neutralLighter,
bnk>                        padding: '2px 6px',
bnk>                        borderRadius: '2px',
bnk>                        fontSize: '11px',
bnk>                        fontWeight: 600
bnk>                      }}>
bnk>                        {TextService.format(strings.ConsentDialog_NotGranted)}
bnk>                      </Text>
bnk>                    )}
bnk>                  </Stack>

bnk>                  <Text variant="small" style={{ color: theme.palette.neutralPrimary }}>
bnk>                    {item.description}
bnk>                  </Text>

bnk>                  {item.error && (
bnk>                    <Text variant="small" style={{
bnk>                      color: theme.palette.red,
bnk>                      wordBreak: 'break-word',
bnk>                      maxWidth: '100%'
bnk>                    }}>
bnk>                      {TextService.format(strings.ConsentDialog_Error)}: {item.error}
bnk>                    </Text>
bnk>                  )}
bnk>                </Stack>

bnk>                <Stack horizontal verticalAlign="center" style={{ minWidth: 140, justifyContent: 'flex-end' }}>
bnk>                  {item.isGranted ? (
bnk>                    <DefaultButton
bnk>                      disabled={true}
bnk>                      text={TextService.format(strings.ConsentDialog_Granted)}
bnk>                      iconProps={{ iconName: 'CheckMark' }}
bnk>                      styles={{
bnk>                        root: {
bnk>                          backgroundColor: theme.palette.neutralLighter,
bnk>                          borderColor: theme.palette.neutralLight,
bnk>                          color: theme.palette.neutralSecondary
bnk>                        },
bnk>                        icon: { color: theme.palette.green }
bnk>                      }}
bnk>                    />
bnk>                  ) : item.isChecking ? (
bnk>                    <DefaultButton
bnk>                      disabled={true}
bnk>                      text={TextService.format(strings.ConsentDialog_Checking)}
bnk>                      onRenderIcon={() => <Spinner size={SpinnerSize.xSmall} />}
bnk>                      styles={{
bnk>                        root: {
bnk>                          backgroundColor: theme.palette.neutralLighter,
bnk>                          borderColor: theme.palette.neutralLight,
bnk>                          color: theme.palette.neutralSecondary
bnk>                        }
bnk>                      }}
bnk>                    />
bnk>                  ) : (
bnk>                    <PrimaryButton
bnk>                      text={TextService.format(strings.ConsentDialog_GrantConsent)}
bnk>                      onClick={() => requestConsent(item)}
bnk>                    />
bnk>                  )}
bnk>                </Stack>
bnk>              </Stack>
bnk>              {index < consentItems.length - 1 && <Separator styles={{ root: { margin: '4px 0' } }} />}
bnk>            </div>
bnk>          ))}
bnk>        </Stack>
bnk>      </Stack>

bnk>      <DialogFooter styles={{ actions: { display: 'flex', flexGrow: 1 }, actionsRight: { flexGrow: 1, justifyContent: 'space-between' } }}>
bnk>        <DefaultButton
bnk>          text={TextService.format(strings.ConsentDialog_RefreshAll)}
bnk>          onClick={checkAllConsents}
bnk>          disabled={isInitializing}
bnk>          iconProps={{ iconName: 'Refresh' }}
bnk>        />
bnk>        <DefaultButton onClick={props.onDismiss} text={TextService.format(strings.ConsentDialog_Close)} />
bnk>      </DialogFooter>
bnk>    </Dialog>
bnk>  );
bnk>};

bnk>



Охх этот винегрет Реакта, я от него выпал в осадок ещё давно, когда прикручивал кусок на реакте к проекту на ангуларе. Ну в любом случае- твой пример кода накидывается в режиме отключки мозга за 30 минут путём копи-пасты, когда рука набита.

Вот пример — я убил больше недели на задачу, счас есть подвижки, но внёс 2 регресси при использовании на старом коде (который до этих изменении 2 регрессий не имеет) https://rsdn.org/forum/web/8992844.flat
Автор: Артём
Дата: 18.09 00:35
. Идея такая- кастомная directive, которая при использовании одного и того же контрола на разных экранах (как child разного parent) не создавать новый instance, а отцеплять от одного parent и прицеплять к другому. Чтобы сохранялся state того контрола. Учитывая, сколько усилий я потратил в своё время, чтоб заставить клод написать простой тест-покрытие Cypress и потом забил, оставшуюся половину допилил руками, то заставить болванчика написать что-то чуть сложнее типичной копи-пасты формы, думаю, нереально.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.